summaryrefslogtreecommitdiffstats
path: root/picosoc
diff options
context:
space:
mode:
authorYann Herklotz <git@yannherklotz.com>2022-11-24 22:27:15 +0000
committerYann Herklotz <git@yannherklotz.com>2022-11-24 22:27:15 +0000
commit59c9a162631b78eff84e2002478413b98c2cffbb (patch)
tree7d604206a2deb29c9f097ff1f3b7de78f44b34a3 /picosoc
downloadbutterstick-59c9a162631b78eff84e2002478413b98c2cffbb.tar.gz
butterstick-59c9a162631b78eff84e2002478413b98c2cffbb.zip
Move all files
Diffstat (limited to 'picosoc')
-rw-r--r--picosoc/.gitignore29
-rw-r--r--picosoc/Makefile123
-rw-r--r--picosoc/README.md114
-rw-r--r--picosoc/firmware.c770
-rw-r--r--picosoc/hx8kdemo.core35
-rw-r--r--picosoc/hx8kdemo.pcf40
-rw-r--r--picosoc/hx8kdemo.v139
-rw-r--r--picosoc/hx8kdemo_tb.v108
-rw-r--r--picosoc/ice40up5k_spram.v91
-rw-r--r--picosoc/icebreaker.core36
-rw-r--r--picosoc/icebreaker.pcf25
-rw-r--r--picosoc/icebreaker.v151
-rw-r--r--picosoc/icebreaker_tb.v122
-rw-r--r--picosoc/overview.svg757
-rw-r--r--picosoc/performance.pngbin0 -> 62502 bytes
-rw-r--r--picosoc/performance.py165
-rw-r--r--picosoc/picosoc.core27
-rw-r--r--picosoc/picosoc.v262
-rw-r--r--picosoc/sections.lds71
-rw-r--r--picosoc/simpleuart.v137
-rw-r--r--picosoc/spiflash.core24
-rw-r--r--picosoc/spiflash.v409
-rw-r--r--picosoc/spiflash_tb.v366
-rw-r--r--picosoc/spimemio.v579
-rw-r--r--picosoc/start.s159
25 files changed, 4739 insertions, 0 deletions
diff --git a/picosoc/.gitignore b/picosoc/.gitignore
new file mode 100644
index 0000000..4ac8239
--- /dev/null
+++ b/picosoc/.gitignore
@@ -0,0 +1,29 @@
+/spiflash_tb.vcd
+/spiflash_tb.vvp
+/hx8kdemo.asc
+/hx8kdemo.bin
+/hx8kdemo.json
+/hx8kdemo.log
+/hx8kdemo.rpt
+/hx8kdemo_syn.v
+/hx8kdemo_syn_tb.vvp
+/hx8kdemo_tb.vvp
+/hx8kdemo_fw.elf
+/hx8kdemo_fw.hex
+/hx8kdemo_fw.bin
+/hx8kdemo_sections.lds
+/icebreaker.asc
+/icebreaker.bin
+/icebreaker.json
+/icebreaker.log
+/icebreaker.rpt
+/icebreaker_syn.v
+/icebreaker_syn_tb.vvp
+/icebreaker_tb.vvp
+/icebreaker_fw.elf
+/icebreaker_fw.hex
+/icebreaker_fw.bin
+/icebreaker_sections.lds
+/testbench.vcd
+/cmos.log
+
diff --git a/picosoc/Makefile b/picosoc/Makefile
new file mode 100644
index 0000000..291a12d
--- /dev/null
+++ b/picosoc/Makefile
@@ -0,0 +1,123 @@
+
+CROSS=riscv32-unknown-elf-
+CFLAGS=
+
+# ---- iCE40 HX8K Breakout Board ----
+
+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
+
+hx8kdemo.json: hx8kdemo.v spimemio.v simpleuart.v picosoc.v ../picorv32.v
+ yosys -ql hx8kdemo.log -p 'synth_ice40 -top hx8kdemo -json hx8kdemo.json' $^
+
+hx8kdemo_tb.vvp: hx8kdemo_tb.v hx8kdemo.v spimemio.v simpleuart.v picosoc.v ../picorv32.v spiflash.v
+ iverilog -s testbench -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v` -DNO_ICE40_DEFAULT_ASSIGNMENTS
+
+hx8kdemo_syn_tb.vvp: hx8kdemo_tb.v hx8kdemo_syn.v spiflash.v
+ iverilog -s testbench -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v` -DNO_ICE40_DEFAULT_ASSIGNMENTS
+
+hx8kdemo_syn.v: hx8kdemo.json
+ yosys -p 'read_json hx8kdemo.json; write_verilog hx8kdemo_syn.v'
+
+hx8kdemo.asc: hx8kdemo.pcf hx8kdemo.json
+ nextpnr-ice40 --hx8k --package ct256 --asc hx8kdemo.asc --json hx8kdemo.json --pcf hx8kdemo.pcf
+
+hx8kdemo.bin: hx8kdemo.asc
+ icetime -d hx8k -c 12 -mtr hx8kdemo.rpt hx8kdemo.asc
+ icepack hx8kdemo.asc hx8kdemo.bin
+
+hx8kprog: hx8kdemo.bin hx8kdemo_fw.bin
+ iceprog hx8kdemo.bin
+ iceprog -o 1M hx8kdemo_fw.bin
+
+hx8kprog_fw: hx8kdemo_fw.bin
+ iceprog -o 1M hx8kdemo_fw.bin
+
+hx8kdemo_sections.lds: sections.lds
+ $(CROSS)cpp -P -DHX8KDEMO -o $@ $^
+
+hx8kdemo_fw.elf: hx8kdemo_sections.lds start.s firmware.c
+ $(CROSS)gcc $(CFLAGS) -DHX8KDEMO -mabi=ilp32 -march=rv32imc -Wl,--build-id=none,-Bstatic,-T,hx8kdemo_sections.lds,--strip-debug -ffreestanding -nostdlib -o hx8kdemo_fw.elf start.s firmware.c
+
+hx8kdemo_fw.hex: hx8kdemo_fw.elf
+ $(CROSS)objcopy -O verilog hx8kdemo_fw.elf hx8kdemo_fw.hex
+
+hx8kdemo_fw.bin: hx8kdemo_fw.elf
+ $(CROSS)objcopy -O binary hx8kdemo_fw.elf hx8kdemo_fw.bin
+
+# ---- iCE40 IceBreaker Board ----
+
+icebsim: icebreaker_tb.vvp icebreaker_fw.hex
+ vvp -N $< +firmware=icebreaker_fw.hex
+
+icebsynsim: icebreaker_syn_tb.vvp icebreaker_fw.hex
+ vvp -N $< +firmware=icebreaker_fw.hex
+
+icebreaker.json: icebreaker.v ice40up5k_spram.v spimemio.v simpleuart.v picosoc.v ../picorv32.v
+ yosys -ql icebreaker.log -p 'synth_ice40 -dsp -top icebreaker -json icebreaker.json' $^
+
+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` -DNO_ICE40_DEFAULT_ASSIGNMENTS
+
+icebreaker_syn_tb.vvp: icebreaker_tb.v icebreaker_syn.v spiflash.v
+ iverilog -s testbench -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v` -DNO_ICE40_DEFAULT_ASSIGNMENTS
+
+icebreaker_syn.v: icebreaker.json
+ yosys -p 'read_json icebreaker.json; write_verilog icebreaker_syn.v'
+
+icebreaker.asc: icebreaker.pcf icebreaker.json
+ nextpnr-ice40 --freq 13 --up5k --package sg48 --asc icebreaker.asc --pcf icebreaker.pcf --json icebreaker.json
+
+icebreaker.bin: icebreaker.asc
+ icetime -d up5k -c 12 -mtr icebreaker.rpt icebreaker.asc
+ icepack icebreaker.asc icebreaker.bin
+
+icebprog: icebreaker.bin icebreaker_fw.bin
+ iceprog icebreaker.bin
+ iceprog -o 1M icebreaker_fw.bin
+
+icebprog_fw: icebreaker_fw.bin
+ iceprog -o 1M icebreaker_fw.bin
+
+icebreaker_sections.lds: sections.lds
+ $(CROSS)cpp -P -DICEBREAKER -o $@ $^
+
+icebreaker_fw.elf: icebreaker_sections.lds start.s firmware.c
+ $(CROSS)gcc $(CFLAGS) -DICEBREAKER -mabi=ilp32 -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
+ $(CROSS)objcopy -O verilog icebreaker_fw.elf icebreaker_fw.hex
+
+icebreaker_fw.bin: icebreaker_fw.elf
+ $(CROSS)objcopy -O binary icebreaker_fw.elf icebreaker_fw.bin
+
+# ---- Testbench for SPI Flash Model ----
+
+spiflash_tb: spiflash_tb.vvp icebreaker_fw.hex
+ vvp -N $< +firmware=icebreaker_fw.hex
+
+spiflash_tb.vvp: spiflash.v spiflash_tb.v
+ iverilog -s testbench -o $@ $^
+
+# ---- ASIC Synthesis Tests ----
+
+cmos.log: spimemio.v simpleuart.v picosoc.v ../picorv32.v
+ yosys -l cmos.log -p 'synth -top picosoc; abc -g cmos2; opt -fast; stat' $^
+
+# ---- Clean ----
+
+clean:
+ rm -f testbench.vvp testbench.vcd spiflash_tb.vvp spiflash_tb.vcd
+ rm -f hx8kdemo_fw.elf hx8kdemo_fw.hex hx8kdemo_fw.bin cmos.log
+ rm -f icebreaker_fw.elf icebreaker_fw.hex icebreaker_fw.bin
+ rm -f hx8kdemo.blif hx8kdemo.log hx8kdemo.asc hx8kdemo.rpt hx8kdemo.bin
+ rm -f hx8kdemo_syn.v hx8kdemo_syn_tb.vvp hx8kdemo_tb.vvp
+ rm -f icebreaker.json icebreaker.log icebreaker.asc icebreaker.rpt icebreaker.bin
+ rm -f icebreaker_syn.v icebreaker_syn_tb.vvp icebreaker_tb.vvp
+
+.PHONY: spiflash_tb clean
+.PHONY: hx8kprog hx8kprog_fw hx8ksim hx8ksynsim
+.PHONY: icebprog icebprog_fw icebsim icebsynsim
diff --git a/picosoc/README.md b/picosoc/README.md
new file mode 100644
index 0000000..1708709
--- /dev/null
+++ b/picosoc/README.md
@@ -0,0 +1,114 @@
+
+PicoSoC - A simple example SoC using PicoRV32
+=============================================
+
+![](overview.svg)
+
+This is a simple PicoRV32 example design that can run code directly from an SPI
+flash chip. It can be used as a turn-key solution for simple control tasks in
+ASIC and FPGA designs.
+
+An example implementation targeting the Lattice iCE40-HX8K Breakout Board is
+included.
+
+The flash is mapped to the memory regions starting at 0x00000000 and
+0x01000000, with the SRAM overlayed for the mapping at 0x00000000. The SRAM
+is just a small scratchpad memory (default 256 words, i.e. 1 kB).
+
+The reset vector is set to 0x00100000, i.e. at 1MB into in the flash memory.
+
+See the included demo firmware and linker script for how to build a firmware
+image for this system.
+
+Run `make hx8ksim` or `make icebsim` to run the test bench (and create `testbench.vcd`).
+
+Run `make hx8kprog` to build the configuration bit-stream and firmware images
+and upload them to a connected iCE40-HX8K Breakout Board.
+
+Run `make icebprog` to build the configuration bit-stream and firmware images
+and upload them to a connected iCEBreaker Board.
+
+| File | Description |
+| ----------------------------------- | --------------------------------------------------------------- |
+| [picosoc.v](picosoc.v) | Top-level PicoSoC Verilog module |
+| [spimemio.v](spimemio.v) | Memory controller that interfaces to external SPI flash |
+| [simpleuart.v](simpleuart.v) | Simple UART core connected directly to SoC TX/RX lines |
+| [start.s](start.s) | Assembler source for firmware.hex/firmware.bin |
+| [firmware.c](firmware.c) | C source for firmware.hex/firmware.bin |
+| [sections.lds](sections.lds) | Linker script 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 |
+| [hx8kdemo\_tb.v](hx8kdemo_tb.v) | Testbench for implementation on iCE40-HX8K Breakout Board |
+| [icebreaker.v](icebreaker.v) | FPGA-based example implementation on iCEBreaker Board |
+| [icebreaker.pcf](icebreaker.pcf) | Pin constraints for implementation on iCEBreaker Board |
+| [icebreaker\_tb.v](icebreaker_tb.v) | Testbench for implementation on iCEBreaker Board |
+
+### Memory map:
+
+| Address Range | Description |
+| ------------------------ | --------------------------------------- |
+| 0x00000000 .. 0x00FFFFFF | Internal SRAM |
+| 0x01000000 .. 0x01FFFFFF | External Serial Flash |
+| 0x02000000 .. 0x02000003 | SPI Flash Controller Config Register |
+| 0x02000004 .. 0x02000007 | UART Clock Divider Register |
+| 0x02000008 .. 0x0200000B | UART Send/Recv Data Register |
+| 0x03000000 .. 0xFFFFFFFF | Memory mapped user peripherals |
+
+Reading from the addresses in the internal SRAM region beyond the end of the
+physical SRAM will read from the corresponding addresses in serial flash.
+
+Reading from the UART Send/Recv Data Register will return the last received
+byte, or -1 (all 32 bits set) when the receive buffer is empty.
+
+The UART Clock Divider Register must be set to the system clock frequency
+divided by the baud rate.
+
+The example design (hx8kdemo.v) has the 8 LEDs on the iCE40-HX8K Breakout Board
+mapped to the low byte of the 32 bit word at address 0x03000000.
+
+### SPI Flash Controller Config Register:
+
+| Bit(s) | Description |
+| -----: | --------------------------------------------------------- |
+| 31 | MEMIO Enable (reset=1, set to 0 to bit bang SPI commands) |
+| 30:23 | Reserved (read 0) |
+| 22 | DDR Enable bit (reset=0) |
+| 21 | QSPI Enable bit (reset=0) |
+| 20 | CRM Enable bit (reset=0) |
+| 19:16 | Read latency (dummy) cycles (reset=8) |
+| 15:12 | Reserved (read 0) |
+| 11:8 | IO Output enable bits in bit bang mode |
+| 7:6 | Reserved (read 0) |
+| 5 | Chip select (CS) line in bit bang mode |
+| 4 | Serial clock line in bit bang mode |
+| 3:0 | IO data bits in bit bang mode |
+
+The following settings for CRM/DDR/QSPI modes are valid:
+
+| CRM | QSPI | DDR | Read Command Byte | Mode Byte |
+| :-: | :--: | :-: | :-------------------- | :-------: |
+| 0 | 0 | 0 | 03h Read | N/A |
+| 0 | 0 | 1 | BBh Dual I/O Read | FFh |
+| 1 | 0 | 1 | BBh Dual I/O Read | A5h |
+| 0 | 1 | 0 | EBh Quad I/O Read | FFh |
+| 1 | 1 | 0 | EBh Quad I/O Read | A5h |
+| 0 | 1 | 1 | EDh DDR Quad I/O Read | FFh |
+| 1 | 1 | 1 | EDh DDR Quad I/O Read | A5h |
+
+The following plot visualizes the relative performance of the different configurations:
+
+![](performance.png)
+
+Consult the datasheet for your SPI flash to learn which configurations are supported
+by the chip and what the maximum clock frequencies are for each configuration.
+
+For Quad I/O mode the QUAD flag in CR1V must be set before enabling Quad I/O in the
+SPI master. Either set it by writing the corresponding bit in CR1NV once, or by writing
+it from your device firmware at every bootup. (See `set_flash_qspi_flag()` in
+`firmware.c` for an example for the latter.)
+
+Note that some changes to the Lattice iCE40-HX8K Breakout Board are required to support
+the faster configurations: (1) The flash chip must be replaced with one that supports the
+faster read commands and (2) the IO2 and IO3 pins on the flash chip must be connected to
+the FPGA IO pins T9 and T8 (near the center of J3).
+
diff --git a/picosoc/firmware.c b/picosoc/firmware.c
new file mode 100644
index 0000000..aadf31b
--- /dev/null
+++ b/picosoc/firmware.c
@@ -0,0 +1,770 @@
+/*
+ * PicoSoC - A simple example SoC using PicoRV32
+ *
+ * Copyright (C) 2017 Claire Xenia Wolf <claire@yosyshq.com>
+ *
+ * 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.
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#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
+
+// a pointer to this is a null pointer, but the compiler does not
+// know that because "sram" is a linker symbol from sections.lds.
+extern uint32_t sram;
+
+#define reg_spictrl (*(volatile uint32_t*)0x02000000)
+#define reg_uart_clkdiv (*(volatile uint32_t*)0x02000004)
+#define reg_uart_data (*(volatile uint32_t*)0x02000008)
+#define reg_leds (*(volatile uint32_t*)0x03000000)
+
+// --------------------------------------------------------
+
+extern uint32_t flashio_worker_begin;
+extern uint32_t flashio_worker_end;
+
+void flashio(uint8_t *data, int len, uint8_t wrencmd)
+{
+ uint32_t func[&flashio_worker_end - &flashio_worker_begin];
+
+ uint32_t *src_ptr = &flashio_worker_begin;
+ uint32_t *dst_ptr = func;
+
+ while (src_ptr != &flashio_worker_end)
+ *(dst_ptr++) = *(src_ptr++);
+
+ ((void(*)(uint8_t*, uint32_t, uint32_t))func)(data, len, wrencmd);
+}
+
+#ifdef HX8KDEMO
+void set_flash_qspi_flag()
+{
+ uint8_t buffer[8];
+ uint32_t addr_cr1v = 0x800002;
+
+ // Read Any Register (RDAR 65h)
+ buffer[0] = 0x65;
+ buffer[1] = addr_cr1v >> 16;
+ buffer[2] = addr_cr1v >> 8;
+ buffer[3] = addr_cr1v;
+ buffer[4] = 0; // dummy
+ buffer[5] = 0; // rdata
+ flashio(buffer, 6, 0);
+ uint8_t cr1v = buffer[5];
+
+ // Write Enable (WREN 06h) + Write Any Register (WRAR 71h)
+ buffer[0] = 0x71;
+ buffer[1] = addr_cr1v >> 16;
+ buffer[2] = addr_cr1v >> 8;
+ buffer[3] = addr_cr1v;
+ buffer[4] = cr1v | 2; // Enable QSPI
+ flashio(buffer, 5, 0x06);
+}
+
+void set_flash_latency(uint8_t value)
+{
+ reg_spictrl = (reg_spictrl & ~0x007f0000) | ((value & 15) << 16);
+
+ uint32_t addr = 0x800004;
+ uint8_t buffer_wr[5] = {0x71, addr >> 16, addr >> 8, addr, 0x70 | value};
+ flashio(buffer_wr, 5, 0x06);
+}
+
+void set_flash_mode_spi()
+{
+ reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00000000;
+}
+
+void set_flash_mode_dual()
+{
+ reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00400000;
+}
+
+void set_flash_mode_quad()
+{
+ reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00200000;
+}
+
+void set_flash_mode_qddr()
+{
+ reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00600000;
+}
+#endif
+
+#ifdef ICEBREAKER
+void set_flash_qspi_flag()
+{
+ uint8_t buffer[8];
+
+ // Read Configuration Registers (RDCR1 35h)
+ buffer[0] = 0x35;
+ buffer[1] = 0x00; // rdata
+ flashio(buffer, 2, 0);
+ uint8_t sr2 = buffer[1];
+
+ // Write Enable Volatile (50h) + Write Status Register 2 (31h)
+ buffer[0] = 0x31;
+ buffer[1] = sr2 | 2; // Enable QSPI
+ flashio(buffer, 2, 0x50);
+}
+
+void set_flash_mode_spi()
+{
+ reg_spictrl = (reg_spictrl & ~0x007f0000) | 0x00000000;
+}
+
+void set_flash_mode_dual()
+{
+ reg_spictrl = (reg_spictrl & ~0x007f0000) | 0x00400000;
+}
+
+void set_flash_mode_quad()
+{
+ reg_spictrl = (reg_spictrl & ~0x007f0000) | 0x00240000;
+}
+
+void set_flash_mode_qddr()
+{
+ reg_spictrl = (reg_spictrl & ~0x007f0000) | 0x00670000;
+}
+
+void enable_flash_crm()
+{
+ reg_spictrl |= 0x00100000;
+}
+#endif
+
+// --------------------------------------------------------
+
+void putchar(char c)
+{
+ if (c == '\n')
+ putchar('\r');
+ reg_uart_data = c;
+}
+
+void print(const char *p)
+{
+ while (*p)
+ putchar(*(p++));
+}
+
+void print_hex(uint32_t v, int digits)
+{
+ for (int i = 7; i >= 0; i--) {
+ char c = "0123456789abcdef"[(v >> (4*i)) & 15];
+ if (c == '0' && i >= digits) continue;
+ putchar(c);
+ digits = i;
+ }
+}
+
+void print_dec(uint32_t v)
+{
+ 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; }
+ else if (v >= 60) { putchar('6'); v -= 60; }
+ else if (v >= 50) { putchar('5'); v -= 50; }
+ else if (v >= 40) { putchar('4'); v -= 40; }
+ else if (v >= 30) { putchar('3'); v -= 30; }
+ else if (v >= 20) { putchar('2'); v -= 20; }
+ else if (v >= 10) { putchar('1'); v -= 10; }
+
+ if (v >= 9) { putchar('9'); v -= 9; }
+ else if (v >= 8) { putchar('8'); v -= 8; }
+ else if (v >= 7) { putchar('7'); v -= 7; }
+ else if (v >= 6) { putchar('6'); v -= 6; }
+ else if (v >= 5) { putchar('5'); v -= 5; }
+ else if (v >= 4) { putchar('4'); v -= 4; }
+ else if (v >= 3) { putchar('3'); v -= 3; }
+ else if (v >= 2) { putchar('2'); v -= 2; }
+ else if (v >= 1) { putchar('1'); v -= 1; }
+ else putchar('0');
+}
+
+char getchar_prompt(char *prompt)
+{
+ int32_t c = -1;
+
+ uint32_t cycles_begin, cycles_now, cycles;
+ __asm__ volatile ("rdcycle %0" : "=r"(cycles_begin));
+
+ reg_leds = ~0;
+
+ if (prompt)
+ print(prompt);
+
+ while (c == -1) {
+ __asm__ volatile ("rdcycle %0" : "=r"(cycles_now));
+ cycles = cycles_now - cycles_begin;
+ if (cycles > 12000000) {
+ if (prompt)
+ print(prompt);
+ cycles_begin = cycles_now;
+ reg_leds = ~reg_leds;
+ }
+ c = reg_uart_data;
+ }
+
+ reg_leds = 0;
+ return c;
+}
+
+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()
+{
+ uint8_t buffer[17] = { 0x9F, /* zeros */ };
+ flashio(buffer, 17, 0);
+
+ for (int i = 1; i <= 16; i++) {
+ putchar(' ');
+ print_hex(buffer[i], 2);
+ }
+ putchar('\n');
+}
+
+// --------------------------------------------------------
+
+#ifdef HX8KDEMO
+uint8_t cmd_read_flash_regs_print(uint32_t addr, const char *name)
+{
+ set_flash_latency(8);
+
+ uint8_t buffer[6] = {0x65, addr >> 16, addr >> 8, addr, 0, 0};
+ flashio(buffer, 6, 0);
+
+ print("0x");
+ print_hex(addr, 6);
+ print(" ");
+ print(name);
+ print(" 0x");
+ print_hex(buffer[5], 2);
+ print("\n");
+
+ return buffer[5];
+}
+
+void cmd_read_flash_regs()
+{
+ print("\n");
+ uint8_t sr1v = cmd_read_flash_regs_print(0x800000, "SR1V");
+ uint8_t sr2v = cmd_read_flash_regs_print(0x800001, "SR2V");
+ uint8_t cr1v = cmd_read_flash_regs_print(0x800002, "CR1V");
+ uint8_t cr2v = cmd_read_flash_regs_print(0x800003, "CR2V");
+ uint8_t cr3v = cmd_read_flash_regs_print(0x800004, "CR3V");
+ uint8_t vdlp = cmd_read_flash_regs_print(0x800005, "VDLP");
+}
+#endif
+
+#ifdef ICEBREAKER
+uint8_t cmd_read_flash_reg(uint8_t cmd)
+{
+ uint8_t buffer[2] = {cmd, 0};
+ flashio(buffer, 2, 0);
+ return buffer[1];
+}
+
+void print_reg_bit(int val, const char *name)
+{
+ for (int i = 0; i < 12; i++) {
+ if (*name == 0)
+ putchar(' ');
+ else
+ putchar(*(name++));
+ }
+
+ putchar(val ? '1' : '0');
+ putchar('\n');
+}
+
+void cmd_read_flash_regs()
+{
+ putchar('\n');
+
+ uint8_t sr1 = cmd_read_flash_reg(0x05);
+ uint8_t sr2 = cmd_read_flash_reg(0x35);
+ uint8_t sr3 = cmd_read_flash_reg(0x15);
+
+ print_reg_bit(sr1 & 0x01, "S0 (BUSY)");
+ print_reg_bit(sr1 & 0x02, "S1 (WEL)");
+ print_reg_bit(sr1 & 0x04, "S2 (BP0)");
+ print_reg_bit(sr1 & 0x08, "S3 (BP1)");
+ print_reg_bit(sr1 & 0x10, "S4 (BP2)");
+ print_reg_bit(sr1 & 0x20, "S5 (TB)");
+ print_reg_bit(sr1 & 0x40, "S6 (SEC)");
+ print_reg_bit(sr1 & 0x80, "S7 (SRP)");
+ putchar('\n');
+
+ print_reg_bit(sr2 & 0x01, "S8 (SRL)");
+ print_reg_bit(sr2 & 0x02, "S9 (QE)");
+ print_reg_bit(sr2 & 0x04, "S10 ----");
+ print_reg_bit(sr2 & 0x08, "S11 (LB1)");
+ print_reg_bit(sr2 & 0x10, "S12 (LB2)");
+ print_reg_bit(sr2 & 0x20, "S13 (LB3)");
+ print_reg_bit(sr2 & 0x40, "S14 (CMP)");
+ print_reg_bit(sr2 & 0x80, "S15 (SUS)");
+ putchar('\n');
+
+ print_reg_bit(sr3 & 0x01, "S16 ----");
+ print_reg_bit(sr3 & 0x02, "S17 ----");
+ print_reg_bit(sr3 & 0x04, "S18 (WPS)");
+ print_reg_bit(sr3 & 0x08, "S19 ----");
+ print_reg_bit(sr3 & 0x10, "S20 ----");
+ print_reg_bit(sr3 & 0x20, "S21 (DRV0)");
+ print_reg_bit(sr3 & 0x40, "S22 (DRV1)");
+ print_reg_bit(sr3 & 0x80, "S23 (HOLD)");
+ putchar('\n');
+}
+#endif
+
+// --------------------------------------------------------
+
+uint32_t cmd_benchmark(bool verbose, uint32_t *instns_p)
+{
+ uint8_t data[256];
+ uint32_t *words = (void*)data;
+
+ uint32_t x32 = 314159265;
+
+ uint32_t cycles_begin, cycles_end;
+ uint32_t instns_begin, instns_end;
+ __asm__ volatile ("rdcycle %0" : "=r"(cycles_begin));
+ __asm__ volatile ("rdinstret %0" : "=r"(instns_begin));
+
+ for (int i = 0; i < 20; i++)
+ {
+ for (int k = 0; k < 256; k++)
+ {
+ x32 ^= x32 << 13;
+ x32 ^= x32 >> 17;
+ x32 ^= x32 << 5;
+ data[k] = x32;
+ }
+
+ for (int k = 0, p = 0; k < 256; k++)
+ {
+ if (data[k])
+ data[p++] = k;
+ }
+
+ for (int k = 0, p = 0; k < 64; k++)
+ {
+ x32 = x32 ^ words[k];
+ }
+ }
+
+ __asm__ volatile ("rdcycle %0" : "=r"(cycles_end));
+ __asm__ volatile ("rdinstret %0" : "=r"(instns_end));
+
+ if (verbose)
+ {
+ print("Cycles: 0x");
+ print_hex(cycles_end - cycles_begin, 8);
+ putchar('\n');
+
+ print("Instns: 0x");
+ print_hex(instns_end - instns_begin, 8);
+ putchar('\n');
+
+ print("Chksum: 0x");
+ print_hex(x32, 8);
+ putchar('\n');
+ }
+
+ if (instns_p)
+ *instns_p = instns_end - instns_begin;
+
+ return cycles_end - cycles_begin;
+}
+
+// --------------------------------------------------------
+
+#ifdef HX8KDEMO
+void cmd_benchmark_all()
+{
+ uint32_t instns = 0;
+
+ print("default ");
+ reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00000000;
+ print(": ");
+ print_hex(cmd_benchmark(false, &instns), 8);
+ putchar('\n');
+
+ for (int i = 8; i > 0; i--)
+ {
+ print("dspi-");
+ print_dec(i);
+ print(" ");
+
+ set_flash_latency(i);
+ reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00400000;
+
+ print(": ");
+ print_hex(cmd_benchmark(false, &instns), 8);
+ putchar('\n');
+ }
+
+ for (int i = 8; i > 0; i--)
+ {
+ print("dspi-crm-");
+ print_dec(i);
+ print(" ");
+
+ set_flash_latency(i);
+ reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00500000;
+
+ print(": ");
+ print_hex(cmd_benchmark(false, &instns), 8);
+ putchar('\n');
+ }
+
+ for (int i = 8; i > 0; i--)
+ {
+ print("qspi-");
+ print_dec(i);
+ print(" ");
+
+ set_flash_latency(i);
+ reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00200000;
+
+ print(": ");
+ print_hex(cmd_benchmark(false, &instns), 8);
+ putchar('\n');
+ }
+
+ for (int i = 8; i > 0; i--)
+ {
+ print("qspi-crm-");
+ print_dec(i);
+ print(" ");
+
+ set_flash_latency(i);
+ reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00300000;
+
+ print(": ");
+ print_hex(cmd_benchmark(false, &instns), 8);
+ putchar('\n');
+ }
+
+ for (int i = 8; i > 0; i--)
+ {
+ print("qspi-ddr-");
+ print_dec(i);
+ print(" ");
+
+ set_flash_latency(i);
+ reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00600000;
+
+ print(": ");
+ print_hex(cmd_benchmark(false, &instns), 8);
+ putchar('\n');
+ }
+
+ for (int i = 8; i > 0; i--)
+ {
+ print("qspi-ddr-crm-");
+ print_dec(i);
+ print(" ");
+
+ set_flash_latency(i);
+ reg_spictrl = (reg_spictrl & ~0x00700000) | 0x00700000;
+
+ print(": ");
+ print_hex(cmd_benchmark(false, &instns), 8);
+ putchar('\n');
+ }
+
+ print("instns : ");
+ print_hex(instns, 8);
+ putchar('\n');
+}
+#endif
+
+#ifdef ICEBREAKER
+void cmd_benchmark_all()
+{
+ uint32_t instns = 0;
+
+ print("default ");
+ set_flash_mode_spi();
+ print_hex(cmd_benchmark(false, &instns), 8);
+ putchar('\n');
+
+ print("dual ");
+ set_flash_mode_dual();
+ print_hex(cmd_benchmark(false, &instns), 8);
+ putchar('\n');
+
+ // print("dual-crm ");
+ // enable_flash_crm();
+ // print_hex(cmd_benchmark(false, &instns), 8);
+ // putchar('\n');
+
+ print("quad ");
+ set_flash_mode_quad();
+ print_hex(cmd_benchmark(false, &instns), 8);
+ putchar('\n');
+
+ print("quad-crm ");
+ enable_flash_crm();
+ print_hex(cmd_benchmark(false, &instns), 8);
+ putchar('\n');
+
+ print("qddr ");
+ set_flash_mode_qddr();
+ print_hex(cmd_benchmark(false, &instns), 8);
+ putchar('\n');
+
+ print("qddr-crm ");
+ enable_flash_crm();
+ print_hex(cmd_benchmark(false, &instns), 8);
+ putchar('\n');
+
+}
+#endif
+
+void cmd_echo()
+{
+ print("Return to menu by sending '!'\n\n");
+ char c;
+ while ((c = getchar()) != '!')
+ putchar(c);
+}
+
+// --------------------------------------------------------
+
+void main()
+{
+ reg_leds = 31;
+ reg_uart_clkdiv = 104;
+ print("Booting..\n");
+
+ reg_leds = 63;
+ set_flash_qspi_flag();
+
+ reg_leds = 127;
+ while (getchar_prompt("Press ENTER to continue..\n") != '\r') { /* wait */ }
+
+ print("\n");
+ print(" ____ _ ____ ____\n");
+ print(" | _ \\(_) ___ ___/ ___| ___ / ___|\n");
+ print(" | |_) | |/ __/ _ \\___ \\ / _ \\| |\n");
+ print(" | __/| | (_| (_) |__) | (_) | |___\n");
+ print(" |_| |_|\\___\\___/____/ \\___/ \\____|\n");
+ print("\n");
+
+ print("Total memory: ");
+ print_dec(MEM_TOTAL / 1024);
+ print(" KiB\n");
+ print("\n");
+
+ //cmd_memtest(); // test overwrites bss and data memory
+ print("\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");
+ print(" [2] Read SPI Config Regs\n");
+ print(" [3] Switch to default mode\n");
+ print(" [4] Switch to Dual I/O mode\n");
+ print(" [5] Switch to Quad I/O mode\n");
+ print(" [6] Switch to Quad DDR mode\n");
+ 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");
+
+ for (int rep = 10; rep > 0; rep--)
+ {
+ print("Command> ");
+ char cmd = getchar();
+ if (cmd > 32 && cmd < 127)
+ putchar(cmd);
+ print("\n");
+
+ switch (cmd)
+ {
+ case '1':
+ cmd_read_flash_id();
+ break;
+ case '2':
+ cmd_read_flash_regs();
+ break;
+ case '3':
+ set_flash_mode_spi();
+ break;
+ case '4':
+ set_flash_mode_dual();
+ break;
+ case '5':
+ set_flash_mode_quad();
+ break;
+ case '6':
+ set_flash_mode_qddr();
+ break;
+ case '7':
+ reg_spictrl = reg_spictrl ^ 0x00100000;
+ break;
+ case '9':
+ cmd_benchmark(true, 0);
+ break;
+ case '0':
+ cmd_benchmark_all();
+ break;
+ case 'M':
+ cmd_memtest();
+ break;
+ case 'S':
+ cmd_print_spi_state();
+ break;
+ case 'e':
+ cmd_echo();
+ break;
+ default:
+ continue;
+ }
+
+ break;
+ }
+ }
+}
diff --git a/picosoc/hx8kdemo.core b/picosoc/hx8kdemo.core
new file mode 100644
index 0000000..97a1989
--- /dev/null
+++ b/picosoc/hx8kdemo.core
@@ -0,0 +1,35 @@
+CAPI=2:
+
+name : ::hx8kdemo:0
+
+filesets:
+ hx8kdemo:
+ files: [hx8kdemo.v]
+ file_type : verilogSource
+ depend : [picosoc]
+ hx8ksim:
+ files:
+ - hx8kdemo_tb.v
+ file_type : verilogSource
+ depend : [spiflash, "yosys:techlibs:ice40"]
+
+ constraints:
+ files: [hx8kdemo.pcf]
+ file_type : PCF
+
+targets:
+ synth:
+ default_tool : icestorm
+ filesets : [constraints, hx8kdemo]
+ tools:
+ icestorm:
+ arachne_pnr_options : [-d, 8k]
+ toplevel : [hx8kdemo]
+ sim:
+ default_tool : icarus
+ filesets : [hx8kdemo, hx8ksim]
+ tools:
+ xsim:
+ xelab_options : [--timescale, 1ns/1ps]
+
+ toplevel : [testbench]
diff --git a/picosoc/hx8kdemo.pcf b/picosoc/hx8kdemo.pcf
new file mode 100644
index 0000000..418bae8
--- /dev/null
+++ b/picosoc/hx8kdemo.pcf
@@ -0,0 +1,40 @@
+
+# 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
+
+# for QSPI mode the flash chip on the iCE40-HX8K Breakout Board
+# must be replaced with one that supports QSPI and the IO2 and IO3
+# pins must be soldered to T9 and P8 (center on J3)
+set_io flash_io2 T9
+set_io flash_io3 P8
+
+set_io ser_tx B12
+set_io ser_rx B10
+
+# left on J3
+set_io debug_ser_tx T1
+set_io debug_ser_rx R3
+
+# right on J3
+set_io debug_flash_csb T15
+set_io debug_flash_clk R16
+set_io debug_flash_io0 N12
+set_io debug_flash_io1 P13
+set_io debug_flash_io2 T13
+set_io debug_flash_io3 T14
+
+set_io leds[7] B5 # D9
+set_io leds[6] B4 # D8
+set_io leds[5] A2 # D7
+set_io leds[4] A1 # D6
+set_io leds[3] C5 # D5
+set_io leds[2] C4 # D4
+set_io leds[1] B3 # D3
+set_io leds[0] C3 # D2
+
diff --git a/picosoc/hx8kdemo.v b/picosoc/hx8kdemo.v
new file mode 100644
index 0000000..f9a82f1
--- /dev/null
+++ b/picosoc/hx8kdemo.v
@@ -0,0 +1,139 @@
+/*
+ * PicoSoC - A simple example SoC using PicoRV32
+ *
+ * Copyright (C) 2017 Claire Xenia Wolf <claire@yosyshq.com>
+ *
+ * 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,
+
+ output 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,
+
+ output debug_ser_tx,
+ output debug_ser_rx,
+
+ output debug_flash_csb,
+ output debug_flash_clk,
+ output debug_flash_io0,
+ output debug_flash_io1,
+ output debug_flash_io2,
+ output debug_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;
+
+ always @(posedge clk) begin
+ if (!resetn) begin
+ gpio <= 0;
+ end else begin
+ iomem_ready <= 0;
+ if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 03) 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
+ end
+
+ picosoc soc (
+ .clk (clk ),
+ .resetn (resetn ),
+
+ .ser_tx (ser_tx ),
+ .ser_rx (ser_rx ),
+
+ .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),
+
+ .irq_5 (1'b0 ),
+ .irq_6 (1'b0 ),
+ .irq_7 (1'b0 ),
+
+ .iomem_valid (iomem_valid ),
+ .iomem_ready (iomem_ready ),
+ .iomem_wstrb (iomem_wstrb ),
+ .iomem_addr (iomem_addr ),
+ .iomem_wdata (iomem_wdata ),
+ .iomem_rdata (iomem_rdata )
+ );
+
+ assign debug_ser_tx = ser_tx;
+ assign debug_ser_rx = ser_rx;
+
+ assign debug_flash_csb = flash_csb;
+ assign debug_flash_clk = flash_clk;
+ assign debug_flash_io0 = flash_io0_di;
+ assign debug_flash_io1 = flash_io1_di;
+ assign debug_flash_io2 = flash_io2_di;
+ assign debug_flash_io3 = flash_io3_di;
+endmodule
diff --git a/picosoc/hx8kdemo_tb.v b/picosoc/hx8kdemo_tb.v
new file mode 100644
index 0000000..3fe9c1d
--- /dev/null
+++ b/picosoc/hx8kdemo_tb.v
@@ -0,0 +1,108 @@
+/*
+ * PicoSoC - A simple example SoC using PicoRV32
+ *
+ * Copyright (C) 2017 Claire Xenia Wolf <claire@yosyshq.com>
+ *
+ * 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.
+ *
+ */
+
+`timescale 1 ns / 1 ps
+
+module testbench;
+ reg clk;
+ always #5 clk = (clk === 1'b0);
+
+ localparam ser_half_period = 53;
+ event ser_sample;
+
+ initial begin
+ $dumpfile("testbench.vcd");
+ $dumpvars(0, testbench);
+
+ repeat (6) begin
+ repeat (50000) @(posedge clk);
+ $display("+50000 cycles");
+ end
+ $finish;
+ end
+
+ integer cycle_cnt = 0;
+
+ always @(posedge clk) begin
+ cycle_cnt <= cycle_cnt + 1;
+ end
+
+ wire [7:0] leds;
+
+ wire ser_rx;
+ wire ser_tx;
+
+ wire flash_csb;
+ wire flash_clk;
+ wire flash_io0;
+ wire flash_io1;
+ wire flash_io2;
+ wire flash_io3;
+
+ always @(leds) begin
+ #1 $display("%b", leds);
+ end
+
+ hx8kdemo uut (
+ .clk (clk ),
+ .leds (leds ),
+ .ser_rx (ser_rx ),
+ .ser_tx (ser_tx ),
+ .flash_csb(flash_csb),
+ .flash_clk(flash_clk),
+ .flash_io0(flash_io0),
+ .flash_io1(flash_io1),
+ .flash_io2(flash_io2),
+ .flash_io3(flash_io3)
+ );
+
+ spiflash spiflash (
+ .csb(flash_csb),
+ .clk(flash_clk),
+ .io0(flash_io0),
+ .io1(flash_io1),
+ .io2(flash_io2),
+ .io3(flash_io3)
+ );
+
+ reg [7:0] buffer;
+
+ always begin
+ @(negedge ser_tx);
+
+ repeat (ser_half_period) @(posedge clk);
+ -> ser_sample; // start bit
+
+ repeat (8) begin
+ repeat (ser_half_period) @(posedge clk);
+ repeat (ser_half_period) @(posedge clk);
+ buffer = {ser_tx, buffer[7:1]};
+ -> ser_sample; // data bit
+ end
+
+ repeat (ser_half_period) @(posedge clk);
+ repeat (ser_half_period) @(posedge clk);
+ -> ser_sample; // stop bit
+
+ if (buffer < 32 || buffer >= 127)
+ $display("Serial data: %d", buffer);
+ else
+ $display("Serial data: '%c'", buffer);
+ end
+endmodule
diff --git a/picosoc/ice40up5k_spram.v b/picosoc/ice40up5k_spram.v
new file mode 100644
index 0000000..6d010f2
--- /dev/null
+++ b/picosoc/ice40up5k_spram.v
@@ -0,0 +1,91 @@
+
+/*
+ * PicoSoC - A simple example SoC using PicoRV32
+ *
+ * Copyright (C) 2017 Claire Xenia Wolf <claire@yosyshq.com>
+ *
+ * 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.core b/picosoc/icebreaker.core
new file mode 100644
index 0000000..5af5fd6
--- /dev/null
+++ b/picosoc/icebreaker.core
@@ -0,0 +1,36 @@
+CAPI=2:
+
+name : ::icebreaker:0
+
+filesets:
+ top:
+ files: [icebreaker.v]
+ file_type : verilogSource
+ depend : [picosoc]
+ tb:
+ files:
+ - icebreaker_tb.v
+ file_type : verilogSource
+ depend : [spiflash, "yosys:techlibs:ice40"]
+
+ constraints:
+ files: [icebreaker.pcf]
+ file_type : PCF
+
+targets:
+ synth:
+ default_tool : icestorm
+ filesets : [constraints, top]
+ tools:
+ icestorm:
+ nextpnr_options : [--freq, 13, --up5k]
+ pnr : next
+ toplevel : [icebreaker]
+ sim:
+ default_tool : icarus
+ filesets : [top, tb]
+ tools:
+ xsim:
+ xelab_options : [--timescale, 1ns/1ps]
+
+ toplevel : [testbench]
diff --git a/picosoc/icebreaker.pcf b/picosoc/icebreaker.pcf
new file mode 100644
index 0000000..86cf78e
--- /dev/null
+++ b/picosoc/icebreaker.pcf
@@ -0,0 +1,25 @@
+# 12 MHz clock
+set_io clk 35
+
+# RS232
+set_io ser_rx 6
+set_io ser_tx 9
+
+# SPI Flash
+set_io flash_clk 15
+set_io flash_csb 16
+set_io flash_io0 14
+set_io flash_io1 17
+set_io flash_io2 12
+set_io flash_io3 13
+
+# LEDs (PMOD 2)
+set_io led1 27
+set_io led2 25
+set_io led3 21
+set_io led4 23
+set_io led5 26
+
+# Onboard LEDs
+set_io ledr_n 11
+set_io ledg_n 37
diff --git a/picosoc/icebreaker.v b/picosoc/icebreaker.v
new file mode 100644
index 0000000..a943bc6
--- /dev/null
+++ b/picosoc/icebreaker.v
@@ -0,0 +1,151 @@
+/*
+ * PicoSoC - A simple example SoC using PicoRV32
+ *
+ * Copyright (C) 2017 Claire Xenia Wolf <claire@yosyshq.com>
+ *
+ * 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.
+ *
+ */
+
+`ifdef PICOSOC_V
+`error "icebreaker.v must be read before picosoc.v!"
+`endif
+
+`define PICOSOC_MEM ice40up5k_spram
+
+module icebreaker (
+ input clk,
+
+ output ser_tx,
+ input ser_rx,
+
+ output led1,
+ output led2,
+ output led3,
+ output led4,
+ output led5,
+
+ output ledr_n,
+ output ledg_n,
+
+ output flash_csb,
+ output flash_clk,
+ inout flash_io0,
+ inout flash_io1,
+ inout flash_io2,
+ inout flash_io3
+);
+ parameter integer MEM_WORDS = 32768;
+
+ reg [5:0] reset_cnt = 0;
+ wire resetn = &reset_cnt;
+
+ always @(posedge clk) begin
+ reset_cnt <= reset_cnt + !resetn;
+ end
+
+ wire [7:0] leds;
+
+ assign led1 = leds[1];
+ assign led2 = leds[2];
+ assign led3 = leds[3];
+ assign led4 = leds[4];
+ assign led5 = leds[5];
+
+ assign ledr_n = !leds[6];
+ assign ledg_n = !leds[7];
+
+ 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;
+
+ always @(posedge clk) begin
+ if (!resetn) begin
+ gpio <= 0;
+ end else begin
+ iomem_ready <= 0;
+ if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 03) 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
+ end
+
+ picosoc #(
+ .BARREL_SHIFTER(0),
+ .ENABLE_MUL(0),
+ .ENABLE_DIV(0),
+ .ENABLE_FAST_MUL(1),
+ .MEM_WORDS(MEM_WORDS)
+ ) soc (
+ .clk (clk ),
+ .resetn (resetn ),
+
+ .ser_tx (ser_tx ),
+ .ser_rx (ser_rx ),
+
+ .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),
+
+ .irq_5 (1'b0 ),
+ .irq_6 (1'b0 ),
+ .irq_7 (1'b0 ),
+
+ .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
diff --git a/picosoc/icebreaker_tb.v b/picosoc/icebreaker_tb.v
new file mode 100644
index 0000000..c09c10d
--- /dev/null
+++ b/picosoc/icebreaker_tb.v
@@ -0,0 +1,122 @@
+/*
+ * PicoSoC - A simple example SoC using PicoRV32
+ *
+ * Copyright (C) 2017 Claire Xenia Wolf <claire@yosyshq.com>
+ *
+ * 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.
+ *
+ */
+
+`timescale 1 ns / 1 ps
+
+module testbench;
+ reg clk;
+ always #5 clk = (clk === 1'b0);
+
+ localparam ser_half_period = 53;
+ event ser_sample;
+
+ initial begin
+ $dumpfile("testbench.vcd");
+ $dumpvars(0, testbench);
+
+ repeat (6) begin
+ repeat (50000) @(posedge clk);
+ $display("+50000 cycles");
+ end
+ $finish;
+ end
+
+ integer cycle_cnt = 0;
+
+ always @(posedge clk) begin
+ cycle_cnt <= cycle_cnt + 1;
+ end
+
+ wire led1, led2, led3, led4, led5;
+ wire ledr_n, ledg_n;
+
+ wire [6:0] leds = {!ledg_n, !ledr_n, led5, led4, led3, led2, led1};
+
+ wire ser_rx;
+ wire ser_tx;
+
+ wire flash_csb;
+ wire flash_clk;
+ wire flash_io0;
+ wire flash_io1;
+ wire flash_io2;
+ wire flash_io3;
+
+ always @(leds) begin
+ #1 $display("%b", leds);
+ end
+
+ 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 ),
+ .led3 (led3 ),
+ .led4 (led4 ),
+ .led5 (led5 ),
+ .ledr_n (ledr_n ),
+ .ledg_n (ledg_n ),
+ .ser_rx (ser_rx ),
+ .ser_tx (ser_tx ),
+ .flash_csb(flash_csb),
+ .flash_clk(flash_clk),
+ .flash_io0(flash_io0),
+ .flash_io1(flash_io1),
+ .flash_io2(flash_io2),
+ .flash_io3(flash_io3)
+ );
+
+ spiflash spiflash (
+ .csb(flash_csb),
+ .clk(flash_clk),
+ .io0(flash_io0),
+ .io1(flash_io1),
+ .io2(flash_io2),
+ .io3(flash_io3)
+ );
+
+ reg [7:0] buffer;
+
+ always begin
+ @(negedge ser_tx);
+
+ repeat (ser_half_period) @(posedge clk);
+ -> ser_sample; // start bit
+
+ repeat (8) begin
+ repeat (ser_half_period) @(posedge clk);
+ repeat (ser_half_period) @(posedge clk);
+ buffer = {ser_tx, buffer[7:1]};
+ -> ser_sample; // data bit
+ end
+
+ repeat (ser_half_period) @(posedge clk);
+ repeat (ser_half_period) @(posedge clk);
+ -> ser_sample; // stop bit
+
+ if (buffer < 32 || buffer >= 127)
+ $display("Serial data: %d", buffer);
+ else
+ $display("Serial data: '%c'", buffer);
+ end
+endmodule
diff --git a/picosoc/overview.svg b/picosoc/overview.svg
new file mode 100644
index 0000000..2335f76
--- /dev/null
+++ b/picosoc/overview.svg
@@ -0,0 +1,757 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="752.71472"
+ height="512"
+ viewBox="0 0 752.71472 512"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="overview.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.4"
+ inkscape:cx="323.81769"
+ inkscape:cy="196.47245"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ units="px"
+ fit-margin-top="10"
+ fit-margin-right="10"
+ fit-margin-bottom="10"
+ fit-margin-left="10"
+ inkscape:window-width="1855"
+ inkscape:window-height="1056"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3336"
+ originx="184.53606"
+ originy="-656.49999" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(184.53606,116.13779)">
+ <rect
+ style="opacity:1;fill:#b3b3d0;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.93901455;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3338"
+ width="601.48956"
+ height="490.06097"
+ x="-62.083782"
+ y="-105.16828" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="-45.2868"
+ y="-60.797707"
+ id="text3340"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3342"
+ x="-45.2868"
+ y="-60.797707"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:37.5px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">Your Chip</tspan></text>
+ <rect
+ style="opacity:1;fill:#b3e1b3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3344"
+ width="270"
+ height="390"
+ x="-32.053295"
+ y="-35.137794" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="-22.429668"
+ y="-1.2263393"
+ id="text3340-0"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3342-9"
+ x="-22.429668"
+ y="-1.2263393"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">PicoSoC</tspan></text>
+ <rect
+ style="opacity:1;fill:#d9883a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3364"
+ width="110"
+ height="90"
+ x="-22.053295"
+ y="24.862207" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="35.3167"
+ y="56.630821"
+ id="text3340-0-7"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ x="35.3167"
+ y="56.630821"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
+ id="tspan3384">XIP SPI</tspan><tspan
+ sodipodi:role="line"
+ x="35.3167"
+ y="75.380821"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
+ id="tspan3390">Flash</tspan><tspan
+ sodipodi:role="line"
+ x="35.3167"
+ y="94.130821"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
+ id="tspan3392">Controller</tspan><tspan
+ sodipodi:role="line"
+ x="35.3167"
+ y="112.88082"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
+ id="tspan3386" /></text>
+ <rect
+ style="opacity:1;fill:#d9883a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.64055121;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3394"
+ width="110.35945"
+ height="60.359447"
+ x="-22.233013"
+ y="124.68247" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="34.602421"
+ y="160.34511"
+ id="text3340-0-7-9"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ x="34.602421"
+ y="160.34511"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
+ id="tspan3386-2">UART</tspan></text>
+ <rect
+ style="opacity:1;fill:#d9883a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3432"
+ width="110"
+ height="150"
+ x="-22.053295"
+ y="194.8622" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="33.459568"
+ y="261.91653"
+ id="text3340-0-7-9-6"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ x="33.459568"
+ y="261.91653"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
+ id="tspan3386-2-6">SRAM</tspan><tspan
+ sodipodi:role="line"
+ x="33.459568"
+ y="280.66653"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
+ id="tspan3452" /><tspan
+ sodipodi:role="line"
+ x="33.459568"
+ y="294.5386"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
+ id="tspan3454">(default 1kB)</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="165.82141"
+ y="38.508293"
+ id="text3340-0-7-5"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ x="165.82141"
+ y="38.508293"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
+ id="tspan3494">32 Bit System Bus</tspan></text>
+ <rect
+ style="opacity:1;fill:#d9883a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.19784403;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3496"
+ width="119.80215"
+ height="290.30978"
+ x="108.04526"
+ y="55.060112" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="156.32541"
+ y="79.02784"
+ id="text3340-0-7-9-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ x="156.32541"
+ y="79.02784"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:center;text-anchor:middle"
+ id="tspan3386-2-9">PicoRV32</tspan></text>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 87.946684,264.8622 10,0 0,-219.999994 149.999996,0"
+ id="path3518"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 87.946684,154.8622 10,0"
+ id="path3520"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 87.946684,64.862196 10,0"
+ id="path3522"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 167.94668,44.862206 0,9.41744 0,0"
+ id="path3524"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -22.053466,144.8622 -60,0"
+ id="path3526"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -22.053466,164.8622 -60,0"
+ id="path3528"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -22.053466,34.862206 -60,0"
+ id="path3530"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -22.053466,54.862206 -60,0"
+ id="path3532"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -22.053466,74.862196 -60,0"
+ id="path3534"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -22.053466,84.862196 -60,0"
+ id="path3536"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -22.053466,94.862196 -60,0"
+ id="path3538"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -22.053466,104.8622 -60,0"
+ id="path3540"
+ inkscape:connector-curvature="0" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="-150.03317"
+ y="38.357124"
+ id="text4342"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4344"
+ x="-150.03317"
+ y="38.357124"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">FLASH_SCK</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="-150.03317"
+ y="58.357109"
+ id="text4342-0"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4344-2"
+ x="-150.03317"
+ y="58.357109"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">FLASH_CSB</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="-150.03317"
+ y="78.357109"
+ id="text4342-9"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4344-6"
+ x="-150.03317"
+ y="78.357109"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">FLASH_IO0</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="-150.03317"
+ y="87.857079"
+ id="text4342-5"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4344-4"
+ x="-150.03317"
+ y="87.857079"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">FLASH_IO1</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="-150.03317"
+ y="98.357109"
+ id="text4342-3"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4344-7"
+ x="-150.03317"
+ y="98.357109"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">FLASH_IO2</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="-150.03317"
+ y="107.85708"
+ id="text4342-05"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4344-0"
+ x="-150.03317"
+ y="107.85708"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">FLASH_IO3</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="-148.6046"
+ y="148.14287"
+ id="text4342-7"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4344-28"
+ x="-148.6046"
+ y="148.14287"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">SERIAL_TX</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="-148.46175"
+ y="168.14287"
+ id="text4342-7-4"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4344-28-2"
+ x="-148.46175"
+ y="168.14287"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">SERIAL_RX</tspan></text>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -81.821316,364.8622 349.999996,0 0,-10"
+ id="path4432"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -81.821316,374.8622 359.999996,0 0,-20"
+ id="path4434"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -21.821316,354.8622 0,10 0,0"
+ id="path4436"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -11.821316,354.8622 0,20"
+ id="path4438"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="opacity:1;fill:#c7ca58;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.96552444;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3344-5"
+ width="260.74875"
+ height="390.03448"
+ x="248.3298"
+ y="-34.998299" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="259.57034"
+ y="-1.2263241"
+ id="text3340-0-73"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3342-9-8"
+ x="259.57034"
+ y="-1.2263241"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">Your Circuit</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="-174.88274"
+ y="368.80356"
+ id="text4342-9-9"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4344-6-1"
+ x="-174.88274"
+ y="368.80356"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">SYSTEM_CLOCK</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:80px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="-174.88274"
+ y="378.30356"
+ id="text4342-5-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4344-4-9"
+ x="-174.88274"
+ y="378.30356"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, '">SYSTEM_RESET</tspan></text>
+ <rect
+ style="opacity:1;fill:#d46785;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.95069826;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect4497"
+ width="218.62073"
+ height="60.049301"
+ x="278.15402"
+ y="24.837549" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 248.17868,44.862206 30,0"
+ id="path4499"
+ inkscape:connector-curvature="0" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="288.32541"
+ y="47.02784"
+ id="text3340-0-7-9-1-9"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ x="288.32541"
+ y="47.02784"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:start;text-anchor:start"
+ id="tspan3386-2-9-7">GPIO Controller</tspan></text>
+ <rect
+ style="opacity:1;fill:#d46785;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect4519"
+ width="220"
+ height="120"
+ x="278.17868"
+ y="104.86222" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="290.32541"
+ y="127.02784"
+ id="text3340-0-7-9-1-9-0"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ x="290.32541"
+ y="127.02784"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:start;text-anchor:start"
+ id="tspan3386-2-9-7-9">Custom Block</tspan></text>
+ <rect
+ style="opacity:1;fill:#d46785;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect4539"
+ width="220"
+ height="100"
+ x="278.17868"
+ y="244.8622" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="290.32541"
+ y="267.02783"
+ id="text3340-0-7-9-1-9-0-6"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ x="290.32541"
+ y="267.02783"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:start;text-anchor:start"
+ id="tspan3386-2-9-7-9-6">Custom Block</tspan></text>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 258.17868,44.862206 0,219.999994 20,0"
+ id="path4559"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 298.17868,84.862196 0,20.000004"
+ id="path4561"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 308.17868,84.862196 0,20.000004"
+ id="path4563"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 318.17868,84.862196 0,20.000004"
+ id="path4565"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 328.17868,84.862196 0,20.000004"
+ id="path4567"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 338.17868,84.862196 0,20.000004"
+ id="path4569"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 348.17868,84.862196 0,20.000004"
+ id="path4571"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 358.17868,84.862196 0,20.000004"
+ id="path4573"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 368.17868,84.862196 0,20.000004"
+ id="path4575"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 378.17868,84.862196 0,20.000004"
+ id="path4577"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 388.17868,84.862196 0,20.000004"
+ id="path4579"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 398.17868,84.862196 0,20.000004"
+ id="path4581"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 408.17868,84.862196 0,20.000004"
+ id="path4583"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 418.17868,84.862196 0,20.000004"
+ id="path4585"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 428.17868,84.862196 0,20.000004"
+ id="path4587"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 438.17868,84.862196 0,20.000004"
+ id="path4589"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 448.17868,84.862196 0,20.000004"
+ id="path4591"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 458.17868,84.862196 0,20.000004"
+ id="path4593"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 468.17868,84.862196 0,20.000004"
+ id="path4595"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 478.17868,84.862196 0,20.000004"
+ id="path4597"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 488.17868,84.862196 0,20.000004"
+ id="path4599"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.17868,114.8622 60,0"
+ id="path4601"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.17868,124.8622 60,0"
+ id="path4603"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.17868,134.8622 60,0"
+ id="path4605"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.17868,144.8622 60,0"
+ id="path4607"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.17868,254.8622 60,0"
+ id="path4609"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.17868,264.8622 60,0"
+ id="path4611"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.17868,274.8622 60,0"
+ id="path4613"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.17868,284.8622 60,0"
+ id="path4615"
+ inkscape:connector-curvature="0" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="124.32541"
+ y="111.02784"
+ id="text3340-0-7-9-1-2"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ x="124.32541"
+ y="111.02784"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:start;text-anchor:start"
+ id="tspan3386-2-9-8">- RISC-V ISA</tspan><tspan
+ sodipodi:role="line"
+ x="124.32541"
+ y="123.52784"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:start;text-anchor:start"
+ id="tspan4637">- RV32IMC</tspan><tspan
+ sodipodi:role="line"
+ x="124.32541"
+ y="136.02783"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';text-align:start;text-anchor:start"
+ id="tspan4639">- GNU Toolchain</tspan></text>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.17868,154.85204 60,0"
+ id="path4601-3"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.17868,164.85204 60,0"
+ id="path4603-6"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.17868,174.85204 60,0"
+ id="path4605-7"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.17868,184.85204 60,0"
+ id="path4607-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.17868,194.60966 60,0"
+ id="path4601-3-3"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.17868,204.60966 60,0"
+ id="path4603-6-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.17868,214.60966 60,0"
+ id="path4605-7-6"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.07153,294.75505 60,0"
+ id="path4607-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.07153,304.74489 60,0"
+ id="path4601-3-1"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.07153,314.74489 60,0"
+ id="path4603-6-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.07153,324.74489 60,0"
+ id="path4605-7-7"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 498.07153,334.74489 60,0"
+ id="path4607-5-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 497.71438,29.85204 60,0"
+ id="path4603-6-7"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 497.71438,39.85204 60,0"
+ id="path4605-7-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 497.71438,49.85204 60,0"
+ id="path4607-5-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 497.71438,59.60966 60,0"
+ id="path4601-3-3-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 497.71438,69.60966 60,0"
+ id="path4603-6-5-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 497.71438,79.60966 60,0"
+ id="path4605-7-6-3"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/picosoc/performance.png b/picosoc/performance.png
new file mode 100644
index 0000000..aac75b2
--- /dev/null
+++ b/picosoc/performance.png
Binary files differ
diff --git a/picosoc/performance.py b/picosoc/performance.py
new file mode 100644
index 0000000..92c50c5
--- /dev/null
+++ b/picosoc/performance.py
@@ -0,0 +1,165 @@
+#!/usr/bin/env python3
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+uncompr_text = """
+default : 010f52ef
+dspi-8 : 008dc82f
+dspi-7 : 008d6d63
+dspi-6 : 008d1297
+dspi-5 : 008cb7cb
+dspi-4 : 008c5cff
+dspi-3 : 008c0233
+dspi-2 : 008ba767
+dspi-1 : 008b4c9b
+dspi-crm-8 : 008af1cf
+dspi-crm-7 : 008a9703
+dspi-crm-6 : 008a3c37
+dspi-crm-5 : 0089e16b
+dspi-crm-4 : 0089869f
+dspi-crm-3 : 00892bd3
+dspi-crm-2 : 0088d107
+dspi-crm-1 : 0088763b
+qspi-8 : 004a2c6f
+qspi-7 : 0049d1a3
+qspi-6 : 004976d7
+qspi-5 : 00491c0b
+qspi-4 : 0048c13f
+qspi-3 : 00486673
+qspi-2 : 00480ba7
+qspi-1 : 0047b0db
+qspi-crm-8 : 0047560f
+qspi-crm-7 : 0046fb43
+qspi-crm-6 : 0046a077
+qspi-crm-5 : 004645ab
+qspi-crm-4 : 0045eadf
+qspi-crm-3 : 00459013
+qspi-crm-2 : 00453547
+qspi-crm-1 : 0044da7b
+qspi-ddr-8 : 00288bf5
+qspi-ddr-7 : 00283129
+qspi-ddr-6 : 0027d65d
+qspi-ddr-5 : 00277b91
+qspi-ddr-4 : 002720c5
+qspi-ddr-3 : 0026c5f9
+qspi-ddr-2 : 00266b2d
+qspi-ddr-1 : 00261061
+qspi-ddr-crm-8 : 0025b595
+qspi-ddr-crm-7 : 00255ac9
+qspi-ddr-crm-6 : 0024fffd
+qspi-ddr-crm-5 : 0024a531
+qspi-ddr-crm-4 : 00244a65
+qspi-ddr-crm-3 : 0023ef99
+qspi-ddr-crm-2 : 002394cd
+qspi-ddr-crm-1 : 00233a01
+instns : 0003df2d
+"""
+
+compr_text = """
+default : 00f3d36d
+dspi-8 : 008008ad
+dspi-7 : 007fade1
+dspi-6 : 007f5315
+dspi-5 : 007ef849
+dspi-4 : 007e9d7d
+dspi-3 : 007e42b1
+dspi-2 : 007de7e5
+dspi-1 : 007d8d19
+dspi-crm-8 : 007d324d
+dspi-crm-7 : 007cd781
+dspi-crm-6 : 007c7cb5
+dspi-crm-5 : 007c21e9
+dspi-crm-4 : 007bc71d
+dspi-crm-3 : 007b6c51
+dspi-crm-2 : 007b1185
+dspi-crm-1 : 007ab6b9
+qspi-8 : 00434ced
+qspi-7 : 0042f221
+qspi-6 : 00429755
+qspi-5 : 00423c89
+qspi-4 : 0041e1bd
+qspi-3 : 004186f1
+qspi-2 : 00412c25
+qspi-1 : 0040d159
+qspi-crm-8 : 0040768d
+qspi-crm-7 : 00401bc1
+qspi-crm-6 : 003fc0f5
+qspi-crm-5 : 003f6629
+qspi-crm-4 : 003f0b5d
+qspi-crm-3 : 003eb091
+qspi-crm-2 : 003e55c5
+qspi-crm-1 : 003dfaf9
+qspi-ddr-8 : 00255d87
+qspi-ddr-7 : 002502bb
+qspi-ddr-6 : 0024a7ef
+qspi-ddr-5 : 00244d23
+qspi-ddr-4 : 0023f257
+qspi-ddr-3 : 0023978b
+qspi-ddr-2 : 00233cbf
+qspi-ddr-1 : 0022e1f3
+qspi-ddr-crm-8 : 00228727
+qspi-ddr-crm-7 : 00222c5b
+qspi-ddr-crm-6 : 0021d18f
+qspi-ddr-crm-5 : 002176c3
+qspi-ddr-crm-4 : 00211bf7
+qspi-ddr-crm-3 : 0020c12b
+qspi-ddr-crm-2 : 0020665f
+qspi-ddr-crm-1 : 00200b93
+instns : 0003df2d
+"""
+
+labels = list()
+uncompr_values = list()
+compr_values = list()
+
+for line in uncompr_text.split("\n"):
+ if line != "":
+ line = line.split()
+ if line[0] == "instns":
+ for i in range(len(uncompr_values)):
+ uncompr_values[i] = int(line[2], 16) / uncompr_values[i]
+ else:
+ labels.append(line[0])
+ uncompr_values.append(int(line[2], 16))
+
+for line in compr_text.split("\n"):
+ if line != "":
+ line = line.split()
+ if line[0] == "instns":
+ for i in range(len(compr_values)):
+ compr_values[i] = int(line[2], 16) / compr_values[i]
+ else:
+ compr_values.append(int(line[2], 16))
+
+print(np.array(compr_values) / np.array(uncompr_values))
+
+values = list()
+for i in range(len(compr_values)):
+ values.append(uncompr_values[i] / uncompr_values[0])
+ # values.append(compr_values[i] / compr_values[0])
+
+values = np.array(values)
+print(values)
+
+plt.figure(figsize=(10, 5))
+plt.title("Performance comparison for different PicoSoC SPI flash configurations")
+plt.plot(range(len(labels)), values)
+plt.xticks(range(len(labels)), labels, rotation=80)
+
+for color, x1, x2 in [["black", 0, 0], ["red", 1, 8], ["green", 9, 16],
+ ["red", 17, 24], ["green", 25, 32], ["red", 33, 40], ["green", 41, 48]]:
+ for t in plt.axes().xaxis.get_ticklabels()[x1:x2+1]:
+ t.set_color(color)
+ plt.plot([x1, x1], [0, values[x1] - 0.2], color=color)
+ plt.plot([x2, x2], [0, values[x2] - 0.2], color=color)
+ plt.plot([x1], [values[x1]], "k.")
+ plt.plot([x2], [values[x2]], "k.")
+
+plt.xlim(-1, len(labels))
+plt.ylim(0, 9)
+plt.grid()
+
+plt.gcf().subplots_adjust(bottom=0.3)
+plt.savefig("performance.png")
+# plt.show()
diff --git a/picosoc/picosoc.core b/picosoc/picosoc.core
new file mode 100644
index 0000000..eb0988a
--- /dev/null
+++ b/picosoc/picosoc.core
@@ -0,0 +1,27 @@
+CAPI=2:
+
+name : ::picosoc:0
+
+filesets:
+ picosoc:
+ files:
+ - simpleuart.v
+ - spimemio.v
+ - picosoc.v
+ file_type : verilogSource
+ depend : [picorv32]
+
+targets:
+ default:
+ filesets : [picosoc]
+ 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
new file mode 100644
index 0000000..9790791
--- /dev/null
+++ b/picosoc/picosoc.v
@@ -0,0 +1,262 @@
+/*
+ * PicoSoC - A simple example SoC using PicoRV32
+ *
+ * Copyright (C) 2017 Claire Xenia Wolf <claire@yosyshq.com>
+ *
+ * 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.
+ *
+ */
+
+`ifndef PICORV32_REGS
+`ifdef PICORV32_V
+`error "picosoc.v must be read before picorv32.v!"
+`endif
+
+`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,
+
+ 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,
+
+ input irq_5,
+ input irq_6,
+ input irq_7,
+
+ output ser_tx,
+ input ser_rx,
+
+ output flash_csb,
+ output flash_clk,
+
+ 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 [0:0] BARREL_SHIFTER = 1;
+ parameter [0:0] ENABLE_MUL = 1;
+ parameter [0:0] ENABLE_DIV = 1;
+ parameter [0:0] ENABLE_FAST_MUL = 0;
+ parameter [0:0] ENABLE_COMPRESSED = 1;
+ parameter [0:0] ENABLE_COUNTERS = 1;
+ parameter [0:0] ENABLE_IRQ_QREGS = 0;
+
+ parameter integer MEM_WORDS = 256;
+ parameter [31:0] STACKADDR = (4*MEM_WORDS); // end of memory
+ parameter [31:0] PROGADDR_RESET = 32'h 0010_0000; // 1 MB into flash
+ parameter [31:0] PROGADDR_IRQ = 32'h 0000_0000;
+
+ reg [31:0] irq;
+ wire irq_stall = 0;
+ wire irq_uart = 0;
+
+ always @* begin
+ irq = 0;
+ irq[3] = irq_stall;
+ irq[4] = irq_uart;
+ irq[5] = irq_5;
+ irq[6] = irq_6;
+ irq[7] = irq_7;
+ end
+
+ wire mem_valid;
+ wire mem_instr;
+ wire mem_ready;
+ wire [31:0] mem_addr;
+ wire [31:0] mem_wdata;
+ wire [3:0] mem_wstrb;
+ wire [31:0] mem_rdata;
+
+ wire spimem_ready;
+ wire [31:0] spimem_rdata;
+
+ reg ram_ready;
+ wire [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;
+
+ wire spimemio_cfgreg_sel = mem_valid && (mem_addr == 32'h 0200_0000);
+ wire [31:0] spimemio_cfgreg_do;
+
+ wire simpleuart_reg_div_sel = mem_valid && (mem_addr == 32'h 0200_0004);
+ wire [31:0] simpleuart_reg_div_do;
+
+ wire simpleuart_reg_dat_sel = mem_valid && (mem_addr == 32'h 0200_0008);
+ wire [31:0] simpleuart_reg_dat_do;
+ wire simpleuart_reg_dat_wait;
+
+ assign mem_ready = (iomem_valid && iomem_ready) || spimem_ready || ram_ready || spimemio_cfgreg_sel ||
+ simpleuart_reg_div_sel || (simpleuart_reg_dat_sel && !simpleuart_reg_dat_wait);
+
+ assign mem_rdata = (iomem_valid && iomem_ready) ? iomem_rdata : spimem_ready ? spimem_rdata : ram_ready ? ram_rdata :
+ spimemio_cfgreg_sel ? spimemio_cfgreg_do : simpleuart_reg_div_sel ? simpleuart_reg_div_do :
+ simpleuart_reg_dat_sel ? simpleuart_reg_dat_do : 32'h 0000_0000;
+
+ picorv32 #(
+ .STACKADDR(STACKADDR),
+ .PROGADDR_RESET(PROGADDR_RESET),
+ .PROGADDR_IRQ(PROGADDR_IRQ),
+ .BARREL_SHIFTER(BARREL_SHIFTER),
+ .COMPRESSED_ISA(ENABLE_COMPRESSED),
+ .ENABLE_COUNTERS(ENABLE_COUNTERS),
+ .ENABLE_MUL(ENABLE_MUL),
+ .ENABLE_DIV(ENABLE_DIV),
+ .ENABLE_FAST_MUL(ENABLE_FAST_MUL),
+ .ENABLE_IRQ(1),
+ .ENABLE_IRQ_QREGS(ENABLE_IRQ_QREGS)
+ ) cpu (
+ .clk (clk ),
+ .resetn (resetn ),
+ .mem_valid (mem_valid ),
+ .mem_instr (mem_instr ),
+ .mem_ready (mem_ready ),
+ .mem_addr (mem_addr ),
+ .mem_wdata (mem_wdata ),
+ .mem_wstrb (mem_wstrb ),
+ .mem_rdata (mem_rdata ),
+ .irq (irq )
+ );
+
+ spimemio spimemio (
+ .clk (clk),
+ .resetn (resetn),
+ .valid (mem_valid && mem_addr >= 4*MEM_WORDS && mem_addr < 32'h 0200_0000),
+ .ready (spimem_ready),
+ .addr (mem_addr[23:0]),
+ .rdata (spimem_rdata),
+
+ .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),
+
+ .cfgreg_we(spimemio_cfgreg_sel ? mem_wstrb : 4'b 0000),
+ .cfgreg_di(mem_wdata),
+ .cfgreg_do(spimemio_cfgreg_do)
+ );
+
+ simpleuart simpleuart (
+ .clk (clk ),
+ .resetn (resetn ),
+
+ .ser_tx (ser_tx ),
+ .ser_rx (ser_rx ),
+
+ .reg_div_we (simpleuart_reg_div_sel ? mem_wstrb : 4'b 0000),
+ .reg_div_di (mem_wdata),
+ .reg_div_do (simpleuart_reg_div_do),
+
+ .reg_dat_we (simpleuart_reg_dat_sel ? mem_wstrb[0] : 1'b 0),
+ .reg_dat_re (simpleuart_reg_dat_sel && !mem_wstrb),
+ .reg_dat_di (mem_wdata),
+ .reg_dat_do (simpleuart_reg_dat_do),
+ .reg_dat_wait(simpleuart_reg_dat_wait)
+ );
+
+ always @(posedge clk)
+ ram_ready <= mem_valid && !mem_ready && mem_addr < 4*MEM_WORDS;
+
+ `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]),
+ .wdata(mem_wdata),
+ .rdata(ram_rdata)
+ );
+endmodule
+
+// Implementation note:
+// Replace the following two modules with wrappers for your SRAM cells.
+
+module picosoc_regs (
+ input clk, wen,
+ input [5:0] waddr,
+ input [5:0] raddr1,
+ input [5:0] raddr2,
+ input [31:0] wdata,
+ output [31:0] rdata1,
+ output [31:0] rdata2
+);
+ reg [31:0] regs [0:31];
+
+ always @(posedge clk)
+ if (wen) regs[waddr[4:0]] <= wdata;
+
+ assign rdata1 = regs[raddr1[4:0]];
+ assign rdata2 = regs[raddr2[4:0]];
+endmodule
+
+module picosoc_mem #(
+ parameter integer WORDS = 256
+) (
+ input clk,
+ input [3:0] wen,
+ input [21:0] addr,
+ input [31:0] wdata,
+ output reg [31:0] rdata
+);
+ reg [31:0] mem [0:WORDS-1];
+
+ always @(posedge clk) begin
+ rdata <= mem[addr];
+ if (wen[0]) mem[addr][ 7: 0] <= wdata[ 7: 0];
+ if (wen[1]) mem[addr][15: 8] <= wdata[15: 8];
+ if (wen[2]) mem[addr][23:16] <= wdata[23:16];
+ if (wen[3]) mem[addr][31:24] <= wdata[31:24];
+ end
+endmodule
+
diff --git a/picosoc/sections.lds b/picosoc/sections.lds
new file mode 100644
index 0000000..f38d813
--- /dev/null
+++ b/picosoc/sections.lds
@@ -0,0 +1,71 @@
+#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 = MEM_TOTAL
+}
+
+SECTIONS {
+ /* The program code and other data goes into FLASH */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ *(.srodata) /* .rodata sections (constants, strings, etc.) */
+ *(.srodata*) /* .rodata* sections (constants, strings, etc.) */
+ . = ALIGN(4);
+ _etext = .; /* define a global symbol at end of code */
+ _sidata = _etext; /* This is used by the startup in order to initialize the .data secion */
+ } >FLASH
+
+
+ /* This is the initialized data section
+ The program executes knowing that the data is in the RAM
+ but the loader puts the initial values in the FLASH (inidata).
+ It is one task of the startup to copy the initial values from FLASH to RAM. */
+ .data : AT ( _sidata )
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */
+ _ram_start = .; /* create a global symbol at ram start for garbage collector */
+ . = ALIGN(4);
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+ *(.sdata) /* .sdata sections */
+ *(.sdata*) /* .sdata* sections */
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
+ } >RAM
+
+ /* Uninitialized data section */
+ .bss :
+ {
+ . = ALIGN(4);
+ _sbss = .; /* define a global symbol at bss start; used by startup code */
+ *(.bss)
+ *(.bss*)
+ *(.sbss)
+ *(.sbss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end; used by startup code */
+ } >RAM
+
+ /* this is to define the start of the heap, and make sure we have a minimum size */
+ .heap :
+ {
+ . = ALIGN(4);
+ _heap_start = .; /* define a global symbol at heap start */
+ } >RAM
+}
diff --git a/picosoc/simpleuart.v b/picosoc/simpleuart.v
new file mode 100644
index 0000000..5ffef77
--- /dev/null
+++ b/picosoc/simpleuart.v
@@ -0,0 +1,137 @@
+/*
+ * PicoSoC - A simple example SoC using PicoRV32
+ *
+ * Copyright (C) 2017 Claire Xenia Wolf <claire@yosyshq.com>
+ *
+ * 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 simpleuart #(parameter integer DEFAULT_DIV = 1) (
+ input clk,
+ input resetn,
+
+ output ser_tx,
+ input ser_rx,
+
+ input [3:0] reg_div_we,
+ input [31:0] reg_div_di,
+ output [31:0] reg_div_do,
+
+ input reg_dat_we,
+ input reg_dat_re,
+ input [31:0] reg_dat_di,
+ output [31:0] reg_dat_do,
+ output reg_dat_wait
+);
+ reg [31:0] cfg_divider;
+
+ reg [3:0] recv_state;
+ reg [31:0] recv_divcnt;
+ reg [7:0] recv_pattern;
+ reg [7:0] recv_buf_data;
+ reg recv_buf_valid;
+
+ reg [9:0] send_pattern;
+ reg [3:0] send_bitcnt;
+ reg [31:0] send_divcnt;
+ reg send_dummy;
+
+ assign reg_div_do = cfg_divider;
+
+ assign reg_dat_wait = reg_dat_we && (send_bitcnt || send_dummy);
+ assign reg_dat_do = recv_buf_valid ? recv_buf_data : ~0;
+
+ always @(posedge clk) begin
+ if (!resetn) begin
+ cfg_divider <= DEFAULT_DIV;
+ end else begin
+ if (reg_div_we[0]) cfg_divider[ 7: 0] <= reg_div_di[ 7: 0];
+ if (reg_div_we[1]) cfg_divider[15: 8] <= reg_div_di[15: 8];
+ if (reg_div_we[2]) cfg_divider[23:16] <= reg_div_di[23:16];
+ if (reg_div_we[3]) cfg_divider[31:24] <= reg_div_di[31:24];
+ end
+ end
+
+ always @(posedge clk) begin
+ if (!resetn) begin
+ recv_state <= 0;
+ recv_divcnt <= 0;
+ recv_pattern <= 0;
+ recv_buf_data <= 0;
+ recv_buf_valid <= 0;
+ end else begin
+ recv_divcnt <= recv_divcnt + 1;
+ if (reg_dat_re)
+ recv_buf_valid <= 0;
+ case (recv_state)
+ 0: begin
+ if (!ser_rx)
+ recv_state <= 1;
+ recv_divcnt <= 0;
+ end
+ 1: begin
+ if (2*recv_divcnt > cfg_divider) begin
+ recv_state <= 2;
+ recv_divcnt <= 0;
+ end
+ end
+ 10: begin
+ if (recv_divcnt > cfg_divider) begin
+ recv_buf_data <= recv_pattern;
+ recv_buf_valid <= 1;
+ recv_state <= 0;
+ end
+ end
+ default: begin
+ if (recv_divcnt > cfg_divider) begin
+ recv_pattern <= {ser_rx, recv_pattern[7:1]};
+ recv_state <= recv_state + 1;
+ recv_divcnt <= 0;
+ end
+ end
+ endcase
+ end
+ end
+
+ assign ser_tx = send_pattern[0];
+
+ always @(posedge clk) begin
+ if (reg_div_we)
+ send_dummy <= 1;
+ send_divcnt <= send_divcnt + 1;
+ if (!resetn) begin
+ send_pattern <= ~0;
+ send_bitcnt <= 0;
+ send_divcnt <= 0;
+ send_dummy <= 1;
+ end else begin
+ if (send_dummy && !send_bitcnt) begin
+ send_pattern <= ~0;
+ send_bitcnt <= 15;
+ send_divcnt <= 0;
+ send_dummy <= 0;
+ end else
+ if (reg_dat_we && !send_bitcnt) begin
+ send_pattern <= {1'b1, reg_dat_di[7:0], 1'b0};
+ send_bitcnt <= 10;
+ send_divcnt <= 0;
+ end else
+ if (send_divcnt > cfg_divider && send_bitcnt) begin
+ send_pattern <= {1'b1, send_pattern[9:1]};
+ send_bitcnt <= send_bitcnt - 1;
+ send_divcnt <= 0;
+ end
+ end
+ end
+endmodule
diff --git a/picosoc/spiflash.core b/picosoc/spiflash.core
new file mode 100644
index 0000000..1b7d153
--- /dev/null
+++ b/picosoc/spiflash.core
@@ -0,0 +1,24 @@
+CAPI=2:
+
+name : ::spiflash:0
+
+filesets:
+ model:
+ files : [spiflash.v]
+ file_type : verilogSource
+ tb:
+ files : [spiflash_tb.v]
+ file_type : verilogSource
+
+targets:
+ default:
+ default_tool : icarus
+ filesets : [model, "is_toplevel? (tb)"]
+ parameters : [firmware]
+ toplevel : [testbench]
+
+parameters :
+ firmware:
+ datatype : file
+ description : Initial SPI Flash contents (in verilog hex format)
+ paramtype : plusarg
diff --git a/picosoc/spiflash.v b/picosoc/spiflash.v
new file mode 100644
index 0000000..22b337b
--- /dev/null
+++ b/picosoc/spiflash.v
@@ -0,0 +1,409 @@
+/*
+ * PicoSoC - A simple example SoC using PicoRV32
+ *
+ * Copyright (C) 2017 Claire Xenia Wolf <claire@yosyshq.com>
+ *
+ * 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.
+ *
+ */
+
+`timescale 1 ns / 1 ps
+
+//
+// Simple SPI flash simulation model
+//
+// This model samples io input signals 1ns before the SPI clock edge and
+// updates output signals 1ns after the SPI clock edge.
+//
+// Supported commands:
+// AB, B9, FF, 03, BB, EB, ED
+//
+// Well written SPI flash data sheets:
+// Cypress S25FL064L http://www.cypress.com/file/316661/download
+// Cypress S25FL128L http://www.cypress.com/file/316171/download
+//
+// SPI flash used on iCEBreaker board:
+// https://www.winbond.com/resource-files/w25q128jv%20dtr%20revb%2011042016.pdf
+//
+
+module spiflash (
+ input csb,
+ input clk,
+ inout io0, // MOSI
+ inout io1, // MISO
+ inout io2,
+ inout io3
+);
+ localparam verbose = 0;
+ localparam integer latency = 8;
+
+ reg [7:0] buffer;
+ integer bitcount = 0;
+ integer bytecount = 0;
+ integer dummycount = 0;
+
+ reg [7:0] spi_cmd;
+ reg [7:0] xip_cmd = 0;
+ reg [23:0] spi_addr;
+
+ reg [7:0] spi_in;
+ reg [7:0] spi_out;
+ reg spi_io_vld;
+
+ reg powered_up = 0;
+
+ localparam [3:0] mode_spi = 1;
+ localparam [3:0] mode_dspi_rd = 2;
+ localparam [3:0] mode_dspi_wr = 3;
+ localparam [3:0] mode_qspi_rd = 4;
+ localparam [3:0] mode_qspi_wr = 5;
+ localparam [3:0] mode_qspi_ddr_rd = 6;
+ localparam [3:0] mode_qspi_ddr_wr = 7;
+
+ reg [3:0] mode = 0;
+ reg [3:0] next_mode = 0;
+
+ reg io0_oe = 0;
+ reg io1_oe = 0;
+ reg io2_oe = 0;
+ reg io3_oe = 0;
+
+ reg io0_dout = 0;
+ reg io1_dout = 0;
+ reg io2_dout = 0;
+ reg io3_dout = 0;
+
+ assign #1 io0 = io0_oe ? io0_dout : 1'bz;
+ assign #1 io1 = io1_oe ? io1_dout : 1'bz;
+ assign #1 io2 = io2_oe ? io2_dout : 1'bz;
+ assign #1 io3 = io3_oe ? io3_dout : 1'bz;
+
+ wire io0_delayed;
+ wire io1_delayed;
+ wire io2_delayed;
+ wire io3_delayed;
+
+ assign #1 io0_delayed = io0;
+ assign #1 io1_delayed = io1;
+ assign #1 io2_delayed = io2;
+ assign #1 io3_delayed = io3;
+
+ // 16 MB (128Mb) Flash
+ reg [7:0] memory [0:16*1024*1024-1];
+
+ reg [1023:0] firmware_file;
+ initial begin
+ if (!$value$plusargs("firmware=%s", firmware_file))
+ firmware_file = "firmware.hex";
+ $readmemh(firmware_file, memory);
+ end
+
+ task spi_action;
+ begin
+ spi_in = buffer;
+
+ if (bytecount == 1) begin
+ spi_cmd = buffer;
+
+ if (spi_cmd == 8'h ab)
+ powered_up = 1;
+
+ if (spi_cmd == 8'h b9)
+ powered_up = 0;
+
+ if (spi_cmd == 8'h ff)
+ xip_cmd = 0;
+ end
+
+ if (powered_up && spi_cmd == 'h 03) 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 (powered_up && spi_cmd == 'h bb) begin
+ if (bytecount == 1)
+ mode = mode_dspi_rd;
+
+ 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 == 5) begin
+ xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
+ mode = mode_dspi_wr;
+ dummycount = latency;
+ end
+
+ if (bytecount >= 5) begin
+ buffer = memory[spi_addr];
+ spi_addr = spi_addr + 1;
+ end
+ end
+
+ if (powered_up && spi_cmd == 'h eb) begin
+ if (bytecount == 1)
+ mode = mode_qspi_rd;
+
+ 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 == 5) begin
+ xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
+ mode = mode_qspi_wr;
+ dummycount = latency;
+ end
+
+ if (bytecount >= 5) begin
+ buffer = memory[spi_addr];
+ spi_addr = spi_addr + 1;
+ end
+ end
+
+ if (powered_up && spi_cmd == 'h ed) begin
+ if (bytecount == 1)
+ next_mode = mode_qspi_ddr_rd;
+
+ 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 == 5) begin
+ xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
+ mode = mode_qspi_ddr_wr;
+ dummycount = latency;
+ end
+
+ if (bytecount >= 5) begin
+ buffer = memory[spi_addr];
+ spi_addr = spi_addr + 1;
+ end
+ end
+
+ spi_out = buffer;
+ spi_io_vld = 1;
+
+ if (verbose) begin
+ if (bytecount == 1)
+ $write("<SPI-START>");
+ $write("<SPI:%02x:%02x>", spi_in, spi_out);
+ end
+
+ end
+ endtask
+
+ task ddr_rd_edge;
+ begin
+ buffer = {buffer, io3_delayed, io2_delayed, io1_delayed, io0_delayed};
+ bitcount = bitcount + 4;
+ if (bitcount == 8) begin
+ bitcount = 0;
+ bytecount = bytecount + 1;
+ spi_action;
+ end
+ end
+ endtask
+
+ task ddr_wr_edge;
+ begin
+ io0_oe = 1;
+ io1_oe = 1;
+ io2_oe = 1;
+ io3_oe = 1;
+
+ io0_dout = buffer[4];
+ io1_dout = buffer[5];
+ io2_dout = buffer[6];
+ io3_dout = buffer[7];
+
+ buffer = {buffer, 4'h 0};
+ bitcount = bitcount + 4;
+ if (bitcount == 8) begin
+ bitcount = 0;
+ bytecount = bytecount + 1;
+ spi_action;
+ end
+ end
+ endtask
+
+ always @(csb) begin
+ if (csb) begin
+ if (verbose) begin
+ $display("");
+ $fflush;
+ end
+ buffer = 0;
+ bitcount = 0;
+ bytecount = 0;
+ mode = mode_spi;
+ io0_oe = 0;
+ io1_oe = 0;
+ io2_oe = 0;
+ io3_oe = 0;
+ end else
+ if (xip_cmd) begin
+ buffer = xip_cmd;
+ bitcount = 0;
+ bytecount = 1;
+ spi_action;
+ end
+ end
+
+ always @(csb, clk) begin
+ spi_io_vld = 0;
+ if (!csb && !clk) begin
+ if (dummycount > 0) begin
+ io0_oe = 0;
+ io1_oe = 0;
+ io2_oe = 0;
+ io3_oe = 0;
+ end else
+ case (mode)
+ mode_spi: begin
+ io0_oe = 0;
+ io1_oe = 1;
+ io2_oe = 0;
+ io3_oe = 0;
+ io1_dout = buffer[7];
+ end
+ mode_dspi_rd: begin
+ io0_oe = 0;
+ io1_oe = 0;
+ io2_oe = 0;
+ io3_oe = 0;
+ end
+ mode_dspi_wr: begin
+ io0_oe = 1;
+ io1_oe = 1;
+ io2_oe = 0;
+ io3_oe = 0;
+ io0_dout = buffer[6];
+ io1_dout = buffer[7];
+ end
+ mode_qspi_rd: begin
+ io0_oe = 0;
+ io1_oe = 0;
+ io2_oe = 0;
+ io3_oe = 0;
+ end
+ mode_qspi_wr: begin
+ io0_oe = 1;
+ io1_oe = 1;
+ io2_oe = 1;
+ io3_oe = 1;
+ io0_dout = buffer[4];
+ io1_dout = buffer[5];
+ io2_dout = buffer[6];
+ io3_dout = buffer[7];
+ end
+ mode_qspi_ddr_rd: begin
+ ddr_rd_edge;
+ end
+ mode_qspi_ddr_wr: begin
+ ddr_wr_edge;
+ end
+ endcase
+ if (next_mode) begin
+ case (next_mode)
+ mode_qspi_ddr_rd: begin
+ io0_oe = 0;
+ io1_oe = 0;
+ io2_oe = 0;
+ io3_oe = 0;
+ end
+ mode_qspi_ddr_wr: begin
+ io0_oe = 1;
+ io1_oe = 1;
+ io2_oe = 1;
+ io3_oe = 1;
+ io0_dout = buffer[4];
+ io1_dout = buffer[5];
+ io2_dout = buffer[6];
+ io3_dout = buffer[7];
+ end
+ endcase
+ mode = next_mode;
+ next_mode = 0;
+ end
+ end
+ end
+
+ always @(posedge clk) begin
+ if (!csb) begin
+ if (dummycount > 0) begin
+ dummycount = dummycount - 1;
+ end else
+ case (mode)
+ mode_spi: begin
+ buffer = {buffer, io0};
+ bitcount = bitcount + 1;
+ if (bitcount == 8) begin
+ bitcount = 0;
+ bytecount = bytecount + 1;
+ spi_action;
+ end
+ end
+ mode_dspi_rd, mode_dspi_wr: begin
+ buffer = {buffer, io1, io0};
+ bitcount = bitcount + 2;
+ if (bitcount == 8) begin
+ bitcount = 0;
+ bytecount = bytecount + 1;
+ spi_action;
+ end
+ end
+ mode_qspi_rd, mode_qspi_wr: begin
+ buffer = {buffer, io3, io2, io1, io0};
+ bitcount = bitcount + 4;
+ if (bitcount == 8) begin
+ bitcount = 0;
+ bytecount = bytecount + 1;
+ spi_action;
+ end
+ end
+ mode_qspi_ddr_rd: begin
+ ddr_rd_edge;
+ end
+ mode_qspi_ddr_wr: begin
+ ddr_wr_edge;
+ end
+ endcase
+ end
+ end
+endmodule
diff --git a/picosoc/spiflash_tb.v b/picosoc/spiflash_tb.v
new file mode 100644
index 0000000..a5b5edc
--- /dev/null
+++ b/picosoc/spiflash_tb.v
@@ -0,0 +1,366 @@
+/*
+ * PicoSoC - A simple example SoC using PicoRV32
+ *
+ * Copyright (C) 2017 Claire Xenia Wolf <claire@yosyshq.com>
+ *
+ * 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.
+ *
+ */
+
+`timescale 1 ns / 1 ps
+
+module testbench;
+ reg flash_csb = 1;
+ reg flash_clk = 0;
+
+ wire flash_io0;
+ wire flash_io1;
+ wire flash_io2;
+ wire flash_io3;
+
+ reg flash_io0_oe = 0;
+ reg flash_io1_oe = 0;
+ reg flash_io2_oe = 0;
+ reg flash_io3_oe = 0;
+
+ reg flash_io0_dout = 0;
+ reg flash_io1_dout = 0;
+ reg flash_io2_dout = 0;
+ reg flash_io3_dout = 0;
+
+ assign flash_io0 = flash_io0_oe ? flash_io0_dout : 1'bz;
+ assign flash_io1 = flash_io1_oe ? flash_io1_dout : 1'bz;
+ assign flash_io2 = flash_io2_oe ? flash_io2_dout : 1'bz;
+ assign flash_io3 = flash_io3_oe ? flash_io3_dout : 1'bz;
+
+ spiflash uut (
+ .csb(flash_csb),
+ .clk(flash_clk),
+ .io0(flash_io0),
+ .io1(flash_io1),
+ .io2(flash_io2),
+ .io3(flash_io3)
+ );
+
+ localparam [23:0] offset = 24'h100000;
+ localparam [31:0] word0 = 32'h 00000093;
+ localparam [31:0] word1 = 32'h 00000193;
+
+ reg [7:0] rdata;
+ integer errcount = 0;
+
+ task expect;
+ input [7:0] data;
+ begin
+ if (data !== rdata) begin
+ $display("ERROR: Got %x (%b) but expected %x (%b).", rdata, rdata, data, data);
+ errcount = errcount + 1;
+ end
+ end
+ endtask
+
+ task xfer_begin;
+ begin
+ #5;
+ flash_csb = 0;
+ $display("-- BEGIN");
+ #5;
+ end
+ endtask
+
+ task xfer_dummy;
+ begin
+ flash_io0_oe = 0;
+ flash_io1_oe = 0;
+ flash_io2_oe = 0;
+ flash_io3_oe = 0;
+
+ #5;
+ flash_clk = 1;
+ #5;
+ flash_clk = 0;
+ #5;
+ end
+ endtask
+
+ task xfer_end;
+ begin
+ #5;
+ flash_csb = 1;
+ flash_io0_oe = 0;
+ flash_io1_oe = 0;
+ flash_io2_oe = 0;
+ flash_io3_oe = 0;
+ $display("-- END");
+ $display("");
+ #5;
+ end
+ endtask
+
+ task xfer_spi;
+ input [7:0] data;
+ integer i;
+ begin
+ flash_io0_oe = 1;
+ flash_io1_oe = 0;
+ flash_io2_oe = 0;
+ flash_io3_oe = 0;
+
+ for (i = 0; i < 8; i=i+1) begin
+ flash_io0_dout = data[7-i];
+ #5;
+ flash_clk = 1;
+ rdata[7-i] = flash_io1;
+ #5;
+ flash_clk = 0;
+ end
+
+ $display("-- SPI SDR %02x %02x", data, rdata);
+ #5;
+ end
+ endtask
+
+ task xfer_qspi_wr;
+ input [7:0] data;
+ integer i;
+ begin
+ flash_io0_oe = 1;
+ flash_io1_oe = 1;
+ flash_io2_oe = 1;
+ flash_io3_oe = 1;
+
+ flash_io0_dout = data[4];
+ flash_io1_dout = data[5];
+ flash_io2_dout = data[6];
+ flash_io3_dout = data[7];
+
+ #5;
+ flash_clk = 1;
+
+ #5;
+ flash_clk = 0;
+ flash_io0_dout = data[0];
+ flash_io1_dout = data[1];
+ flash_io2_dout = data[2];
+ flash_io3_dout = data[3];
+
+ #5;
+ flash_clk = 1;
+ #5;
+ flash_clk = 0;
+
+ $display("-- QSPI SDR %02x --", data);
+ #5;
+ end
+ endtask
+
+ task xfer_qspi_rd;
+ integer i;
+ begin
+ flash_io0_oe = 0;
+ flash_io1_oe = 0;
+ flash_io2_oe = 0;
+ flash_io3_oe = 0;
+
+ #5;
+ flash_clk = 1;
+ rdata[4] = flash_io0;
+ rdata[5] = flash_io1;
+ rdata[6] = flash_io2;
+ rdata[7] = flash_io3;
+
+ #5;
+ flash_clk = 0;
+
+ #5;
+ flash_clk = 1;
+ rdata[0] = flash_io0;
+ rdata[1] = flash_io1;
+ rdata[2] = flash_io2;
+ rdata[3] = flash_io3;
+
+ #5;
+ flash_clk = 0;
+
+ $display("-- QSPI SDR -- %02x", rdata);
+ #5;
+ end
+ endtask
+
+ task xfer_qspi_ddr_wr;
+ input [7:0] data;
+ integer i;
+ begin
+ flash_io0_oe = 1;
+ flash_io1_oe = 1;
+ flash_io2_oe = 1;
+ flash_io3_oe = 1;
+
+ flash_io0_dout = data[4];
+ flash_io1_dout = data[5];
+ flash_io2_dout = data[6];
+ flash_io3_dout = data[7];
+
+ #5;
+ flash_clk = 1;
+ flash_io0_dout = data[0];
+ flash_io1_dout = data[1];
+ flash_io2_dout = data[2];
+ flash_io3_dout = data[3];
+
+ #5;
+ flash_clk = 0;
+
+ $display("-- QSPI DDR %02x --", data);
+ #5;
+ end
+ endtask
+
+ task xfer_qspi_ddr_rd;
+ integer i;
+ begin
+ flash_io0_oe = 0;
+ flash_io1_oe = 0;
+ flash_io2_oe = 0;
+ flash_io3_oe = 0;
+
+ #5;
+ flash_clk = 1;
+ rdata[4] = flash_io0;
+ rdata[5] = flash_io1;
+ rdata[6] = flash_io2;
+ rdata[7] = flash_io3;
+
+ #5;
+ flash_clk = 0;
+ rdata[0] = flash_io0;
+ rdata[1] = flash_io1;
+ rdata[2] = flash_io2;
+ rdata[3] = flash_io3;
+
+ $display("-- QSPI DDR -- %02x", rdata);
+ #5;
+ end
+ endtask
+
+ initial begin
+ $dumpfile("spiflash_tb.vcd");
+ $dumpvars(0, testbench);
+ $display("");
+
+ $display("Reset (FFh)");
+ xfer_begin;
+ xfer_spi(8'h ff);
+ xfer_end;
+
+ $display("Power Up (ABh)");
+ xfer_begin;
+ xfer_spi(8'h ab);
+ xfer_end;
+
+ $display("Read Data (03h)");
+ xfer_begin;
+ xfer_spi(8'h 03);
+ xfer_spi(offset[23:16]);
+ xfer_spi(offset[15:8]);
+ xfer_spi(offset[7:0]);
+ xfer_spi(8'h 00); expect(word0[7:0]);
+ xfer_spi(8'h 00); expect(word0[15:8]);
+ xfer_spi(8'h 00); expect(word0[23:16]);
+ xfer_spi(8'h 00); expect(word0[31:24]);
+ xfer_spi(8'h 00); expect(word1[7:0]);
+ xfer_spi(8'h 00); expect(word1[15:8]);
+ xfer_spi(8'h 00); expect(word1[23:16]);
+ xfer_spi(8'h 00); expect(word1[31:24]);
+ xfer_end;
+
+ $display("Quad I/O Read (EBh)");
+ xfer_begin;
+ xfer_spi(8'h eb);
+ xfer_qspi_wr(offset[23:16]);
+ xfer_qspi_wr(offset[15:8]);
+ xfer_qspi_wr(offset[7:0]);
+ xfer_qspi_wr(8'h a5);
+ repeat (8) xfer_dummy;
+ xfer_qspi_rd; expect(word0[7:0]);
+ xfer_qspi_rd; expect(word0[15:8]);
+ xfer_qspi_rd; expect(word0[23:16]);
+ xfer_qspi_rd; expect(word0[31:24]);
+ xfer_qspi_rd; expect(word1[7:0]);
+ xfer_qspi_rd; expect(word1[15:8]);
+ xfer_qspi_rd; expect(word1[23:16]);
+ xfer_qspi_rd; expect(word1[31:24]);
+ xfer_end;
+
+ $display("Continous Quad I/O Read");
+ xfer_begin;
+ xfer_qspi_wr(offset[23:16]);
+ xfer_qspi_wr(offset[15:8]);
+ xfer_qspi_wr(offset[7:0]);
+ xfer_qspi_wr(8'h ff);
+ repeat (8) xfer_dummy;
+ xfer_qspi_rd; expect(word0[7:0]);
+ xfer_qspi_rd; expect(word0[15:8]);
+ xfer_qspi_rd; expect(word0[23:16]);
+ xfer_qspi_rd; expect(word0[31:24]);
+ xfer_qspi_rd; expect(word1[7:0]);
+ xfer_qspi_rd; expect(word1[15:8]);
+ xfer_qspi_rd; expect(word1[23:16]);
+ xfer_qspi_rd; expect(word1[31:24]);
+ xfer_end;
+
+ $display("DDR Quad I/O Read (EDh)");
+ xfer_begin;
+ xfer_spi(8'h ed);
+ xfer_qspi_ddr_wr(offset[23:16]);
+ xfer_qspi_ddr_wr(offset[15:8]);
+ xfer_qspi_ddr_wr(offset[7:0]);
+ xfer_qspi_ddr_wr(8'h a5);
+ repeat (8) xfer_dummy;
+ xfer_qspi_ddr_rd; expect(word0[7:0]);
+ xfer_qspi_ddr_rd; expect(word0[15:8]);
+ xfer_qspi_ddr_rd; expect(word0[23:16]);
+ xfer_qspi_ddr_rd; expect(word0[31:24]);
+ xfer_qspi_ddr_rd; expect(word1[7:0]);
+ xfer_qspi_ddr_rd; expect(word1[15:8]);
+ xfer_qspi_ddr_rd; expect(word1[23:16]);
+ xfer_qspi_ddr_rd; expect(word1[31:24]);
+ xfer_end;
+
+ $display("Continous DDR Quad I/O Read");
+ xfer_begin;
+ xfer_qspi_ddr_wr(offset[23:16]);
+ xfer_qspi_ddr_wr(offset[15:8]);
+ xfer_qspi_ddr_wr(offset[7:0]);
+ xfer_qspi_ddr_wr(8'h ff);
+ repeat (8) xfer_dummy;
+ xfer_qspi_ddr_rd; expect(word0[7:0]);
+ xfer_qspi_ddr_rd; expect(word0[15:8]);
+ xfer_qspi_ddr_rd; expect(word0[23:16]);
+ xfer_qspi_ddr_rd; expect(word0[31:24]);
+ xfer_qspi_ddr_rd; expect(word1[7:0]);
+ xfer_qspi_ddr_rd; expect(word1[15:8]);
+ xfer_qspi_ddr_rd; expect(word1[23:16]);
+ xfer_qspi_ddr_rd; expect(word1[31:24]);
+ xfer_end;
+
+ #5;
+
+ if (errcount) begin
+ $display("FAIL");
+ $stop;
+ end else begin
+ $display("PASS");
+ end
+ end
+endmodule
diff --git a/picosoc/spimemio.v b/picosoc/spimemio.v
new file mode 100644
index 0000000..b4ee446
--- /dev/null
+++ b/picosoc/spimemio.v
@@ -0,0 +1,579 @@
+/*
+ * PicoSoC - A simple example SoC using PicoRV32
+ *
+ * Copyright (C) 2017 Claire Xenia Wolf <claire@yosyshq.com>
+ *
+ * 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 spimemio (
+ input clk, resetn,
+
+ input valid,
+ output ready,
+ input [23:0] addr,
+ output reg [31:0] rdata,
+
+ output flash_csb,
+ output flash_clk,
+
+ 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,
+
+ input [3:0] cfgreg_we,
+ input [31:0] cfgreg_di,
+ output [31:0] cfgreg_do
+);
+ reg xfer_resetn;
+ reg din_valid;
+ wire din_ready;
+ reg [7:0] din_data;
+ reg [3:0] din_tag;
+ reg din_cont;
+ reg din_qspi;
+ reg din_ddr;
+ reg din_rd;
+
+ wire dout_valid;
+ wire [7:0] dout_data;
+ wire [3:0] dout_tag;
+
+ reg [23:0] buffer;
+
+ reg [23:0] rd_addr;
+ reg rd_valid;
+ reg rd_wait;
+ reg rd_inc;
+
+ assign ready = valid && (addr == rd_addr) && rd_valid;
+ wire jump = valid && !ready && (addr != rd_addr+4) && rd_valid;
+
+ reg softreset;
+
+ reg config_en; // cfgreg[31]
+ reg config_ddr; // cfgreg[22]
+ reg config_qspi; // cfgreg[21]
+ reg config_cont; // cfgreg[20]
+ reg [3:0] config_dummy; // cfgreg[19:16]
+ reg [3:0] config_oe; // cfgreg[11:8]
+ reg config_csb; // cfgreg[5]
+ reg config_clk; // cfgref[4]
+ reg [3:0] config_do; // cfgreg[3:0]
+
+ assign cfgreg_do[31] = config_en;
+ assign cfgreg_do[30:23] = 0;
+ assign cfgreg_do[22] = config_ddr;
+ assign cfgreg_do[21] = config_qspi;
+ assign cfgreg_do[20] = config_cont;
+ assign cfgreg_do[19:16] = config_dummy;
+ assign cfgreg_do[15:12] = 0;
+ assign cfgreg_do[11:8] = {flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe};
+ assign cfgreg_do[7:6] = 0;
+ assign cfgreg_do[5] = flash_csb;
+ assign cfgreg_do[4] = flash_clk;
+ assign cfgreg_do[3:0] = {flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di};
+
+ always @(posedge clk) begin
+ softreset <= !config_en || cfgreg_we;
+ if (!resetn) begin
+ softreset <= 1;
+ config_en <= 1;
+ config_csb <= 0;
+ config_clk <= 0;
+ config_oe <= 0;
+ config_do <= 0;
+ config_ddr <= 0;
+ config_qspi <= 0;
+ config_cont <= 0;
+ config_dummy <= 8;
+ end else begin
+ if (cfgreg_we[0]) begin
+ config_csb <= cfgreg_di[5];
+ config_clk <= cfgreg_di[4];
+ config_do <= cfgreg_di[3:0];
+ end
+ if (cfgreg_we[1]) begin
+ config_oe <= cfgreg_di[11:8];
+ end
+ if (cfgreg_we[2]) begin
+ config_ddr <= cfgreg_di[22];
+ config_qspi <= cfgreg_di[21];
+ config_cont <= cfgreg_di[20];
+ config_dummy <= cfgreg_di[19:16];
+ end
+ if (cfgreg_we[3]) begin
+ config_en <= cfgreg_di[31];
+ end
+ end
+ end
+
+ wire xfer_csb;
+ wire xfer_clk;
+
+ wire xfer_io0_oe;
+ wire xfer_io1_oe;
+ wire xfer_io2_oe;
+ wire xfer_io3_oe;
+
+ wire xfer_io0_do;
+ wire xfer_io1_do;
+ wire xfer_io2_do;
+ wire xfer_io3_do;
+
+ reg xfer_io0_90;
+ reg xfer_io1_90;
+ reg xfer_io2_90;
+ reg xfer_io3_90;
+
+ always @(negedge clk) begin
+ xfer_io0_90 <= xfer_io0_do;
+ xfer_io1_90 <= xfer_io1_do;
+ xfer_io2_90 <= xfer_io2_do;
+ xfer_io3_90 <= xfer_io3_do;
+ end
+
+ assign flash_csb = config_en ? xfer_csb : config_csb;
+ assign flash_clk = config_en ? xfer_clk : config_clk;
+
+ assign flash_io0_oe = config_en ? xfer_io0_oe : config_oe[0];
+ assign flash_io1_oe = config_en ? xfer_io1_oe : config_oe[1];
+ assign flash_io2_oe = config_en ? xfer_io2_oe : config_oe[2];
+ assign flash_io3_oe = config_en ? xfer_io3_oe : config_oe[3];
+
+ assign flash_io0_do = config_en ? (config_ddr ? xfer_io0_90 : xfer_io0_do) : config_do[0];
+ assign flash_io1_do = config_en ? (config_ddr ? xfer_io1_90 : xfer_io1_do) : config_do[1];
+ assign flash_io2_do = config_en ? (config_ddr ? xfer_io2_90 : xfer_io2_do) : config_do[2];
+ assign flash_io3_do = config_en ? (config_ddr ? xfer_io3_90 : xfer_io3_do) : config_do[3];
+
+ wire xfer_dspi = din_ddr && !din_qspi;
+ wire xfer_ddr = din_ddr && din_qspi;
+
+ spimemio_xfer xfer (
+ .clk (clk ),
+ .resetn (xfer_resetn ),
+ .din_valid (din_valid ),
+ .din_ready (din_ready ),
+ .din_data (din_data ),
+ .din_tag (din_tag ),
+ .din_cont (din_cont ),
+ .din_dspi (xfer_dspi ),
+ .din_qspi (din_qspi ),
+ .din_ddr (xfer_ddr ),
+ .din_rd (din_rd ),
+ .dout_valid (dout_valid ),
+ .dout_data (dout_data ),
+ .dout_tag (dout_tag ),
+ .flash_csb (xfer_csb ),
+ .flash_clk (xfer_clk ),
+ .flash_io0_oe (xfer_io0_oe ),
+ .flash_io1_oe (xfer_io1_oe ),
+ .flash_io2_oe (xfer_io2_oe ),
+ .flash_io3_oe (xfer_io3_oe ),
+ .flash_io0_do (xfer_io0_do ),
+ .flash_io1_do (xfer_io1_do ),
+ .flash_io2_do (xfer_io2_do ),
+ .flash_io3_do (xfer_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)
+ );
+
+ reg [3:0] state;
+
+ always @(posedge clk) begin
+ xfer_resetn <= 1;
+ din_valid <= 0;
+
+ if (!resetn || softreset) begin
+ state <= 0;
+ xfer_resetn <= 0;
+ rd_valid <= 0;
+ din_tag <= 0;
+ din_cont <= 0;
+ din_qspi <= 0;
+ din_ddr <= 0;
+ din_rd <= 0;
+ end else begin
+ if (dout_valid && dout_tag == 1) buffer[ 7: 0] <= dout_data;
+ if (dout_valid && dout_tag == 2) buffer[15: 8] <= dout_data;
+ if (dout_valid && dout_tag == 3) buffer[23:16] <= dout_data;
+ if (dout_valid && dout_tag == 4) begin
+ rdata <= {dout_data, buffer};
+ rd_addr <= rd_inc ? rd_addr + 4 : addr;
+ rd_valid <= 1;
+ rd_wait <= rd_inc;
+ rd_inc <= 1;
+ end
+
+ if (valid)
+ rd_wait <= 0;
+
+ case (state)
+ 0: begin
+ din_valid <= 1;
+ din_data <= 8'h ff;
+ din_tag <= 0;
+ if (din_ready) begin
+ din_valid <= 0;
+ state <= 1;
+ end
+ end
+ 1: begin
+ if (dout_valid) begin
+ xfer_resetn <= 0;
+ state <= 2;
+ end
+ end
+ 2: begin
+ din_valid <= 1;
+ din_data <= 8'h ab;
+ din_tag <= 0;
+ if (din_ready) begin
+ din_valid <= 0;
+ state <= 3;
+ end
+ end
+ 3: begin
+ if (dout_valid) begin
+ xfer_resetn <= 0;
+ state <= 4;
+ end
+ end
+ 4: begin
+ rd_inc <= 0;
+ din_valid <= 1;
+ din_tag <= 0;
+ case ({config_ddr, config_qspi})
+ 2'b11: din_data <= 8'h ED;
+ 2'b01: din_data <= 8'h EB;
+ 2'b10: din_data <= 8'h BB;
+ 2'b00: din_data <= 8'h 03;
+ endcase
+ if (din_ready) begin
+ din_valid <= 0;
+ state <= 5;
+ end
+ end
+ 5: begin
+ if (valid && !ready) begin
+ din_valid <= 1;
+ din_tag <= 0;
+ din_data <= addr[23:16];
+ din_qspi <= config_qspi;
+ din_ddr <= config_ddr;
+ if (din_ready) begin
+ din_valid <= 0;
+ state <= 6;
+ end
+ end
+ end
+ 6: begin
+ din_valid <= 1;
+ din_tag <= 0;
+ din_data <= addr[15:8];
+ if (din_ready) begin
+ din_valid <= 0;
+ state <= 7;
+ end
+ end
+ 7: begin
+ din_valid <= 1;
+ din_tag <= 0;
+ din_data <= addr[7:0];
+ if (din_ready) begin
+ din_valid <= 0;
+ din_data <= 0;
+ state <= config_qspi || config_ddr ? 8 : 9;
+ end
+ end
+ 8: begin
+ din_valid <= 1;
+ din_tag <= 0;
+ din_data <= config_cont ? 8'h A5 : 8'h FF;
+ if (din_ready) begin
+ din_rd <= 1;
+ din_data <= config_dummy;
+ din_valid <= 0;
+ state <= 9;
+ end
+ end
+ 9: begin
+ din_valid <= 1;
+ din_tag <= 1;
+ if (din_ready) begin
+ din_valid <= 0;
+ state <= 10;
+ end
+ end
+ 10: begin
+ din_valid <= 1;
+ din_data <= 8'h 00;
+ din_tag <= 2;
+ if (din_ready) begin
+ din_valid <= 0;
+ state <= 11;
+ end
+ end
+ 11: begin
+ din_valid <= 1;
+ din_tag <= 3;
+ if (din_ready) begin
+ din_valid <= 0;
+ state <= 12;
+ end
+ end
+ 12: begin
+ if (!rd_wait || valid) begin
+ din_valid <= 1;
+ din_tag <= 4;
+ if (din_ready) begin
+ din_valid <= 0;
+ state <= 9;
+ end
+ end
+ end
+ endcase
+
+ if (jump) begin
+ rd_inc <= 0;
+ rd_valid <= 0;
+ xfer_resetn <= 0;
+ if (config_cont) begin
+ state <= 5;
+ end else begin
+ state <= 4;
+ din_qspi <= 0;
+ din_ddr <= 0;
+ end
+ din_rd <= 0;
+ end
+ end
+ end
+endmodule
+
+module spimemio_xfer (
+ input clk, resetn,
+
+ input din_valid,
+ output din_ready,
+ input [7:0] din_data,
+ input [3:0] din_tag,
+ input din_cont,
+ input din_dspi,
+ input din_qspi,
+ input din_ddr,
+ input din_rd,
+
+ output dout_valid,
+ output [7:0] dout_data,
+ output [3:0] dout_tag,
+
+ output reg flash_csb,
+ output reg flash_clk,
+
+ output reg flash_io0_oe,
+ output reg flash_io1_oe,
+ output reg flash_io2_oe,
+ output reg flash_io3_oe,
+
+ output reg flash_io0_do,
+ output reg flash_io1_do,
+ output reg flash_io2_do,
+ output reg flash_io3_do,
+
+ input flash_io0_di,
+ input flash_io1_di,
+ input flash_io2_di,
+ input flash_io3_di
+);
+ reg [7:0] obuffer;
+ reg [7:0] ibuffer;
+
+ reg [3:0] count;
+ reg [3:0] dummy_count;
+
+ reg xfer_cont;
+ reg xfer_dspi;
+ reg xfer_qspi;
+ reg xfer_ddr;
+ reg xfer_ddr_q;
+ reg xfer_rd;
+ reg [3:0] xfer_tag;
+ reg [3:0] xfer_tag_q;
+
+ reg [7:0] next_obuffer;
+ reg [7:0] next_ibuffer;
+ reg [3:0] next_count;
+
+ reg fetch;
+ reg next_fetch;
+ reg last_fetch;
+
+ always @(posedge clk) begin
+ xfer_ddr_q <= xfer_ddr;
+ xfer_tag_q <= xfer_tag;
+ end
+
+ assign din_ready = din_valid && resetn && next_fetch;
+
+ assign dout_valid = (xfer_ddr_q ? fetch && !last_fetch : next_fetch && !fetch) && resetn;
+ assign dout_data = ibuffer;
+ assign dout_tag = xfer_tag_q;
+
+ always @* begin
+ flash_io0_oe = 0;
+ flash_io1_oe = 0;
+ flash_io2_oe = 0;
+ flash_io3_oe = 0;
+
+ flash_io0_do = 0;
+ flash_io1_do = 0;
+ flash_io2_do = 0;
+ flash_io3_do = 0;
+
+ next_obuffer = obuffer;
+ next_ibuffer = ibuffer;
+ next_count = count;
+ next_fetch = 0;
+
+ if (dummy_count == 0) begin
+ casez ({xfer_ddr, xfer_qspi, xfer_dspi})
+ 3'b 000: begin
+ flash_io0_oe = 1;
+ flash_io0_do = obuffer[7];
+
+ if (flash_clk) begin
+ next_obuffer = {obuffer[6:0], 1'b 0};
+ next_count = count - |count;
+ end else begin
+ next_ibuffer = {ibuffer[6:0], flash_io1_di};
+ end
+
+ next_fetch = (next_count == 0);
+ end
+ 3'b 01?: begin
+ flash_io0_oe = !xfer_rd;
+ flash_io1_oe = !xfer_rd;
+ flash_io2_oe = !xfer_rd;
+ flash_io3_oe = !xfer_rd;
+
+ flash_io0_do = obuffer[4];
+ flash_io1_do = obuffer[5];
+ flash_io2_do = obuffer[6];
+ flash_io3_do = obuffer[7];
+
+ if (flash_clk) begin
+ next_obuffer = {obuffer[3:0], 4'b 0000};
+ next_count = count - {|count, 2'b00};
+ end else begin
+ next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di};
+ end
+
+ next_fetch = (next_count == 0);
+ end
+ 3'b 11?: begin
+ flash_io0_oe = !xfer_rd;
+ flash_io1_oe = !xfer_rd;
+ flash_io2_oe = !xfer_rd;
+ flash_io3_oe = !xfer_rd;
+
+ flash_io0_do = obuffer[4];
+ flash_io1_do = obuffer[5];
+ flash_io2_do = obuffer[6];
+ flash_io3_do = obuffer[7];
+
+ next_obuffer = {obuffer[3:0], 4'b 0000};
+ next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di};
+ next_count = count - {|count, 2'b00};
+
+ next_fetch = (next_count == 0);
+ end
+ 3'b ??1: begin
+ flash_io0_oe = !xfer_rd;
+ flash_io1_oe = !xfer_rd;
+
+ flash_io0_do = obuffer[6];
+ flash_io1_do = obuffer[7];
+
+ if (flash_clk) begin
+ next_obuffer = {obuffer[5:0], 2'b 00};
+ next_count = count - {|count, 1'b0};
+ end else begin
+ next_ibuffer = {ibuffer[5:0], flash_io1_di, flash_io0_di};
+ end
+
+ next_fetch = (next_count == 0);
+ end
+ endcase
+ end
+ end
+
+ always @(posedge clk) begin
+ if (!resetn) begin
+ fetch <= 1;
+ last_fetch <= 1;
+ flash_csb <= 1;
+ flash_clk <= 0;
+ count <= 0;
+ dummy_count <= 0;
+ xfer_tag <= 0;
+ xfer_cont <= 0;
+ xfer_dspi <= 0;
+ xfer_qspi <= 0;
+ xfer_ddr <= 0;
+ xfer_rd <= 0;
+ end else begin
+ fetch <= next_fetch;
+ last_fetch <= xfer_ddr ? fetch : 1;
+ if (dummy_count) begin
+ flash_clk <= !flash_clk && !flash_csb;
+ dummy_count <= dummy_count - flash_clk;
+ end else
+ if (count) begin
+ flash_clk <= !flash_clk && !flash_csb;
+ obuffer <= next_obuffer;
+ ibuffer <= next_ibuffer;
+ count <= next_count;
+ end
+ if (din_valid && din_ready) begin
+ flash_csb <= 0;
+ flash_clk <= 0;
+
+ count <= 8;
+ dummy_count <= din_rd ? din_data : 0;
+ obuffer <= din_data;
+
+ xfer_tag <= din_tag;
+ xfer_cont <= din_cont;
+ xfer_dspi <= din_dspi;
+ xfer_qspi <= din_qspi;
+ xfer_ddr <= din_ddr;
+ xfer_rd <= din_rd;
+ end
+ end
+ end
+endmodule
diff --git a/picosoc/start.s b/picosoc/start.s
new file mode 100644
index 0000000..e9e18db
--- /dev/null
+++ b/picosoc/start.s
@@ -0,0 +1,159 @@
+.section .text
+
+start:
+
+# zero-initialize register file
+addi x1, zero, 0
+# x2 (sp) is initialized by reset
+addi x3, zero, 0
+addi x4, zero, 0
+addi x5, zero, 0
+addi x6, zero, 0
+addi x7, zero, 0
+addi x8, zero, 0
+addi x9, zero, 0
+addi x10, zero, 0
+addi x11, zero, 0
+addi x12, zero, 0
+addi x13, zero, 0
+addi x14, zero, 0
+addi x15, zero, 0
+addi x16, zero, 0
+addi x17, zero, 0
+addi x18, zero, 0
+addi x19, zero, 0
+addi x20, zero, 0
+addi x21, zero, 0
+addi x22, zero, 0
+addi x23, zero, 0
+addi x24, zero, 0
+addi x25, zero, 0
+addi x26, zero, 0
+addi x27, zero, 0
+addi x28, zero, 0
+addi x29, zero, 0
+addi x30, zero, 0
+addi x31, zero, 0
+
+# Update LEDs
+li a0, 0x03000000
+li a1, 1
+sw a1, 0(a0)
+
+# zero initialize entire scratchpad memory
+li a0, 0x00000000
+setmemloop:
+sw a0, 0(a0)
+addi a0, a0, 4
+blt a0, sp, setmemloop
+
+# Update LEDs
+li a0, 0x03000000
+li a1, 3
+sw a1, 0(a0)
+
+# copy data section
+la a0, _sidata
+la a1, _sdata
+la a2, _edata
+bge a1, a2, end_init_data
+loop_init_data:
+lw a3, 0(a0)
+sw a3, 0(a1)
+addi a0, a0, 4
+addi a1, a1, 4
+blt a1, a2, loop_init_data
+end_init_data:
+
+# Update LEDs
+li a0, 0x03000000
+li a1, 7
+sw a1, 0(a0)
+
+# zero-init bss section
+la a0, _sbss
+la a1, _ebss
+bge a0, a1, end_init_bss
+loop_init_bss:
+sw zero, 0(a0)
+addi a0, a0, 4
+blt a0, a1, loop_init_bss
+end_init_bss:
+
+# Update LEDs
+li a0, 0x03000000
+li a1, 15
+sw a1, 0(a0)
+
+# call main
+call main
+loop:
+j loop
+
+.global flashio_worker_begin
+.global flashio_worker_end
+
+.balign 4
+
+flashio_worker_begin:
+# a0 ... data pointer
+# a1 ... data length
+# a2 ... optional WREN cmd (0 = disable)
+
+# address of SPI ctrl reg
+li t0, 0x02000000
+
+# Set CS high, IO0 is output
+li t1, 0x120
+sh t1, 0(t0)
+
+# Enable Manual SPI Ctrl
+sb zero, 3(t0)
+
+# Send optional WREN cmd
+beqz a2, flashio_worker_L1
+li t5, 8
+andi t2, a2, 0xff
+flashio_worker_L4:
+srli t4, t2, 7
+sb t4, 0(t0)
+ori t4, t4, 0x10
+sb t4, 0(t0)
+slli t2, t2, 1
+andi t2, t2, 0xff
+addi t5, t5, -1
+bnez t5, flashio_worker_L4
+sb t1, 0(t0)
+
+# SPI transfer
+flashio_worker_L1:
+beqz a1, flashio_worker_L3
+li t5, 8
+lbu t2, 0(a0)
+flashio_worker_L2:
+srli t4, t2, 7
+sb t4, 0(t0)
+ori t4, t4, 0x10
+sb t4, 0(t0)
+lbu t4, 0(t0)
+andi t4, t4, 2
+srli t4, t4, 1
+slli t2, t2, 1
+or t2, t2, t4
+andi t2, t2, 0xff
+addi t5, t5, -1
+bnez t5, flashio_worker_L2
+sb t2, 0(a0)
+addi a0, a0, 1
+addi a1, a1, -1
+j flashio_worker_L1
+flashio_worker_L3:
+
+# Back to MEMIO mode
+li t1, 0x80
+sb t1, 3(t0)
+
+ret
+
+.balign 4
+flashio_worker_end: