Adding softshell RTL + wrapper RTL.

This is taken from 4e60cd8416751ad0bf38814006a930c58a6f0468 on branch
3cpu-512w-nobuff-wrapped.
diff --git a/verilog/rtl/softshell/dv/.gitignore b/verilog/rtl/softshell/dv/.gitignore
new file mode 100644
index 0000000..3f87749
--- /dev/null
+++ b/verilog/rtl/softshell/dv/.gitignore
@@ -0,0 +1,3 @@
+*.hex
+*.vcd
+*.fst
diff --git a/verilog/rtl/softshell/dv/Makefile b/verilog/rtl/softshell/dv/Makefile
new file mode 100644
index 0000000..df45f15
--- /dev/null
+++ b/verilog/rtl/softshell/dv/Makefile
@@ -0,0 +1,40 @@
+.SUFFIXES:
+
+PATTERN = softshell_top
+
+FIRMWARE_PATH = .
+
+GCC_PATH ?= /opt/riscv32ic/bin
+GCC_PREFIX ?= riscv32-unknown-elf
+
+SIM_FLAGS ?= -DSIM -DFUNCTIONAL -DUSE_POWER_PINS
+ifdef GL
+	SIM_FLAGS += -DGL
+endif
+
+all:  ${PATTERN:=.fst}
+
+%.vvp: %_tb.v firmware.hex
+	iverilog -I $(PDK_ROOT)/sky130A -I ../rtl -I .. \
+	$(SIM_FLAGS) \
+	$< -o $@
+
+%.fst: %.vvp
+	vvp $< -fst
+
+%.elf: %.c $(FIRMWARE_PATH)/sections_cpu0.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32ic -mabi=ilp32 \
+	-Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections_cpu0.lds,--strip-debug \
+	-ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@
+	sed -i 's/@304/@000/g' $@
+
+firmware.hex: $(PATTERN).hex
+	ln -s $< firmware.hex
+
+clean:
+	rm -f *.vvp *.vcd *.fst *.log *.hex *.bin *.elf
+
+.PHONY: clean all
diff --git a/verilog/rtl/softshell/dv/custom_ops.S b/verilog/rtl/softshell/dv/custom_ops.S
new file mode 100644
index 0000000..9034c2a
--- /dev/null
+++ b/verilog/rtl/softshell/dv/custom_ops.S
@@ -0,0 +1,110 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+
+#define regnum_q0   0
+#define regnum_q1   1
+#define regnum_q2   2
+#define regnum_q3   3
+
+#define regnum_x0   0
+#define regnum_x1   1
+#define regnum_x2   2
+#define regnum_x3   3
+#define regnum_x4   4
+#define regnum_x5   5
+#define regnum_x6   6
+#define regnum_x7   7
+#define regnum_x8   8
+#define regnum_x9   9
+#define regnum_x10 10
+#define regnum_x11 11
+#define regnum_x12 12
+#define regnum_x13 13
+#define regnum_x14 14
+#define regnum_x15 15
+#define regnum_x16 16
+#define regnum_x17 17
+#define regnum_x18 18
+#define regnum_x19 19
+#define regnum_x20 20
+#define regnum_x21 21
+#define regnum_x22 22
+#define regnum_x23 23
+#define regnum_x24 24
+#define regnum_x25 25
+#define regnum_x26 26
+#define regnum_x27 27
+#define regnum_x28 28
+#define regnum_x29 29
+#define regnum_x30 30
+#define regnum_x31 31
+
+#define regnum_zero 0
+#define regnum_ra   1
+#define regnum_sp   2
+#define regnum_gp   3
+#define regnum_tp   4
+#define regnum_t0   5
+#define regnum_t1   6
+#define regnum_t2   7
+#define regnum_s0   8
+#define regnum_s1   9
+#define regnum_a0  10
+#define regnum_a1  11
+#define regnum_a2  12
+#define regnum_a3  13
+#define regnum_a4  14
+#define regnum_a5  15
+#define regnum_a6  16
+#define regnum_a7  17
+#define regnum_s2  18
+#define regnum_s3  19
+#define regnum_s4  20
+#define regnum_s5  21
+#define regnum_s6  22
+#define regnum_s7  23
+#define regnum_s8  24
+#define regnum_s9  25
+#define regnum_s10 26
+#define regnum_s11 27
+#define regnum_t3  28
+#define regnum_t4  29
+#define regnum_t5  30
+#define regnum_t6  31
+
+// x8 is s0 and also fp
+#define regnum_fp   8
+
+#define r_type_insn(_f7, _rs2, _rs1, _f3, _rd, _opc) \
+.word (((_f7) << 25) | ((_rs2) << 20) | ((_rs1) << 15) | ((_f3) << 12) | ((_rd) << 7) | ((_opc) << 0))
+
+#define picorv32_getq_insn(_rd, _qs) \
+r_type_insn(0b0000000, 0, regnum_ ## _qs, 0b100, regnum_ ## _rd, 0b0001011)
+
+#define picorv32_setq_insn(_qd, _rs) \
+r_type_insn(0b0000001, 0, regnum_ ## _rs, 0b010, regnum_ ## _qd, 0b0001011)
+
+#define picorv32_retirq_insn() \
+r_type_insn(0b0000010, 0, 0, 0b000, 0, 0b0001011)
+
+#define picorv32_maskirq_insn(_rd, _rs) \
+r_type_insn(0b0000011, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)
+
+#define picorv32_waitirq_insn(_rd) \
+r_type_insn(0b0000100, 0, 0, 0b100, regnum_ ## _rd, 0b0001011)
+
+#define picorv32_timer_insn(_rd, _rs) \
+r_type_insn(0b0000101, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)
+
+#define fio_shift_cfg_sel_insn(_rs1, rs2) \
+r_type_insn(0b0000001, regnum_ ## _rs2, regnum_ ## _rs1, 0b000, 0, 0b0101011)
+
+#define fio_shift_write_insn(_rs1) \
+r_type_insn(0b0000010, 0, regnum_ ## _rs1, 0b000, 0, 0b0101011)
+
+#define fio_shift_read_insn(_rd) \
+r_type_insn(0b0000011, 0, 0, 0b000, regnum_ ## _rd, 0b0101011)
diff --git a/verilog/rtl/softshell/dv/hw.h b/verilog/rtl/softshell/dv/hw.h
new file mode 100644
index 0000000..7f52166
--- /dev/null
+++ b/verilog/rtl/softshell/dv/hw.h
@@ -0,0 +1,60 @@
+// Softshell hardware defines.
+//
+// SPDX-FileCopyrightText: (c) 2020 Harrison Pham <harrison@harrisonpham.com>
+// SPDX-License-Identifier: Apache-2.0
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOFTSHELL_DV_HW_H_
+#define SOFTSHELL_DV_HW_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+extern uint32_t flashio_worker_begin;
+extern uint32_t flashio_worker_end;
+
+// Addresses.
+#define GPIO_BASE_ADDR      0x20000000
+#define PINMUX_BASE_ADDR    0x30810000
+#define UART0_BASE_ADDR     0x30820000
+
+// Private GPIO peripheral.
+#define REG_GPIO_DATA (*(volatile uint32_t*)(GPIO_BASE_ADDR + 0x00))
+#define REG_GPIO_ENA  (*(volatile uint32_t*)(GPIO_BASE_ADDR + 0x04))
+#define REG_GPIO_PU   (*(volatile uint32_t*)(GPIO_BASE_ADDR + 0x08))
+#define REG_GPIO_PD   (*(volatile uint32_t*)(GPIO_BASE_ADDR + 0x0c))
+
+// Shared PINMUX.
+#define REG_PINMUX_IN_UART_RX_SEL \
+  (*(volatile uint32_t*)(PINMUX_BASE_ADDR + 0x1000 + 0))
+#define REG_PINMUX_OUT_GPIOX_SEL(x) \
+  (*(volatile uint32_t*)(PINMUX_BASE_ADDR + 0x2000 + (x << 2)))
+
+#define REG_PINMUX_OUT_SEL_UART0_TX 1
+#define REG_PINMUX_OUT_SEL_CPU0_FLEXIO_0 2
+#define REG_PINMUX_OUT_SEL_CPU0_FLEXIO_1 3
+#define REG_PINMUX_OUT_SEL_CPU0_FLEXIO_2 4
+#define REG_PINMUX_OUT_SEL_CPU0_FLEXIO_3 5
+#define REG_PINMUX_OUT_SEL_CPU0_FLEXIO_4 6
+#define REG_PINMUX_OUT_SEL_CPU0_FLEXIO_5 7
+#define REG_PINMUX_OUT_SEL_CPU0_FLEXIO_6 8
+#define REG_PINMUX_OUT_SEL_CPU0_FLEXIO_7 9
+#define REG_PINMUX_OUT_SEL_CPU0_FLEXIO_8 10
+
+// Shared UART0.
+#define REG_UART0_CLK_DIV (*(volatile uint32_t*)(UART0_BASE_ADDR + 0x00))
+#define REG_UART0_DATA    (*(volatile uint32_t*)(UART0_BASE_ADDR + 0x04))
+#define REG_UART0_CONFIG  (*(volatile uint32_t*)(UART0_BASE_ADDR + 0x08))
+
+#endif  // SOFTSHELL_DV_
diff --git a/verilog/rtl/softshell/dv/sections_cpu0.lds b/verilog/rtl/softshell/dv/sections_cpu0.lds
new file mode 100644
index 0000000..4a1bb39
--- /dev/null
+++ b/verilog/rtl/softshell/dv/sections_cpu0.lds
@@ -0,0 +1,58 @@
+MEMORY {
+	FLASH (rx)	: ORIGIN = 0x30410000, LENGTH = 0x10000 	/* 65 KB */
+	RAM (xrw)	: ORIGIN = 0x30000000, LENGTH = 0x0400		/* 256 words (1 KB) */
+}
+
+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)	/* .srodata sections (constants, strings, etc.) */
+		*(.srodata*)	/* .srodata*sections (constants, strings, etc.) */
+		. = ALIGN(4);
+		_etext = .;		/* define a global symbol at end of code */
+		_sidata = _etext;	/* This is used by the startup to initialize data */
+	} >FLASH
+
+	/* Initialized data section */
+	.data : AT ( _sidata )
+	{
+		. = ALIGN(4);
+		_sdata = .;
+		_ram_start = .;
+		. = ALIGN(4);
+		*(.data)
+		*(.data*)
+		*(.sdata)
+		*(.sdata*)
+		. = ALIGN(4);
+		_edata = .;
+	} >RAM
+
+	/* Uninitialized data section */
+	.bss :
+	{
+		. = ALIGN(4);
+		_sbss = .;
+		*(.bss)
+		*(.bss*)
+		*(.sbss)
+		*(.sbss*)
+		*(COMMON)
+
+		. = ALIGN(4);
+		_ebss = .;
+	} >RAM
+
+	/* Define the start of the heap */
+	.heap :
+	{
+		. = ALIGN(4);
+		_heap_start = .;
+	} >RAM
+}
diff --git a/verilog/rtl/softshell/dv/sections_cpu1.lds b/verilog/rtl/softshell/dv/sections_cpu1.lds
new file mode 100644
index 0000000..5776476
--- /dev/null
+++ b/verilog/rtl/softshell/dv/sections_cpu1.lds
@@ -0,0 +1,58 @@
+MEMORY {
+	FLASH (rx)	: ORIGIN = 0x30420000, LENGTH = 0x10000 	/* 65 KB */
+	RAM (xrw)	: ORIGIN = 0x30000000, LENGTH = 0x0400		/* 256 words (1 KB) */
+}
+
+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)	/* .srodata sections (constants, strings, etc.) */
+		*(.srodata*)	/* .srodata*sections (constants, strings, etc.) */
+		. = ALIGN(4);
+		_etext = .;		/* define a global symbol at end of code */
+		_sidata = _etext;	/* This is used by the startup to initialize data */
+	} >FLASH
+
+	/* Initialized data section */
+	.data : AT ( _sidata )
+	{
+		. = ALIGN(4);
+		_sdata = .;
+		_ram_start = .;
+		. = ALIGN(4);
+		*(.data)
+		*(.data*)
+		*(.sdata)
+		*(.sdata*)
+		. = ALIGN(4);
+		_edata = .;
+	} >RAM
+
+	/* Uninitialized data section */
+	.bss :
+	{
+		. = ALIGN(4);
+		_sbss = .;
+		*(.bss)
+		*(.bss*)
+		*(.sbss)
+		*(.sbss*)
+		*(COMMON)
+
+		. = ALIGN(4);
+		_ebss = .;
+	} >RAM
+
+	/* Define the start of the heap */
+	.heap :
+	{
+		. = ALIGN(4);
+		_heap_start = .;
+	} >RAM
+}
diff --git a/verilog/rtl/softshell/dv/softshell_top.c b/verilog/rtl/softshell/dv/softshell_top.c
new file mode 100644
index 0000000..764aa17
--- /dev/null
+++ b/verilog/rtl/softshell/dv/softshell_top.c
@@ -0,0 +1,115 @@
+// Softshell testbench firmware.
+//
+// SPDX-FileCopyrightText: (c) 2020 Harrison Pham <harrison@harrisonpham.com>
+// SPDX-License-Identifier: Apache-2.0
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#include "hw.h"
+
+#include "../third_party/rocc-software/xcustom.h"
+
+#define FIO_SHIFT_CFG_INSTRUCTION(cfg, clk_div) \
+  ROCC_INSTRUCTION_0_R_R(1, cfg, clk_div, 0b0000001)
+
+#define FIO_SHIFT_WRITE_INSTRUCTION(word) \
+  ROCC_INSTRUCTION_0_R_R(1, word, word, 0b0000010)
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+#define PIN_OFFSET 6
+
+uint32_t mem_test[200];
+
+void main() {
+  // UART testbench loopback.
+  REG_PINMUX_OUT_GPIOX_SEL(30 - PIN_OFFSET) = REG_PINMUX_OUT_SEL_UART0_TX;
+  REG_PINMUX_IN_UART_RX_SEL = 31 - PIN_OFFSET + 1;
+
+  REG_PINMUX_OUT_GPIOX_SEL(PIN_OFFSET + 8 + 0) = REG_PINMUX_OUT_SEL_CPU0_FLEXIO_0;
+  REG_PINMUX_OUT_GPIOX_SEL(PIN_OFFSET + 8 + 1) = REG_PINMUX_OUT_SEL_CPU0_FLEXIO_1;
+  REG_PINMUX_OUT_GPIOX_SEL(PIN_OFFSET + 8 + 2) = REG_PINMUX_OUT_SEL_CPU0_FLEXIO_2;
+  REG_PINMUX_OUT_GPIOX_SEL(PIN_OFFSET + 8 + 3) = REG_PINMUX_OUT_SEL_CPU0_FLEXIO_3;
+  REG_PINMUX_OUT_GPIOX_SEL(PIN_OFFSET + 8 + 4) = REG_PINMUX_OUT_SEL_CPU0_FLEXIO_4;
+  REG_PINMUX_OUT_GPIOX_SEL(PIN_OFFSET + 8 + 5) = REG_PINMUX_OUT_SEL_CPU0_FLEXIO_5;
+  REG_PINMUX_OUT_GPIOX_SEL(PIN_OFFSET + 8 + 6) = REG_PINMUX_OUT_SEL_CPU0_FLEXIO_6;
+  REG_PINMUX_OUT_GPIOX_SEL(PIN_OFFSET + 8 + 7) = REG_PINMUX_OUT_SEL_CPU0_FLEXIO_7;
+  REG_PINMUX_OUT_GPIOX_SEL(PIN_OFFSET + 8 + 8) = REG_PINMUX_OUT_SEL_CPU0_FLEXIO_8;
+
+  // Configure flexio.
+  uint32_t cfg, clk_div;
+  cfg = (0xf << 24) | (8 << 16);
+  clk_div = 64;
+  FIO_SHIFT_CFG_INSTRUCTION(cfg, clk_div);
+
+  // Test pattern.
+  cfg = 0x5234567a;
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+  FIO_SHIFT_WRITE_INSTRUCTION(cfg);
+
+  REG_UART0_CLK_DIV = 32;
+  REG_UART0_CONFIG = 1;
+
+  if (REG_UART0_DATA != 0xffffffff) {
+    asm volatile("ebreak");
+  }
+
+  REG_UART0_DATA = 0x55;
+  REG_UART0_DATA = 0xaa;
+  REG_UART0_DATA = 0x00;
+
+  if (REG_UART0_DATA != 0xaa) {
+    asm volatile("ebreak");
+  }
+
+  REG_GPIO_ENA = 0x80000000;
+
+  for (size_t i = 0; i < ARRAY_SIZE(mem_test); ++i) {
+    mem_test[i] = (~i << 16) + i;
+  }
+
+  for (size_t i = 0; i < ARRAY_SIZE(mem_test); ++i) {
+    if (mem_test[i] != (~i << 16) + i) {
+      asm volatile("ebreak");
+    }
+  }
+
+  uint32_t i = 0;
+  while (true) {
+    ++i;
+    if (i == 10) {
+      REG_GPIO_DATA = 0x80000000;
+    }
+  }
+
+}
diff --git a/verilog/rtl/softshell/dv/softshell_top_tb.v b/verilog/rtl/softshell/dv/softshell_top_tb.v
new file mode 100644
index 0000000..5a7bdd1
--- /dev/null
+++ b/verilog/rtl/softshell/dv/softshell_top_tb.v
@@ -0,0 +1,296 @@
+// Softshell testbench.
+//
+// SPDX-FileCopyrightText: (c) 2020 Harrison Pham <harrison@harrisonpham.com>
+// SPDX-License-Identifier: Apache-2.0
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+`timescale 1 ns / 1 ps
+
+`define MPRJ_IO_PADS 38
+`define MPRJ_PWR_PADS 4		/* vdda1, vccd1, vdda2, vccd2 */
+// `define USE_CUSTOM_DFFRAM
+`define USE_OPENRAM
+`define MEM_WORDS 256
+`define COLS 1
+
+`ifdef GL
+  // NOTE: Make sure to keep this in sync with the actual RTL.
+  `define SHARED_MEM_WORDS 512
+  `define MEM_TEST_STEP_SIZE_WORDS 123
+`else
+  `define MEM_TEST_STEP_SIZE_WORDS 1
+`endif
+
+// Models.
+// `include "third_party/sky130/models/sram_1rw1r_32_256_8_sky130.v"
+// `include "third_party/DFFRAM/models/DFFRAMBB.v"
+// `include "third_party/DFFRAM/models/DFFRAM.v"
+`include "third_party/picorv32/picosoc/spiflash.v"
+
+// Gatelevel models.
+//`ifdef GL
+  `include "libs.ref/sky130_fd_sc_hd/verilog/primitives.v"
+  `include "libs.ref/sky130_fd_sc_hd/verilog/sky130_fd_sc_hd.v"
+  // `include "libs.ref/sky130_fd_sc_hvl/verilog/primitives.v"
+  // `include "libs.ref/sky130_fd_sc_hvl/verilog/sky130_fd_sc_hvl.v"
+//`endif
+
+// Design.
+`ifdef GL
+  `include "../../../gl/user_proj_example.v"
+`else
+  `include "softshell_top.v"
+  `include "rv_core.v"
+  `include "pinmux.v"
+  `include "pcpi_flexio.v"
+  `include "third_party/verilog-wishbone/rtl/wb_arbiter_3.v"
+  `include "third_party/verilog-wishbone/rtl/wb_arbiter_4.v"
+  `include "third_party/verilog-wishbone/rtl/wb_arbiter_5.v"
+  `include "third_party/verilog-wishbone/rtl/arbiter.v"
+  `include "third_party/verilog-wishbone/rtl/priority_encoder.v"
+  `include "third_party/verilog-wishbone/rtl/wb_mux_3.v"
+  `include "third_party/verilog-wishbone/rtl/wb_mux_5.v"
+  `include "third_party/picorv32_wb/mem_ff_wb.v"
+  `include "third_party/picorv32_wb/simpleuart.v"
+  `include "third_party/picorv32_wb/spimemio.v"
+  `include "third_party/picorv32_wb/picorv32.v"
+  `include "third_party/picorv32_wb/gpio32_wb.v"
+  `include "third_party/wb2axip/rtl/afifo.v"
+`endif
+
+module softshell_top_tb;
+  reg clk;
+  reg resetb;
+
+  wire wb_clk_i;
+  wire wb_rst_i;
+  reg wb_stb_i;
+  reg wb_cyc_i;
+  reg wb_we_i;
+  reg [3:0] wb_sel_i;
+  reg [31:0] wb_dat_i;
+  reg [31:0] wb_adr_i;
+  wire wb_ack_o;
+  wire [31:0] wb_dat_o;
+
+  reg  [127:0] la_data_in;
+  wire [127:0] la_data_out;
+  reg  [127:0] la_oen;
+
+  wire [`MPRJ_IO_PADS-1:0] io_in;
+  wire [`MPRJ_IO_PADS-1:0] io_out;
+  wire [`MPRJ_IO_PADS-1:0] io_oeb;
+
+  reg [`MPRJ_IO_PADS-1:0] io_in_reg;
+
+  // Exclude flash pad and UART loopback.
+  assign io_in[37:32] = io_in_reg[37:32];
+  assign io_in[30:14] = io_in_reg[30:14];
+
+  // UART loopback pin 32 (RX) to pin 31 (TX)
+  assign io_in[31] = (!io_oeb[30]) ? (io_out[30]) : (1'bz);
+
+  always #50 clk = ~clk;
+
+  assign wb_clk_i = clk;
+  assign wb_rst_i = ~resetb;
+
+  integer i, address, data;
+  initial begin
+    $dumpfile("softshell_top_tb.fst");
+    $dumpvars(0, softshell_top_tb);
+
+    clk = 0;
+    resetb = 0;
+
+    io_in_reg = {`MPRJ_IO_PADS{1'b0}};
+
+    la_data_in = 128'b0;
+    la_oen = 128'b0;
+
+    wb_stb_i = 0;
+    wb_cyc_i = 0;
+    wb_sel_i = 4'b0;
+    wb_we_i = 0;
+    wb_adr_i = 32'b0;
+    wb_dat_i = 32'b0;
+
+    #200;
+    resetb = 1;
+    #200;
+    $display("Reset complete");
+
+    $display("Holding CPUs in reset for RAM test");
+    la_data_in[4:1] = 4'b1111;
+
+    $display("Testing shared memory");
+    for (i = 0; i < 32 * 4; i = i + 4) begin
+      address = 32'h3000_0000 + i;
+      data = $random;
+      write(address, data);
+      write(address + 4, ~data);
+      read_assert(address, data);
+      read_assert(address + 4, ~data);
+    end
+    for (i = 0; i < `SHARED_MEM_WORDS * 4;
+         i = i + 4 * MEM_TEST_STEP_SIZE_WORDS) begin
+      address = 32'h3000_0000 + i;
+      data = i;
+      write(address, data);
+      read_assert(address, data);
+    end
+    for (i = 0; i < `SHARED_MEM_WORDS * 4;
+         i = i + 4 * MEM_TEST_STEP_SIZE_WORDS) begin
+      address = 32'h3000_0000 + i;
+      data = i;
+      read_assert(address, data);
+    end
+
+    $display("Releasing CPUs from reset");
+    la_data_in[4:1] = 4'b1110;
+
+    $display("Waiting for CPU GPIO toggles");
+    // wait(io_out[7+14:0+14] != 8'h00);
+    wait(io_out[37] == 1'b1);
+
+    $display("Finished");
+    $finish;
+  end
+
+`ifndef GL
+  always begin
+    wait(uut.cpus[0].core.trap == 1'b1);
+    $error("CPU0 TRAP!");
+    $finish;
+  end
+
+  always begin
+    wait(uut.cpus[1].core.trap == 1'b1);
+    $error("CPU1 TRAP!");
+    $finish;
+  end
+`endif
+
+`ifdef GL
+  user_proj_example uut (
+    .VPWR(1'b1),
+    .VGND(1'b0),
+`else
+  softshell_top uut (
+`endif
+    .wb_clk_i(wb_clk_i),
+    .wb_rst_i(wb_rst_i),
+
+    .wbs_stb_i(wb_stb_i),
+    .wbs_cyc_i(wb_cyc_i),
+    .wbs_we_i(wb_we_i),
+    .wbs_sel_i(wb_sel_i),
+    .wbs_dat_i(wb_dat_i),
+    .wbs_adr_i(wb_adr_i),
+    .wbs_ack_o(wb_ack_o),
+    .wbs_dat_o(wb_dat_o),
+
+    // Logic Analyzer Signals
+    .la_data_in(la_data_in),
+    .la_data_out(la_data_out),
+    .la_oen(la_oen),
+
+    // IOs
+    .io_in(io_in),
+    .io_out(io_out),
+    .io_oeb(io_oeb)
+  );
+
+  // Flash signals.
+  wire flash_csb;
+  wire flash_clk;
+  wire flash_io0;
+  wire flash_io1;
+  wire flash_io2;
+  wire flash_io3;
+
+  assign flash_csb = (io_oeb[8] == 1'b0) ? (io_out[8]) : (1'bz);
+  assign flash_clk = (io_oeb[9] == 1'b0) ? (io_out[9]) : (1'bz);
+  assign flash_io0 = (io_oeb[10] == 1'b0) ? (io_out[10]) : (1'bz);
+  assign flash_io1 = (io_oeb[11] == 1'b0) ? (io_out[11]) : (1'bz);
+  assign flash_io2 = (io_oeb[12] == 1'b0) ? (io_out[12]) : (1'bz);
+  assign flash_io3 = (io_oeb[13] == 1'b0) ? (io_out[13]) : (1'bz);
+  assign io_in[10] = flash_io0;
+  assign io_in[11] = flash_io1;
+  assign io_in[12] = flash_io2;
+  assign io_in[13] = flash_io3;
+
+  spiflash flash_model (
+    .csb(flash_csb),
+    .clk(flash_clk),
+    .io0(flash_io0),
+    .io1(flash_io1),
+    .io2(flash_io2),
+    .io3(flash_io3)
+  );
+
+  task write;
+    input [31:0] addr;
+    input [31:0] data;
+    begin
+      @(posedge wb_clk_i) begin
+        wb_stb_i = 1;
+        wb_cyc_i = 1;
+        wb_sel_i = 4'hF;
+        wb_we_i = 1;
+        wb_adr_i = addr;
+        wb_dat_i = data;
+        $display("W   [%0h]=%0h", addr, data);
+      end
+      // Wait for an ACK
+      wait(wb_ack_o == 1);
+      wait(wb_ack_o == 0);
+      wb_cyc_i = 0;
+      wb_stb_i = 0;
+      $display("W D");
+    end
+  endtask
+
+  task read;
+    input [31:0] addr;
+    begin
+      @(posedge wb_clk_i) begin
+        wb_stb_i = 1;
+        wb_cyc_i = 1;
+        wb_we_i = 0;
+        wb_adr_i = addr;
+        $display("R   [%0h]", addr);
+      end
+      // Wait for an ACK
+      wait(wb_ack_o == 1);
+      wait(wb_ack_o == 0);
+      wb_cyc_i = 0;
+      wb_stb_i = 0;
+      $display("R D [%0h]=%0h", addr, wb_dat_o);
+    end
+  endtask
+
+  task read_assert;
+    input [31:0] addr;
+    input [31:0] data;
+    begin
+      read(addr);
+      if (wb_dat_o != data) begin
+        $error("R!! %0h!=%0h", wb_dat_o, data);
+        $fatal;
+      end
+    end
+  endtask
+
+endmodule
diff --git a/verilog/rtl/softshell/dv/start.s b/verilog/rtl/softshell/dv/start.s
new file mode 100644
index 0000000..45f8904
--- /dev/null
+++ b/verilog/rtl/softshell/dv/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
+
+# zero initialize scratchpad memory
+# setmemloop:
+# sw zero, 0(x1)
+# addi x1, x1, 4
+# blt x1, sp, setmemloop
+
+# 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:
+
+# 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:
+
+# 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, 0x30800000
+
+# 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:
+
+# If byte count is zero, we're done
+beqz a1, flashio_worker_L3
+
+# Set t5 to count down 32 bits
+li   t5, 32
+# Load t2 from address a0 (4 bytes)
+lw   t2, 0(a0)
+
+flashio_worker_LY:
+# Set t6 to count down 8 bits
+li   t6, 8
+
+flashio_worker_L2:
+# Clock out the bit (msb first) on IO0 and read bit in from IO1
+srli t4, t2, 31
+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
+
+# Decrement 32 bit count
+addi t5, t5, -1
+bnez t5, flashio_worker_LX
+
+sw   t2, 0(a0)
+addi a0, a0, 4
+lw   t2, 0(a0)
+
+flashio_worker_LX:
+addi t6, t6, -1
+bnez t6, flashio_worker_L2
+addi a1, a1, -1
+bnez a1, flashio_worker_LY
+
+beqz t5, flashio_worker_L3
+sw   t2, 0(a0)
+
+flashio_worker_L3:
+# Back to MEMIO mode
+li   t1, 0x80
+sb   t1, 3(t0)
+
+ret
+.balign 4
+flashio_worker_end:
+
diff --git a/verilog/rtl/softshell/rtl/pcpi_flexio.v b/verilog/rtl/softshell/rtl/pcpi_flexio.v
new file mode 100644
index 0000000..8b15286
--- /dev/null
+++ b/verilog/rtl/softshell/rtl/pcpi_flexio.v
@@ -0,0 +1,196 @@
+// Flexible IO custom instruction for picorv32.
+//
+// SPDX-FileCopyrightText: (c) 2020 Harrison Pham <harrison@harrisonpham.com>
+// SPDX-License-Identifier: Apache-2.0
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+module pcpi_flexio (
+  input               clk,
+  input               resetb,
+  input               pcpi_valid,
+  input       [31:0]  pcpi_insn,
+  input       [31:0]  pcpi_rs1,
+  input       [31:0]  pcpi_rs2,
+  output              pcpi_wr,
+  output      [31:0]  pcpi_rd,
+  output reg          pcpi_wait,
+  output reg          pcpi_ready,
+
+  input               flexio_clk,
+  input               flexio_resetb,
+  input       [7:0]   flexio_in,
+  output      [7:0]   flexio_out,
+  output      [7:0]   flexio_oeb
+);
+
+  // fio_shift_cfg
+  // opcode: custom1
+  // rs1 =
+  //        [31:24] output bit mask
+  //        [23:20]
+  //        [19:16] bits per clock
+  //        [15: 0]
+  // rs2 =
+  //        [23: 0] clock div
+  // rd  = n/a
+  // funct7: 7'b0000001
+  // funct3: don't care
+  wire fio_shift_cfg_sel = pcpi_insn[6:0] == 7'b0101011 &&
+                           pcpi_insn[31:25] == 7'b0000001;
+
+  // fio_shift_write
+  // opcode: custom1
+  // rs1 = lsb write word
+  // rs2 = n/a
+  // rd  = n/a
+  // funct7: 7'b0000010
+  // funct3: don't care
+  wire fio_shift_write_sel = pcpi_insn[6:0] == 7'b0101011 &&
+                             pcpi_insn[31:25] == 7'b0000010;
+
+  // fio_shift_read
+  // rs1 = n/a
+  // rs2 = n/a
+  // rd  = readback word
+  // opcode: custom1
+  // funct7: 7'b0000011
+  // funct3: don't care
+  wire fio_shift_read_sel = pcpi_insn[6:0] == 7'b0101011 &&
+                            pcpi_insn[31:25] == 7'b0000011;
+
+  // Configuration registers.
+  reg [7:0] cfg_out_bit_mask;
+  reg [3:0] cfg_bits_per_clock;
+  reg [23:0] cfg_clk_div;
+
+  // Tieoff unused for now.
+  assign pcpi_rd = 32'b0;
+  assign pcpi_wr = 1'b0;
+
+  // FIFO for output data.
+  reg out_wr_en;
+  reg [31:0] out_wr_data;
+  wire out_wr_full;
+  reg out_rd_en;
+  wire [31:0] out_rd_data;
+  wire out_rd_empty;
+
+  afifo #(
+    .LGFIFO(2),   // 4 level deep fifo
+    .WIDTH(32),
+    .OPT_REGISTER_READS(1'b0)
+  ) out_fifo (
+    .i_wclk(clk),
+    .i_wr_reset_n(resetb),
+    .i_wr(out_wr_en),
+    .i_wr_data(out_wr_data),
+    .o_wr_full(out_wr_full),
+
+    .i_rclk(flexio_clk),
+    .i_rd_reset_n(flexio_resetb),
+    .i_rd(out_rd_en),
+    .o_rd_data(out_rd_data),
+    .o_rd_empty(out_rd_empty)
+  );
+
+  // Instruction registers.
+  always @(posedge clk or negedge resetb) begin
+    if (!resetb) begin
+      pcpi_ready <= 1'b0;
+      pcpi_wait <= 1'b0;
+
+      out_wr_en <= 1'b0;
+      out_wr_data <= 32'b0;
+      cfg_out_bit_mask <= 8'b0;
+      cfg_bits_per_clock <= 4'b0;
+      cfg_clk_div <= 24'b0;
+    end else if (pcpi_valid && !pcpi_ready) begin
+      pcpi_ready <= 1'b1;
+      pcpi_wait <= 1'b0;
+      out_wr_en <= 1'b0;
+
+      if (fio_shift_cfg_sel) begin
+        cfg_out_bit_mask <= pcpi_rs1[31:24];
+        cfg_bits_per_clock <= pcpi_rs1[19:16];
+        cfg_clk_div <= pcpi_rs2[23:0];
+      end else if (fio_shift_write_sel) begin
+        if (out_wr_full) begin
+          pcpi_ready <= 1'b0;
+          pcpi_wait <= 1'b1;
+        end else begin
+          out_wr_data <= pcpi_rs1;
+          out_wr_en <= 1'b1;
+        end
+      end
+    end else begin
+      pcpi_ready <= 1'b0;
+      pcpi_wait <= 1'b0;
+      out_wr_en <= 1'b0;
+    end
+  end
+
+  // Clock gen.
+  reg [23:0] clk_div_cnt;
+  reg clk_en;
+
+  always @(posedge flexio_clk or negedge flexio_resetb) begin
+    if (!flexio_resetb) begin
+      clk_div_cnt <= 24'd0;
+      clk_en <= 1'b0;
+    end else if (clk_div_cnt == cfg_clk_div) begin
+      clk_div_cnt <= 24'd0;
+      clk_en <= 1'b1;
+    end else begin
+      clk_div_cnt <= clk_div_cnt + 16'd1;
+      clk_en <= 1'b0;
+    end
+  end
+
+  // Output shift reg.
+  reg [31:0] out_shift_reg;
+  reg [4:0] out_shift_cnt;
+
+  always @(posedge flexio_clk or negedge flexio_resetb) begin
+    if (!flexio_resetb) begin
+      out_shift_reg <= 32'b0;
+      out_shift_cnt <= 5'd31;
+      out_rd_en <= 1'b0;
+    end else if (clk_en && out_shift_cnt == 5'd31 && !out_rd_empty) begin
+      // Finished shifting out all bits, load value from shift FIFO.
+      out_shift_reg <= out_rd_data;
+      out_rd_en <= 1'b1;
+      case (cfg_bits_per_clock)
+        4'd2: out_shift_cnt <= 5'd16;
+        4'd4: out_shift_cnt <= 5'd24;
+        4'd8: out_shift_cnt <= 5'd28;
+        default: out_shift_cnt <= 5'd0;
+      endcase
+    end else if (clk_en && out_shift_cnt != 5'd31) begin
+      case (cfg_bits_per_clock)
+        4'd2: out_shift_reg <= {out_shift_reg[29:0], 2'b00};
+        4'd4: out_shift_reg <= {out_shift_reg[27:0], 4'b0};
+        4'd8: out_shift_reg <= {out_shift_reg[23:0], 8'b0};
+        default: out_shift_reg <= {out_shift_reg[30:0], 1'b0};
+      endcase
+      out_shift_cnt <= out_shift_cnt + 5'd1;
+      out_rd_en <= 1'b0;
+    end else begin
+      out_rd_en <= 1'b0;
+    end
+  end
+
+  assign flexio_out = out_shift_reg[31:24];
+  assign flexio_oeb = ~cfg_out_bit_mask;
+
+endmodule // module pcpi_flexio
diff --git a/verilog/rtl/softshell/rtl/pinmux.v b/verilog/rtl/softshell/rtl/pinmux.v
new file mode 100644
index 0000000..2441bf7
--- /dev/null
+++ b/verilog/rtl/softshell/rtl/pinmux.v
@@ -0,0 +1,132 @@
+// Any-to-any pin mux for slow speed peripherals.
+//
+// SPDX-FileCopyrightText: (c) 2020 Harrison Pham <harrison@harrisonpham.com>
+// SPDX-License-Identifier: Apache-2.0
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+module pinmux #(
+  // Number of peripheral inputs.  Maximum is 255.
+  parameter NUM_INPUTS = 8,
+  // Number of peripheral outputs.  Maximum is 255.
+  parameter NUM_OUTPUTS = 8,
+  // Total number of GPIOs.  Maximum is 255.
+  parameter NUM_GPIOS = 32
+) (
+  input wb_clk_i,
+  input wb_rst_i,
+
+  input [31:0] wb_adr_i,
+  input [31:0] wb_dat_i,
+  input [3:0] wb_sel_i,
+  input wb_cyc_i,
+  input wb_stb_i,
+  input wb_we_i,
+
+  output reg [31:0] wb_dat_o,
+  output reg wb_ack_o,
+
+  input  [NUM_GPIOS-1:0] gpio_in,
+  output [NUM_GPIOS-1:0] gpio_out,
+  output [NUM_GPIOS-1:0] gpio_oeb,
+
+  output [NUM_INPUTS-1:0]  peripheral_in,
+  input  [NUM_OUTPUTS-1:0] peripheral_out,
+  input  [NUM_OUTPUTS-1:0] peripheral_oeb
+);
+  localparam PINMUX_IN_SEL_ADDR  = 16'h1000;
+  localparam PINMUX_OUT_SEL_ADDR = 16'h2000;
+
+  // Number of bits required for the selection registers.  Theses are sized + 1
+  // to make room for the default selection of 0.
+  localparam INPUT_REG_BITS = $clog2(NUM_GPIOS + 1);
+  localparam OUTPUT_REG_BITS = $clog2(NUM_OUTPUTS + 1);
+
+  // Internal aliases for the input / outputs.  Shifted by one so that selection
+  // of 0 resolves to nothing.
+  wire [NUM_GPIOS:0] gpio_in_int;
+  wire [NUM_OUTPUTS:0] peripheral_out_int;
+  wire [NUM_OUTPUTS:0] peripheral_oeb_int;
+  assign gpio_in_int = {gpio_in, 1'b0};
+  assign peripheral_out_int = {peripheral_out, 1'b0};
+  assign peripheral_oeb_int = {peripheral_oeb, 1'b1};
+
+  // Input select registers, where the register value is the GPIO number to
+  // route to the peripheral_in.
+  reg [INPUT_REG_BITS-1:0] reg_mux_in [NUM_INPUTS-1:0];
+
+  // Output select registers, where the register value is the peripheral_out
+  // index to route to the GPIO.
+  reg [OUTPUT_REG_BITS-1:0] reg_mux_out [NUM_GPIOS-1:0];
+
+  wire slave_sel;
+  wire slave_write_en;
+  assign slave_sel = (wb_stb_i && wb_cyc_i);
+  assign slave_write_en = (|wb_sel_i && wb_we_i);
+
+  wire pinmux_in_sel;
+  wire pinmux_out_sel;
+  assign pinmux_in_sel = |(wb_adr_i[15:0] & PINMUX_IN_SEL_ADDR);
+  assign pinmux_out_sel = |(wb_adr_i[15:0] & PINMUX_OUT_SEL_ADDR);
+
+  integer i;
+  always @(posedge wb_clk_i or posedge wb_rst_i) begin
+    if (wb_rst_i) begin
+      for (i = 0; i < NUM_INPUTS; i = i + 1) begin
+        reg_mux_in[i] <= {INPUT_REG_BITS{1'b0}};
+      end
+      for (i = 0; i < NUM_GPIOS; i = i + 1) begin
+        reg_mux_out[i] <= {OUTPUT_REG_BITS{1'b0}};
+      end
+      wb_ack_o <= 1'b0;
+      wb_dat_o <= 32'b0;
+    end else begin
+      wb_ack_o <= 1'b0;
+
+      if (slave_sel && !wb_ack_o) begin
+        wb_ack_o <= 1'b1;
+
+        if (pinmux_in_sel) begin
+          wb_dat_o <= reg_mux_in[wb_adr_i[INPUT_REG_BITS-1+2:0+2]];
+          if (slave_write_en) begin
+            reg_mux_in[wb_adr_i[INPUT_REG_BITS-1+2:0+2]] <=
+              wb_dat_i[INPUT_REG_BITS-1:0];
+          end
+        end else if (pinmux_out_sel) begin
+          wb_dat_o <= reg_mux_out[wb_adr_i[OUTPUT_REG_BITS-1+2:0+2]];
+          if (slave_write_en) begin
+            reg_mux_out[wb_adr_i[OUTPUT_REG_BITS-1+2:0+2]] <=
+              wb_dat_i[OUTPUT_REG_BITS-1:0];
+          end
+        end
+      end
+    end
+  end
+
+  // Generate peripheral input selection muxes.
+  genvar j;
+  generate
+    for (j = 0; j < NUM_INPUTS; j = j + 1) begin
+      assign peripheral_in[j] = gpio_in_int[reg_mux_in[j]];
+    end
+  endgenerate
+
+  // Generate peripheral output select muxes.
+  generate
+    for (j = 0; j < NUM_GPIOS; j = j + 1) begin
+      assign gpio_out[j] = peripheral_out_int[reg_mux_out[j]];
+      assign gpio_oeb[j] = peripheral_oeb_int[reg_mux_out[j]];
+    end
+  endgenerate
+
+endmodule // module softshell_pinmux
diff --git a/verilog/rtl/softshell/rtl/rv_core.v b/verilog/rtl/softshell/rtl/rv_core.v
new file mode 100644
index 0000000..7e7e56f
--- /dev/null
+++ b/verilog/rtl/softshell/rtl/rv_core.v
@@ -0,0 +1,290 @@
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *  Revision 1,  July 2019:  Added signals to drive flash_clk and flash_csb
+ *  output enable (inverted), tied to reset so that the flash is completely
+ *  isolated from the processor when the processor is in reset.
+ *
+ *  Also: Made ram_wenb a 4-bit bus so that the memory access can be made
+ *  byte-wide for byte-wide instructions.
+ */
+
+`ifdef PICORV32_V
+`error "rv_core.v must be read before picorv32.v!"
+`endif
+
+`define PICORV32_REGS mgmt_soc_regs
+
+// `include "third_party/picorv32_wb/picorv32.v"
+// `include "third_party/picorv32_wb/gpio32_wb.v"
+
+module rv_core #(
+  // Size of memory in 32-bit words.
+  parameter MEM_WORDS = 256,
+  // Reset PC for CPU, address in shared memory.
+  parameter PROGADDR_RESET = 32'h1000_0000,
+  parameter CORE_ID = 0
+)(
+  // Core clock and resets.
+  input wb_clk_i,
+  input wb_rst_i,
+
+  // WB Master (to shared peripherals)
+  input shared_ack_i,
+  input [31:0] shared_dat_i,
+  output shared_cyc_o,
+  output shared_stb_o,
+  output shared_we_o,
+  output [3:0] shared_sel_o,
+  output [31:0] shared_adr_o,
+  output [31:0] shared_dat_o,
+
+  input [31:0]  gpio_in,
+  output [31:0] gpio_out,
+  output [31:0] gpio_oeb,
+
+  input [7:0]   flexio_in,
+  output [7:0]  flexio_out,
+  output [7:0]  flexio_oeb
+);
+
+  // Stack base address, mapped to end of private CCM.
+  parameter [31:0] STACKADDR = (4*(MEM_WORDS));
+  // IRQ handler start address, mapped to private CCM.
+  parameter [31:0] PROGADDR_IRQ = 32'h0000_0000;
+
+  // Slave base addresses.
+  parameter CCM_ADDR_MASK     = 32'hffff_0000;
+  parameter CCM_BASE_ADDR     = 32'h0000_0000;
+
+  parameter GPIO_ADDR_MASK    = 32'hffff_0000;
+  parameter GPIO_BASE_ADDR    = 32'h2000_0000;
+
+  parameter SHARED_ADDR_MASK  = 32'hff00_0000;
+  parameter SHARED_BASE_ADDR  = 32'h3000_0000;
+
+  // Flex IO custom instruction.
+  wire pcpi_valid;
+  wire [31:0] pcpi_insn;
+  wire [31:0] pcpi_rs1;
+  wire [31:0] pcpi_rs2;
+  wire pcpi_wr;
+  wire [31:0] pcpi_rd;
+  wire pcpi_wait;
+  wire pcpi_ready;
+
+  pcpi_flexio flexio (
+    .clk(wb_clk_i),
+    .resetb(~wb_rst_i),
+    .pcpi_valid(pcpi_valid),
+    .pcpi_insn(pcpi_insn),
+    .pcpi_rs1(pcpi_rs1),
+    .pcpi_rs2(pcpi_rs2),
+    .pcpi_wr(pcpi_wr),
+    .pcpi_rd(pcpi_rd),
+    .pcpi_wait(pcpi_wait),
+    .pcpi_ready(pcpi_ready),
+
+    .flexio_clk(wb_clk_i),
+    .flexio_resetb(~wb_rst_i),
+    .flexio_in(flexio_in),
+    .flexio_out(flexio_out),
+    .flexio_oeb(flexio_oeb)
+  );
+
+  // Wishbone internal master bus.
+  wire [31:0] cpu_adr_o;
+  wire [31:0] cpu_dat_i;
+  wire [3:0] cpu_sel_o;
+  wire cpu_we_o;
+  wire cpu_cyc_o;
+  wire cpu_stb_o;
+  wire [31:0] cpu_dat_o;
+  wire cpu_ack_i;
+  wire mem_instr;
+
+  // Extra CPU signals.
+  wire trap;
+  wire [31:0] irq;
+
+  assign irq = 32'b0;
+
+  picorv32_wb #(
+    .STACKADDR(STACKADDR),
+    .PROGADDR_RESET(PROGADDR_RESET),
+    .PROGADDR_IRQ(PROGADDR_IRQ),
+    .BARREL_SHIFTER(1),
+    .COMPRESSED_ISA(1),
+    .ENABLE_MUL(0),
+    .ENABLE_DIV(0),
+    .ENABLE_IRQ(1),
+    .ENABLE_IRQ_QREGS(0),
+    .ENABLE_COUNTERS64(0),
+    .ENABLE_PCPI(1)
+  ) cpu (
+    .wb_clk_i(wb_clk_i),
+    .wb_rst_i(wb_rst_i),
+    .trap(trap),
+    .irq(irq),
+    .mem_instr(mem_instr),
+    .wbm_adr_o(cpu_adr_o),
+    .wbm_dat_i(cpu_dat_i),
+    .wbm_stb_o(cpu_stb_o),
+    .wbm_ack_i(cpu_ack_i),
+    .wbm_cyc_o(cpu_cyc_o),
+    .wbm_dat_o(cpu_dat_o),
+    .wbm_we_o(cpu_we_o),
+    .wbm_sel_o(cpu_sel_o),
+
+    .pcpi_valid(pcpi_valid),
+    .pcpi_insn(pcpi_insn),
+    .pcpi_rs1(pcpi_rs1),
+    .pcpi_rs2(pcpi_rs2),
+    .pcpi_wr(pcpi_wr),
+    .pcpi_rd(pcpi_rd),
+    .pcpi_wait(pcpi_wait),
+    .pcpi_ready(pcpi_ready)
+  );
+
+  // Wishbone CCM slave.
+  wire [31:0] mem_adr_i;
+  wire [31:0] mem_dat_i;
+  wire [3:0]  mem_sel_i;
+  wire mem_we_i;
+  wire mem_cyc_i;
+  wire mem_stb_i;
+  wire mem_ack_o;
+  wire [31:0] mem_dat_o;
+
+  mem_ff_wb #(
+    .MEM_WORDS(MEM_WORDS)
+  ) soc_mem (
+    .wb_clk_i(wb_clk_i),
+    .wb_rst_i(wb_rst_i),
+
+    .wb_adr_i(mem_adr_i),
+    .wb_dat_i(mem_dat_i),
+    .wb_sel_i(mem_sel_i),
+    .wb_we_i(mem_we_i),
+    .wb_cyc_i(mem_cyc_i),
+
+    .wb_stb_i(mem_stb_i),
+    .wb_ack_o(mem_ack_o),
+    .wb_dat_o(mem_dat_o)
+  );
+
+  // Wishbone GPIO slave.
+  wire [31:0] gpio_adr_i;
+  wire [31:0] gpio_dat_i;
+  wire [3:0]  gpio_sel_i;
+  wire gpio_we_i;
+  wire gpio_cyc_i;
+  wire gpio_stb_i;
+  wire gpio_ack_o;
+  wire [31:0] gpio_dat_o;
+
+  gpio32_wb gpio (
+    .wb_clk_i(wb_clk_i),
+    .wb_rst_i(wb_rst_i),
+    .wb_adr_i(gpio_adr_i),
+    .wb_dat_i(gpio_dat_i),
+    .wb_sel_i(gpio_sel_i),
+    .wb_we_i(gpio_we_i),
+    .wb_cyc_i(gpio_cyc_i),
+    .wb_stb_i(gpio_stb_i),
+    .wb_ack_o(gpio_ack_o),
+    .wb_dat_o(gpio_dat_o),
+    .gpio_in(gpio_in),
+    .gpio_out(gpio_out),
+    .gpio_oeb(gpio_oeb)
+  );
+
+  // Wishbone interconnect.
+  wb_mux_3 interconnect (
+    .wbm_adr_i(cpu_adr_o),
+    .wbm_dat_i(cpu_dat_o),
+    .wbm_dat_o(cpu_dat_i),
+    .wbm_we_i(cpu_we_o),
+    .wbm_sel_i(cpu_sel_o),
+    .wbm_stb_i(cpu_stb_o),
+    .wbm_ack_o(cpu_ack_i),
+    .wbm_err_o(),
+    .wbm_rty_o(),
+    .wbm_cyc_i(cpu_cyc_o),
+
+    .wbs0_adr_o(shared_adr_o),
+    .wbs0_dat_i(shared_dat_i),
+    .wbs0_dat_o(shared_dat_o),
+    .wbs0_we_o(shared_we_o),
+    .wbs0_sel_o(shared_sel_o),
+    .wbs0_stb_o(shared_stb_o),
+    .wbs0_ack_i(shared_ack_i),
+    .wbs0_err_i(),
+    .wbs0_rty_i(),
+    .wbs0_cyc_o(shared_cyc_o),
+    .wbs0_addr(SHARED_BASE_ADDR),
+    .wbs0_addr_msk(SHARED_ADDR_MASK),
+
+    .wbs1_adr_o(mem_adr_i),
+    .wbs1_dat_i(mem_dat_o),
+    .wbs1_dat_o(mem_dat_i),
+    .wbs1_we_o(mem_we_i),
+    .wbs1_sel_o(mem_sel_i),
+    .wbs1_stb_o(mem_stb_i),
+    .wbs1_ack_i(mem_ack_o),
+    .wbs1_err_i(),
+    .wbs1_rty_i(),
+    .wbs1_cyc_o(mem_cyc_i),
+    .wbs1_addr(CCM_BASE_ADDR),
+    .wbs1_addr_msk(CCM_ADDR_MASK),
+
+    .wbs2_adr_o(gpio_adr_i),
+    .wbs2_dat_i(gpio_dat_o),
+    .wbs2_dat_o(gpio_dat_i),
+    .wbs2_we_o(gpio_we_i),
+    .wbs2_sel_o(gpio_sel_i),
+    .wbs2_stb_o(gpio_stb_i),
+    .wbs2_ack_i(gpio_ack_o),
+    .wbs2_err_i(),
+    .wbs2_rty_i(),
+    .wbs2_cyc_o(gpio_cyc_i),
+    .wbs2_addr(GPIO_BASE_ADDR),
+    .wbs2_addr_msk(GPIO_ADDR_MASK)
+  );
+
+endmodule // module rv_core
+
+// Implementation note:
+// Replace the following two modules with wrappers for your SRAM cells.
+
+module mgmt_soc_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
diff --git a/verilog/rtl/softshell/rtl/softshell_top.v b/verilog/rtl/softshell/rtl/softshell_top.v
new file mode 100644
index 0000000..33f7d64
--- /dev/null
+++ b/verilog/rtl/softshell/rtl/softshell_top.v
@@ -0,0 +1,722 @@
+// Softshell Top.
+//
+// SPDX-FileCopyrightText: (c) 2020 Harrison Pham <harrison@harrisonpham.com>
+// SPDX-License-Identifier: Apache-2.0
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Pads:
+// io[37:6] - Mapped to 32-bit pinmux (gpios, flexio, uart)
+// io[8] - Flash CSB
+// io[9] - Flash CLK
+// io[10] - Flash DIO0
+// io[11] - Flash DIO1
+// io[12] - Flash DIO2
+// io[13] - Flash DIO3
+//
+// LA:
+// la_data_in[0] - Wishbone reset (also resets CPUs)
+// la_data_in[1] - CPU0 reset
+// la_data_in[2] - CPU1 reset
+// la_data_in[3] - CPU2 reset
+// la_data_in[4] - CPU3 reset
+//
+// la_data_out[31:0] - GPIO out
+// la_data_out[63:32] - GPIO in
+
+// `include "third_party/verilog-wishbone/rtl/wb_arbiter_5.v"
+// `include "third_party/verilog-wishbone/rtl/arbiter.v"
+// `include "third_party/verilog-wishbone/rtl/priority_encoder.v"
+// `include "third_party/verilog-wishbone/rtl/wb_mux_3.v"
+// `include "third_party/verilog-wishbone/rtl/wb_mux_4.v"
+// `include "rv_core.v"
+// `include "third_party/picorv32_wb/mem_ff_wb.v"
+// `include "third_party/picorv32_wb/simpleuart.v"
+// `include "third_party/picorv32_wb/spimemio.v"
+
+// Total shared memory in 32-bit words.
+`define SHARED_MEM_WORDS 512
+
+// Number of CPU cores.
+// TODO(hdpham): Make this less terrible and dangerous to use.
+`define NUM_CPUS 3
+`define HAS_CPU3
+// `define HAS_CPU4
+
+module softshell_top (
+`ifdef USE_POWER_PINS
+  inout vdda1,  // User area 1 3.3V supply
+  inout vdda2,  // User area 2 3.3V supply
+  inout vssa1,  // User area 1 analog ground
+  inout vssa2,  // User area 2 analog ground
+  inout vccd1,  // User area 1 1.8V supply
+  inout vccd2,  // User area 2 1.8v supply
+  inout vssd1,  // User area 1 digital ground
+  inout vssd2,  // User area 2 digital ground
+`endif
+  // Wishbone Slave ports (WB MI A)
+  input wb_clk_i,
+  input wb_rst_i,
+  input wbs_stb_i,
+  input wbs_cyc_i,
+  input wbs_we_i,
+  input [3:0] wbs_sel_i,
+  input [31:0] wbs_dat_i,
+  input [31:0] wbs_adr_i,
+  output wbs_ack_o,
+  output [31:0] wbs_dat_o,
+
+  // Logic Analyzer Signals
+  input  [127:0] la_data_in,
+  output [127:0] la_data_out,
+  input  [127:0] la_oen,
+
+  // IOs
+  input  [`MPRJ_IO_PADS-1:0] io_in,
+  output [`MPRJ_IO_PADS-1:0] io_out,
+  output [`MPRJ_IO_PADS-1:0] io_oeb
+);
+
+  // Softshell base address (used for filtering addresses from Caravel).
+  parameter SOFTSHELL_MASK    = 32'hff00_0000;
+  parameter SOFTSHELL_ADDR    = 32'h3000_0000;
+
+  // Slave base addresses.
+  parameter SHARED_RAM_MASK   = 32'hfff0_0000;
+  parameter SHARED_RAM_ADDR   = 32'h3000_0000;
+
+  parameter SHARED_FLASH_MASK = 32'hfff0_0000;
+  parameter SHARED_FLASH_ADDR = 32'h3040_0000;
+
+  parameter FLASH_CONFIG_MASK = 32'hffff_0000;
+  parameter FLASH_CONFIG_ADDR = 32'h3080_0000;
+  parameter PINMUX_ADDR_MASK  = 32'hffff_0000;
+  parameter PINMUX_BASE_ADDR  = 32'h3081_0000;
+  parameter UART0_ADDR_MASK   = 32'hffff_0000;
+  parameter UART0_BASE_ADDR   = 32'h3082_0000;
+
+  // wire clk;
+  // wire resetb;
+  // assign clk = wb_clk_i;
+  // assign resetb = ~wb_rst_i;
+
+  // // Use a GPIO as a clock source just in case clocking through the wrapper
+  // // isn't flexible enough. This is pretty nasty, but hopefully with enough
+  // // muxing options we'll be okay.
+  // // TODO(harrisonpham): Instantiate proper clock buffer / glitchless mux.
+  // wire clk_ext;
+  // reg clk_muxed;
+
+  // wire [1:0] clk_sel;
+  // reg clk_ext_div2;
+  // assign clk_sel = la_data_in[1:0];
+  // assign clk_ext = io_in[`MPRJ_IO_PADS-1];
+
+  // // Reset is not synchronized! Be careful when releasing reset
+  // // (do it after clock is stable).
+  // // TODO(harrisonpham): Synchronize reset to clk_muxed domain.
+  // wire resetb_muxed;
+  // assign resetb_muxed = resetb & la_data_in[2];
+
+  // always @(posedge clk_ext) begin
+  //   if (!resetb) begin
+  //     clk_ext_div2 <= 1'b0;
+  //   end else begin
+  //     clk_ext_div2 <= ~clk_ext_div2;
+  //   end
+  // end
+
+  // always @* begin
+  //   case (clk_sel)
+  //   2'b00: clk_muxed = clk;
+  //   2'b01: clk_muxed = clk_ext;
+  //   2'b10: clk_muxed = clk_ext_div2;
+  //   2'b11: clk_muxed = 1'b0;
+  //   endcase
+  // end
+
+  // Async reset generator.
+  // Resets from either a wishbone reset or a logic analyzer reset request.
+  reg [2:0] reset_pipe;
+  wire reset_in;
+  wire reset;
+  assign reset_in = wb_rst_i | la_data_in[0];
+  assign reset = reset_pipe[2];
+  always @(posedge wb_clk_i or posedge reset_in) begin
+    if (reset_in) begin
+      reset_pipe <= 3'b111;
+    end else begin
+      reset_pipe <= {reset_pipe[1:0], 1'b0};
+    end
+  end
+
+  // CPU signals.
+  wire [31:0] wbm_adr_i [`NUM_CPUS-1:0];
+  wire [31:0] wbm_dat_i [`NUM_CPUS-1:0];
+  wire [31:0] wbm_dat_o [`NUM_CPUS-1:0];
+  wire        wbm_we_i  [`NUM_CPUS-1:0];
+  wire [3:0]  wbm_sel_i [`NUM_CPUS-1:0];
+  wire        wbm_stb_i [`NUM_CPUS-1:0];
+  wire        wbm_ack_o [`NUM_CPUS-1:0];
+  wire        wbm_err_o [`NUM_CPUS-1:0];
+  wire        wbm_rty_o [`NUM_CPUS-1:0];
+  wire        wbm_cyc_i [`NUM_CPUS-1:0];
+
+  wire [31:0] gpio_in  [`NUM_CPUS-1:0];
+  wire [31:0] gpio_out [`NUM_CPUS-1:0];
+  wire [31:0] gpio_oeb [`NUM_CPUS-1:0];
+
+  wire [7:0]  flexio_in  [`NUM_CPUS-1:0];
+  wire [7:0]  flexio_out [`NUM_CPUS-1:0];
+  wire [7:0]  flexio_oeb [`NUM_CPUS-1:0];
+
+  wire cpu_reset[`NUM_CPUS-1:0];
+
+  // Generate the CPUs
+  genvar i;
+  generate
+    for (i = 0; i < `NUM_CPUS; i = i + 1) begin : cpus
+      assign cpu_reset[i] = la_data_in[i + 1];
+
+      rv_core #(
+        // TODO(hdpham): Resize this once the design fits.
+        .MEM_WORDS(32),
+        // Boot from flash.
+        // TODO(hdpham): Should we switch this back to RAM?
+        .PROGADDR_RESET(SHARED_FLASH_ADDR | ((i + 1) << 16)),
+        .CORE_ID(i)
+      ) core (
+        .wb_clk_i(wb_clk_i),
+        .wb_rst_i(reset | cpu_reset[i]),
+
+        .shared_ack_i(wbm_ack_o[i]),
+        .shared_dat_i(wbm_dat_o[i]),
+        .shared_cyc_o(wbm_cyc_i[i]),
+        .shared_stb_o(wbm_stb_i[i]),
+        .shared_we_o(wbm_we_i[i]),
+        .shared_sel_o(wbm_sel_i[i]),
+        .shared_adr_o(wbm_adr_i[i]),
+        .shared_dat_o(wbm_dat_i[i]),
+
+        .gpio_in(gpio_in[i]),
+        .gpio_out(gpio_out[i]),
+        .gpio_oeb(gpio_oeb[i]),
+
+        .flexio_in(flexio_in[i]),
+        .flexio_out(flexio_out[i]),
+        .flexio_oeb(flexio_oeb[i])
+      );
+    end
+  endgenerate
+
+  // Shared memory.
+  wire [31:0] mem_adr_i;
+  wire [31:0] mem_dat_i;
+  wire [3:0] mem_sel_i;
+  wire mem_we_i;
+  wire mem_cyc_i;
+  wire mem_stb_i;
+  wire mem_ack_o;
+  wire [31:0] mem_dat_o;
+
+  mem_ff_wb #(
+    .MEM_WORDS(`SHARED_MEM_WORDS)
+  ) shared_mem (
+    .wb_clk_i(wb_clk_i),
+    .wb_rst_i(reset),
+
+    .wb_adr_i(mem_adr_i),
+    .wb_dat_i(mem_dat_i),
+    .wb_sel_i(mem_sel_i),
+    .wb_we_i(mem_we_i),
+    .wb_cyc_i(mem_cyc_i),
+
+    .wb_stb_i(mem_stb_i),
+    .wb_ack_o(mem_ack_o),
+    .wb_dat_o(mem_dat_o)
+  );
+
+  // Pinmux.
+  wire [31:0] pinmux_adr_i;
+  wire [31:0] pinmux_dat_i;
+  wire [3:0] pinmux_sel_i;
+  wire pinmux_cyc_i;
+  wire pinmux_stb_i;
+  wire pinmux_we_i;
+  wire [31:0] pinmux_dat_o;
+  wire pinmux_ack_o;
+
+  wire [31:0] pinmux_gpio_in;
+  wire [31:0] pinmux_gpio_out;
+  wire [31:0] pinmux_gpio_oeb;
+
+  pinmux #(
+    .NUM_INPUTS(1),
+    .NUM_OUTPUTS(1 + `NUM_CPUS * 8),
+    .NUM_GPIOS(32)
+  ) pinmux (
+    .wb_clk_i(wb_clk_i),
+    .wb_rst_i(reset),
+
+    .wb_adr_i(pinmux_adr_i),
+    .wb_dat_i(pinmux_dat_i),
+    .wb_sel_i(pinmux_sel_i),
+    .wb_cyc_i(pinmux_cyc_i),
+    .wb_stb_i(pinmux_stb_i),
+    .wb_we_i(pinmux_we_i),
+
+    .wb_dat_o(pinmux_dat_o),
+    .wb_ack_o(pinmux_ack_o),
+
+    .gpio_in(pinmux_gpio_in),
+    .gpio_out(pinmux_gpio_out),
+    .gpio_oeb(pinmux_gpio_oeb),
+
+    .peripheral_in({uart_rx}),
+    .peripheral_out({
+`ifdef HAS_CPU4
+                      flexio_out[3],
+`endif
+`ifdef HAS_CPU3
+                      flexio_out[2],
+`endif
+                      flexio_out[1],
+                      flexio_out[0],
+                      uart_tx
+                    }),
+    .peripheral_oeb({
+`ifdef HAS_CPU4
+                      flexio_oeb[3],
+`endif
+`ifdef HAS_CPU3
+                      flexio_oeb[2],
+`endif
+                      flexio_oeb[1],
+                      flexio_oeb[0],
+                      1'b0
+                    })
+  );
+
+  // Uarts.
+  wire [31:0] uart_adr_i;
+  wire [31:0] uart_dat_i;
+  wire [3:0] uart_sel_i;
+  wire uart_we_i;
+  wire uart_cyc_i;
+  wire uart_stb_i;
+  wire uart_ack_o;
+  wire [31:0] uart_dat_o;
+
+  wire uart_enabled;
+  wire uart_tx;
+  wire uart_rx;
+
+  simpleuart_wb  #(
+    .BASE_ADR(UART0_BASE_ADDR)
+  ) uart0 (
+    .wb_clk_i(wb_clk_i),
+    .wb_rst_i(reset),
+
+    .wb_adr_i(uart_adr_i),
+    .wb_dat_i(uart_dat_i),
+    .wb_sel_i(uart_sel_i),
+    .wb_we_i(uart_we_i),
+    .wb_cyc_i(uart_cyc_i),
+
+    .wb_stb_i(uart_stb_i),
+    .wb_ack_o(uart_ack_o),
+    .wb_dat_o(uart_dat_o),
+
+    .uart_enabled(uart_enabled),
+    .ser_tx(uart_tx),
+    .ser_rx(uart_rx)
+  );
+
+  // Flash.
+  wire [31:0] flash_adr_i;
+  wire [31:0] flash_dat_i;
+  wire [3:0] flash_sel_i;
+  wire flash_we_i;
+  wire flash_cyc_i;
+  wire flash_stb_i;
+  wire flash_ack_o;
+  wire [31:0] flash_dat_o;
+
+  wire flash_cfg_we_i;
+  wire flash_cfg_cyc_i;
+  wire flash_cfg_stb_i;
+  wire flash_cfg_ack_o;
+  wire [31:0] flash_cfg_dat_o;
+
+  wire flash_csb_oeb;
+  wire flash_clk_oeb;
+  wire flash_io0_oeb;
+  wire flash_io1_oeb;
+  wire flash_io2_oeb;
+  wire flash_io3_oeb;
+  wire flash_csb;
+  wire flash_clk;
+  wire flash_io0_do;
+  wire flash_io1_do;
+  wire flash_io2_do;
+  wire flash_io3_do;
+  wire flash_io0_di;
+  wire flash_io1_di;
+  wire flash_io2_di;
+  wire flash_io3_di;
+
+  // Mask off the unused upper flash address bits.
+  wire [31:0] flash_adr_i_masked;
+  assign flash_adr_i_masked = flash_adr_i & ~SHARED_FLASH_MASK;
+
+  spimemio_wb flash (
+    .wb_clk_i(wb_clk_i),
+    .wb_rst_i(reset),
+
+    .wb_adr_i(flash_adr_i_masked),
+    .wb_dat_i(flash_dat_i),
+    .wb_sel_i(flash_sel_i),
+    .wb_we_i(flash_we_i | flash_cfg_we_i),
+    .wb_cyc_i(flash_cyc_i | flash_cfg_cyc_i),
+
+    .wb_flash_stb_i(flash_stb_i),
+    .wb_cfg_stb_i(flash_cfg_stb_i),
+
+    .wb_flash_ack_o(flash_ack_o),
+    .wb_cfg_ack_o(flash_cfg_ack_o),
+
+    .wb_flash_dat_o(flash_dat_o),
+    .wb_cfg_dat_o(flash_cfg_dat_o),
+
+    .pass_thru(1'b0),
+    .pass_thru_csb(1'b0),
+    .pass_thru_sck(1'b0),
+    .pass_thru_sdi(1'b0),
+    .pass_thru_sdo(),
+
+    .flash_csb(flash_csb),
+    .flash_clk(flash_clk),
+
+    .flash_csb_oeb(flash_csb_oeb),
+    .flash_clk_oeb(flash_clk_oeb),
+
+    .flash_io0_oeb(flash_io0_oeb),
+    .flash_io1_oeb(flash_io1_oeb),
+    .flash_io2_oeb(flash_io2_oeb),
+    .flash_io3_oeb(flash_io3_oeb),
+
+    .flash_csb_ieb(),
+    .flash_clk_ieb(),
+
+    .flash_io0_ieb(),
+    .flash_io1_ieb(),
+    .flash_io2_ieb(),
+    .flash_io3_ieb(),
+
+    .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)
+  );
+
+  // Interconnect bus.
+  wire [31:0] mux_adr_i;
+  wire [31:0] mux_dat_i;
+  wire [3:0] mux_sel_i;
+  wire mux_we_i;
+  wire mux_cyc_i;
+  wire mux_stb_i;
+  wire mux_ack_o;
+  wire [31:0] mux_dat_o;
+
+  // Filter addresses from Caravel since we want to be absolutely sure it is
+  // selecting us before letting it access the arbiter.  This is mostly needed
+  // because the wb_intercon.v implementation in Caravel doesn't corrently
+  // filter the wb_cyc_i signal to slaves.
+  wire wbs_addr_sel;
+  assign wbs_addr_sel = (wbs_adr_i & SOFTSHELL_MASK) == SOFTSHELL_ADDR;
+
+  // Round-robin arbiter for shared resources.
+`ifdef HAS_CPU4
+  wb_arbiter_5 #(
+`elsif HAS_CPU3
+  wb_arbiter_4 #(
+`else
+  wb_arbiter_3 #(
+`endif
+    .ARB_TYPE("ROUND_ROBIN")
+  ) arbiter (
+    .clk(wb_clk_i),
+    .rst(reset),
+
+    .wbm0_adr_i(wbs_adr_i),
+    .wbm0_dat_i(wbs_dat_i),
+    .wbm0_dat_o(wbs_dat_o),
+    .wbm0_we_i(wbs_we_i & wbs_addr_sel),
+    .wbm0_sel_i(wbs_sel_i),
+    .wbm0_stb_i(wbs_stb_i & wbs_addr_sel),
+    .wbm0_ack_o(wbs_ack_o),
+    .wbm0_err_o(),
+    .wbm0_rty_o(),
+    .wbm0_cyc_i(wbs_cyc_i & wbs_addr_sel),
+
+    .wbm1_adr_i(wbm_adr_i[0]),
+    .wbm1_dat_i(wbm_dat_i[0]),
+    .wbm1_dat_o(wbm_dat_o[0]),
+    .wbm1_we_i(wbm_we_i[0]),
+    .wbm1_sel_i(wbm_sel_i[0]),
+    .wbm1_stb_i(wbm_stb_i[0]),
+    .wbm1_ack_o(wbm_ack_o[0]),
+    .wbm1_err_o(wbm_err_o[0]),
+    .wbm1_rty_o(wbm_rty_o[0]),
+    .wbm1_cyc_i(wbm_cyc_i[0]),
+
+    .wbm2_adr_i(wbm_adr_i[1]),
+    .wbm2_dat_i(wbm_dat_i[1]),
+    .wbm2_dat_o(wbm_dat_o[1]),
+    .wbm2_we_i(wbm_we_i[1]),
+    .wbm2_sel_i(wbm_sel_i[1]),
+    .wbm2_stb_i(wbm_stb_i[1]),
+    .wbm2_ack_o(wbm_ack_o[1]),
+    .wbm2_err_o(wbm_err_o[1]),
+    .wbm2_rty_o(wbm_rty_o[1]),
+    .wbm2_cyc_i(wbm_cyc_i[1]),
+
+`ifdef HAS_CPU3
+    .wbm3_adr_i(wbm_adr_i[2]),
+    .wbm3_dat_i(wbm_dat_i[2]),
+    .wbm3_dat_o(wbm_dat_o[2]),
+    .wbm3_we_i(wbm_we_i[2]),
+    .wbm3_sel_i(wbm_sel_i[2]),
+    .wbm3_stb_i(wbm_stb_i[2]),
+    .wbm3_ack_o(wbm_ack_o[2]),
+    .wbm3_err_o(wbm_err_o[2]),
+    .wbm3_rty_o(wbm_rty_o[2]),
+    .wbm3_cyc_i(wbm_cyc_i[2]),
+`endif
+
+`ifdef HAS_CPU4
+    .wbm4_adr_i(wbm_adr_i[3]),
+    .wbm4_dat_i(wbm_dat_i[3]),
+    .wbm4_dat_o(wbm_dat_o[3]),
+    .wbm4_we_i(wbm_we_i[3]),
+    .wbm4_sel_i(wbm_sel_i[3]),
+    .wbm4_stb_i(wbm_stb_i[3]),
+    .wbm4_ack_o(wbm_ack_o[3]),
+    .wbm4_err_o(wbm_err_o[3]),
+    .wbm4_rty_o(wbm_rty_o[3]),
+    .wbm4_cyc_i(wbm_cyc_i[3]),
+`endif
+
+    .wbs_adr_o(mux_adr_i),
+    .wbs_dat_i(mux_dat_o),
+    .wbs_dat_o(mux_dat_i),
+    .wbs_we_o(mux_we_i),
+    .wbs_sel_o(mux_sel_i),
+    .wbs_stb_o(mux_stb_i),
+    .wbs_ack_i(mux_ack_o),
+    .wbs_err_i(1'b0),
+    .wbs_rty_i(1'b0),
+    .wbs_cyc_o(mux_cyc_i)
+  );
+
+  // Wishbone slave mux for shared memory and peripherals.
+  wb_mux_5 interconnect (
+    .wbm_adr_i(mux_adr_i),
+    .wbm_dat_i(mux_dat_i),
+    .wbm_dat_o(mux_dat_o),
+    .wbm_we_i(mux_we_i),
+    .wbm_sel_i(mux_sel_i),
+    .wbm_stb_i(mux_stb_i),
+    .wbm_ack_o(mux_ack_o),
+    .wbm_err_o(),
+    .wbm_rty_o(),
+    .wbm_cyc_i(mux_cyc_i),
+
+    .wbs0_adr_o(mem_adr_i),
+    .wbs0_dat_i(mem_dat_o),
+    .wbs0_dat_o(mem_dat_i),
+    .wbs0_we_o(mem_we_i),
+    .wbs0_sel_o(mem_sel_i),
+    .wbs0_stb_o(mem_stb_i),
+    .wbs0_ack_i(mem_ack_o),
+    .wbs0_err_i(1'b0),
+    .wbs0_rty_i(1'b0),
+    .wbs0_cyc_o(mem_cyc_i),
+    .wbs0_addr(SHARED_RAM_ADDR),
+    .wbs0_addr_msk(SHARED_RAM_MASK),
+
+    .wbs1_adr_o(uart_adr_i),
+    .wbs1_dat_i(uart_dat_o),
+    .wbs1_dat_o(uart_dat_i),
+    .wbs1_we_o(uart_we_i),
+    .wbs1_sel_o(uart_sel_i),
+    .wbs1_stb_o(uart_stb_i),
+    .wbs1_ack_i(uart_ack_o),
+    .wbs1_err_i(1'b0),
+    .wbs1_rty_i(1'b0),
+    .wbs1_cyc_o(uart_cyc_i),
+    .wbs1_addr(UART0_BASE_ADDR),
+    .wbs1_addr_msk(UART0_ADDR_MASK),
+
+    .wbs2_adr_o(flash_adr_i),
+    .wbs2_dat_i(flash_dat_o),
+    .wbs2_dat_o(flash_dat_i),
+    .wbs2_we_o(flash_we_i),
+    .wbs2_sel_o(flash_sel_i),
+    .wbs2_stb_o(flash_stb_i),
+    .wbs2_ack_i(flash_ack_o),
+    .wbs2_err_i(1'b0),
+    .wbs2_rty_i(1'b0),
+    .wbs2_cyc_o(flash_cyc_i),
+    .wbs2_addr(SHARED_FLASH_ADDR),
+    .wbs2_addr_msk(SHARED_FLASH_MASK),
+
+    .wbs3_adr_o(),
+    .wbs3_dat_i(flash_cfg_dat_o),
+    .wbs3_dat_o(),
+    .wbs3_we_o(flash_cfg_we_i),
+    .wbs3_sel_o(),
+    .wbs3_stb_o(flash_cfg_stb_i),
+    .wbs3_ack_i(flash_cfg_ack_o),
+    .wbs3_err_i(1'b0),
+    .wbs3_rty_i(1'b0),
+    .wbs3_cyc_o(flash_cfg_cyc_i),
+    .wbs3_addr(FLASH_CONFIG_ADDR),
+    .wbs3_addr_msk(FLASH_CONFIG_MASK),
+
+    .wbs4_adr_o(pinmux_adr_i),
+    .wbs4_dat_i(pinmux_dat_o),
+    .wbs4_dat_o(pinmux_dat_i),
+    .wbs4_we_o(pinmux_we_i),
+    .wbs4_sel_o(pinmux_sel_i),
+    .wbs4_stb_o(pinmux_stb_i),
+    .wbs4_ack_i(pinmux_ack_o),
+    .wbs4_err_i(1'b0),
+    .wbs4_rty_i(1'b0),
+    .wbs4_cyc_o(pinmux_cyc_i),
+    .wbs4_addr(PINMUX_BASE_ADDR),
+    .wbs4_addr_msk(PINMUX_ADDR_MASK)
+  );
+
+  // Connect up GPIOs.
+  wire [31:0] io_in_internal;
+
+  // Internal wires for input ports.
+  assign io_in_internal = io_in[37:6];
+
+  assign pinmux_gpio_in = io_in_internal;
+
+  assign gpio_in[0] = io_in_internal;
+  assign gpio_in[1] = io_in_internal;
+`ifdef HAS_CPU3
+  assign gpio_in[2] = io_in_internal;
+`endif
+`ifdef HAS_CPU4
+  assign gpio_in[3] = io_in_internal;
+`endif
+  // assign uart_rx = io_in_internal[24];
+
+  assign flash_io0_di = io_in_internal[10-6];
+  assign flash_io1_di = io_in_internal[11-6];
+  assign flash_io2_di = io_in_internal[12-6];
+  assign flash_io3_di = io_in_internal[13-6];
+
+  assign io_out[5:0] = 6'b0;
+  assign io_oeb[5:0] = {6{1'b1}};
+
+  // TODO(hdpham): Add ability to disable or mux flash pins.
+  // TODO(hdpham): Add pin mux to remap UART and other peripheral pins.
+
+  // Internal wires for output ports to workaround LVS errors.
+  wire [31:0] io_out_internal;
+  wire [31:0] io_oeb_internal;
+
+  assign io_out_internal = gpio_out[0] |
+                           gpio_out[1] |
+`ifdef HAS_CPU3
+                           gpio_out[2] |
+`endif
+`ifdef HAS_CPU4
+                           gpio_out[3] |
+`endif
+                           {24'b0, flash_io3_do, flash_io2_do,
+                            flash_io1_do, flash_io0_do, flash_clk,
+                            flash_csb, 2'b0} |
+                           pinmux_gpio_out;
+                           //{6'b0, uart_tx, 25'b0};
+  assign io_oeb_internal = gpio_oeb[0] &
+                           gpio_oeb[1] &
+`ifdef HAS_CPU3
+                           gpio_oeb[2] &
+`endif
+`ifdef HAS_CPU4
+                           gpio_oeb[3] &
+`endif
+                           {{24{1'b1}}, flash_io3_oeb, flash_io2_oeb,
+                            flash_io1_oeb, flash_io0_oeb, flash_clk_oeb,
+                            flash_csb_oeb, 2'b11} &
+                           pinmux_gpio_oeb;
+                           //~{6'b0, uart_enabled, 25'b0};
+
+  wire [31:0] io_out_internal_buf;
+  wire [31:0] io_oeb_internal_buf;
+
+//   // Hack to manually insert buffer so LVS is happy.
+//   // TODO(hdpham): Wrap this to make non-technology specific.
+//   generate
+//     for (i = 0; i < 32; i = i + 1) begin
+//       sky130_fd_sc_hd__buf_8 out_buf (
+// `ifdef SIM
+//         // TODO(hdpham): Figure out why the behavioral models don't work.
+//         .VPWR(1'b1),
+//         .VGND(1'b0),
+//         .VPB(1'b1),
+//         .VNB(1'b0),
+// `endif
+//         .X(io_out_internal_buf[i]),
+//         .A(io_out_internal[i])
+//       );
+
+//       sky130_fd_sc_hd__buf_8 oeb_buf (
+// `ifdef SIM
+//         .VPWR(1'b1),
+//         .VGND(1'b0),
+//         .VPB(1'b1),
+//         .VNB(1'b0),
+// `endif
+//         .X(io_oeb_internal_buf[i]),
+//         .A(io_oeb_internal[i])
+//       );
+//     end
+//   endgenerate
+
+  assign io_out_internal_buf = io_out_internal;
+  assign io_oeb_internal_buf = io_oeb_internal;
+
+  assign io_out[37:6] = io_out_internal_buf;
+  assign io_oeb[37:6] = io_oeb_internal_buf;
+
+  assign la_data_out[31:0] = io_out_internal_buf;
+  assign la_data_out[63:32] = io_oeb_internal_buf;
+
+  // Tieoff unused.
+  // TODO(hdpham): Tie this to useful things.
+  assign la_data_out[127:64] = 64'b0;
+
+endmodule // module softshell_top
diff --git a/verilog/rtl/softshell/third_party/DFFRAM/models/DFFRAM.v b/verilog/rtl/softshell/third_party/DFFRAM/models/DFFRAM.v
new file mode 100644
index 0000000..c6af2a6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/DFFRAM/models/DFFRAM.v
@@ -0,0 +1,161 @@
+`default_nettype none
+`ifndef USE_CUSTOM_DFFRAM
+
+module DFFRAM(
+`ifdef USE_POWER_PINS
+    input VPWR,
+    input VGND,
+`endif
+    input CLK,
+    input [3:0] WE,
+    input EN,
+    input [31:0] Di,
+    output reg [31:0] Do,
+    input [7:0] A
+);
+  
+
+reg [31:0] mem [0:`MEM_WORDS-1];
+
+always @(posedge CLK) begin
+    if (EN == 1'b1) begin
+        Do <= mem[A];
+        if (WE[0]) mem[A][ 7: 0] <= Di[ 7: 0];
+        if (WE[1]) mem[A][15: 8] <= Di[15: 8];
+        if (WE[2]) mem[A][23:16] <= Di[23:16];
+        if (WE[3]) mem[A][31:24] <= Di[31:24];
+    end
+end
+endmodule
+
+`else
+
+module DFFRAM #( parameter COLS=1)
+(
+`ifdef USE_POWER_PINS
+    VPWR,
+    VGND,
+`endif
+    CLK,
+    WE,
+    EN,
+    Di,
+    Do,
+    A
+);
+
+    input           CLK;
+    input   [3:0]   WE;
+    input           EN;
+    input   [31:0]  Di;
+    output  [31:0]  Do;
+    input   [7+$clog2(COLS):0]   A;
+
+`ifdef USE_POWER_PINS
+    input VPWR;
+    input VGND;
+`endif
+
+    wire [31:0]     DOUT [COLS-1:0];
+    wire [31:0]     Do_pre;
+    wire [COLS-1:0] EN_lines;
+
+    generate
+        genvar i;
+        for (i=0; i<COLS; i=i+1) begin : COLUMN
+            DFFRAM_COL4 RAMCOLS (
+                                `ifdef USE_POWER_PINS
+                                    .VPWR(VPWR),
+                                    .VGND(VGND),
+                                `endif
+                                    .CLK(CLK), 
+                                    .WE(WE), 
+                                    .EN(EN_lines[i]), 
+                                    .Di(Di), 
+                                    .Do(DOUT[i]), 
+                                    .A(A[7:0]) 
+                                );    
+        end
+        if(COLS==4) begin
+            MUX4x1_32 MUX ( 
+            `ifdef USE_POWER_PINS
+                .VPWR(VPWR),
+                .VGND(VGND),
+            `endif
+                .A0(DOUT[0]),
+                .A1(DOUT[1]),
+                .A2(DOUT[2]),
+                .A3(DOUT[3]),
+                .S(A[9:8]),
+                .X(Do_pre)
+            );
+            DEC2x4 DEC (
+            `ifdef USE_POWER_PINS
+                .VPWR(VPWR),
+                .VGND(VGND),
+            `endif 
+                .EN(EN),
+                .A(A[9:8]),
+                .SEL(EN_lines)
+            );
+        end
+        else if(COLS==2) begin
+            MUX2x1_32 MUX ( 
+            `ifdef USE_POWER_PINS
+                .VPWR(VPWR),
+                .VGND(VGND),
+            `endif 
+                .A0(DOUT[0]),
+                .A1(DOUT[1]),
+                .S(A[8]),
+                .X(Do_pre)
+            );
+            //sky130_fd_sc_hd__inv_4 DEC0 ( .Y(EN_lines[0]), .A(A[8]) );
+            //sky130_fd_sc_hd__clkbuf_4 DEC1 (.X(EN_lines[1]), .A(A[8]) );
+            DEC1x2 DEC ( 
+            `ifdef USE_POWER_PINS
+                .VPWR(VPWR),
+                .VGND(VGND),
+            `endif 
+                .EN(EN),
+                .A(A[8]),
+                .SEL(EN_lines[1:0]) 
+            );
+            
+        end
+        else begin
+            PASS MUX ( 
+            `ifdef USE_POWER_PINS
+                .VPWR(VPWR),
+                .VGND(VGND),
+            `endif 
+                .A(DOUT[0]),
+                .X(Do_pre)
+            );
+            sky130_fd_sc_hd__clkbuf_4 ENBUF (
+           `ifdef USE_POWER_PINS
+                .VPWR(VPWR),
+                .VGND(VGND),
+                .VPB(VPWR),
+                .VNB(VGND),
+            `endif 
+                .X(EN_lines[0]),
+                .A(EN)
+            );
+        end
+    endgenerate
+    
+    sky130_fd_sc_hd__clkbuf_4 DOBUF[31:0] (
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif 
+        .X(Do),
+        .A(Do_pre)
+    );
+
+endmodule
+
+`endif
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/DFFRAM/models/DFFRAMBB.v b/verilog/rtl/softshell/third_party/DFFRAM/models/DFFRAMBB.v
new file mode 100644
index 0000000..712a253
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/DFFRAM/models/DFFRAMBB.v
@@ -0,0 +1,769 @@
+`default_nettype none
+/*
+    Building blocks for DFF based RAM compiler for SKY130A 
+    BYTE        :   8 memory cells used as a building block for WORD module
+    WORD        :   32-bit memory word with select and byte-level WE
+    DEC6x64     :   2x4 Binary Decoder
+    DEC6x64     :   6x64 Binary decoder
+    MUX4x1_32   :   32-bit 4x1 MUX
+    MUX2x1_32   :   32-bit 2x1 MUX
+    SRAM64x32   :   Tri-state buffers based 64x32 DFF RAM 
+    DFFRAM_COL4 :   A single column of 4 SRAM64x32 blocks using 4x1 multiplexors
+*/
+/*
+    Author: Mohamed Shalan (mshalan@aucegypt.edu)
+*/
+
+module BYTE (
+`ifdef USE_POWER_PINS
+    input VPWR,
+    input VGND,
+`endif
+    input CLK,
+    input WE,
+    input SEL,
+    input [7:0] Di,
+    output [7:0] Do
+);
+
+    wire [7:0]  q_wire;
+    wire        we_wire;
+    wire        SEL_B;
+    wire        GCLK;
+
+    sky130_fd_sc_hd__inv_1 INV(
+     `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .Y(SEL_B),
+        .A(SEL)
+    );
+
+    sky130_fd_sc_hd__and2_1 CGAND( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .A(SEL),
+        .B(WE),
+        .X(we_wire)
+    );
+
+    sky130_fd_sc_hd__dlclkp_1 CG( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .CLK(CLK),
+        .GCLK(GCLK),
+        .GATE(we_wire) 
+    );
+
+    generate 
+        genvar i;
+        for(i=0; i<8; i=i+1) begin : BIT
+            sky130_fd_sc_hd__dfxtp_1 FF (
+            `ifdef USE_POWER_PINS
+                .VPWR(VPWR),
+                .VGND(VGND),
+                .VPB(VPWR),
+                .VNB(VGND),
+            `endif 
+                .D(Di[i]),
+                .Q(q_wire[i]),
+                .CLK(GCLK)
+            );
+
+            sky130_fd_sc_hd__ebufn_2 OBUF ( 
+            `ifdef USE_POWER_PINS
+                .VPWR(VPWR),
+                .VGND(VGND),
+                .VPB(VPWR),
+                .VNB(VGND),
+            `endif
+                .A(q_wire[i]),
+                .Z(Do[i]),
+                .TE_B(SEL_B)
+            );
+
+        end
+    endgenerate 
+
+endmodule
+
+
+module WORD32 (
+`ifdef USE_POWER_PINS
+    input VPWR,
+    input VGND,
+`endif
+    input CLK,
+    input [3:0] WE,
+    input SEL,
+    input [31:0] Di,
+    output [31:0] Do
+);
+
+    BYTE B0 (
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+    `endif 
+        .CLK(CLK), .WE(WE[0]), .SEL(SEL), .Di(Di[7:0]), .Do(Do[7:0]) );
+    
+    BYTE B1 ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR), 
+        .VGND(VGND),
+    `endif
+        .CLK(CLK), .WE(WE[1]), .SEL(SEL), .Di(Di[15:8]), .Do(Do[15:8]) );
+    
+    BYTE B2 ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+    `endif
+        .CLK(CLK), .WE(WE[2]), .SEL(SEL), .Di(Di[23:16]), .Do(Do[23:16]) );
+    
+    BYTE B3 ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+    `endif
+        .CLK(CLK), .WE(WE[3]), .SEL(SEL), .Di(Di[31:24]), .Do(Do[31:24]) );
+    
+endmodule 
+
+module DEC1x2 (
+`ifdef USE_POWER_PINS
+    input VPWR,
+    input VGND,
+`endif
+    input           EN,
+    input   [0:0]   A,
+    output  [1:0]   SEL
+);
+    sky130_fd_sc_hd__and2b_2    AND1 ( 
+     `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(SEL[0]),
+        .A_N(A),
+        .B(EN)
+    );
+
+    sky130_fd_sc_hd__and2_2     AND3 ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(SEL[1]),
+        .A(A),
+        .B(A[0])
+    );
+    
+endmodule
+
+module DEC2x4 (
+`ifdef USE_POWER_PINS
+    input VPWR,
+    input VGND,
+`endif
+    input           EN,
+    input   [1:0]   A,
+    output  [3:0]   SEL
+);
+    sky130_fd_sc_hd__nor3b_4    AND0 ( 
+     `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .Y(SEL[0]),
+        .A(A[0]),
+        .B(A[1]),
+        .C_N(EN)
+    );
+
+    sky130_fd_sc_hd__and3b_4    AND1 (
+     `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif 
+        .X(SEL[1]),
+        .A_N(A[1]),
+        .B(A[0]),
+        .C(EN) 
+    );
+
+    sky130_fd_sc_hd__and3b_4    AND2 ( 
+     `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(SEL[2]),
+        .A_N(A[0]),
+        .B(A[1]),
+        .C(EN)
+    );
+   
+    sky130_fd_sc_hd__and3_4     AND3 ( 
+     `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(SEL[3]),
+        .A(A[1]),
+        .B(A[0]),
+        .C(EN) 
+    );
+    
+endmodule
+
+module DEC3x8 (
+`ifdef USE_POWER_PINS
+    input VPWR,
+    input VGND,
+`endif
+    input           EN,
+    input [2:0]     A,
+    output [7:0]    SEL
+);
+    sky130_fd_sc_hd__nor4b_2   AND0 ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .Y(SEL[0]),
+        .A(A[0]),
+        .B(A[1]),
+        .C(A[2]),
+        .D_N(EN)
+    ); // 000
+
+    sky130_fd_sc_hd__and4bb_2   AND1 ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(SEL[1]),
+        .A_N(A[2]),
+        .B_N(A[1]),
+        .C(A[0]),
+        .D(EN)
+    ); // 001
+
+    sky130_fd_sc_hd__and4bb_2   AND2 ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(SEL[2]),
+        .A_N(A[2]),
+        .B_N(A[0]),
+        .C(A[1]),
+        .D(EN) 
+    ); // 010
+
+    sky130_fd_sc_hd__and4b_2    AND3 ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(SEL[3]),
+        .A_N(A[2]),
+        .B(A[1]),
+        .C(A[0]),
+        .D(EN) 
+    );   // 011
+
+    sky130_fd_sc_hd__and4bb_2   AND4 ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(SEL[4]),
+        .A_N(A[0]),
+        .B_N(A[1]),
+        .C(A[2]),
+        .D(EN) 
+    ); // 100
+
+    sky130_fd_sc_hd__and4b_2    AND5 ( 
+     `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(SEL[5]),
+        .A_N(A[1]),
+        .B(A[0]),
+        .C(A[2]),
+        .D(EN)
+    );   // 101
+
+    sky130_fd_sc_hd__and4b_2    AND6 ( 
+     `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(SEL[6]),
+        .A_N(A[0]),
+        .B(A[1]), 
+        .C(A[2]),
+        .D(EN) 
+    );   // 110
+
+    sky130_fd_sc_hd__and4_2     AND7 ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(SEL[7]),
+        .A(A[0]),
+        .B(A[1]),
+        .C(A[2]), 
+        .D(EN)
+    ); // 111
+endmodule
+
+
+module DEC6x64 (
+`ifdef USE_POWER_PINS
+    input VPWR,
+    input VGND,
+`endif
+    input           EN,
+    input   [5:0]   A,
+    output  [63:0] SEL
+);
+    wire [7:0] SEL0_w ;
+    wire [2:0] A_buf;
+    
+    DEC3x8 DEC_L0 ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+    `endif
+        .EN(EN),
+        .A(A[5:3]),
+        .SEL(SEL0_w)
+    );
+
+    sky130_fd_sc_hd__clkbuf_16 ABUF[2:0] (
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(A_buf),
+        .A(A[2:0])
+    );
+
+    generate
+        genvar i;
+        for(i=0; i<8; i=i+1) begin : DEC_L1
+            DEC3x8 U ( 
+            `ifdef USE_POWER_PINS
+                .VPWR(VPWR),
+                .VGND(VGND),
+            `endif
+                .EN(SEL0_w[i]),
+                .A(A_buf),
+                .SEL(SEL[7+8*i: 8*i])
+            );
+        end
+    endgenerate
+endmodule
+
+module MUX2x1_32(
+`ifdef USE_POWER_PINS
+    input VPWR,
+    input VGND,
+`endif
+    input   [31:0]      A0, A1,
+    input   [0:0]       S,
+    output  [31:0]      X
+);
+    sky130_fd_sc_hd__mux2_1 MUX[31:0] (
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .A0(A0),
+        .A1(A1),
+        .S(S[0]),
+        .X(X)
+    );
+
+endmodule
+
+module MUX4x1_32(
+`ifdef USE_POWER_PINS
+    input VPWR,
+    input VGND,
+`endif
+    input   [31:0]      A0, A1, A2, A3,
+    input   [1:0]       S,
+    output  [31:0]      X
+);
+    sky130_fd_sc_hd__mux4_1 MUX[31:0] (
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .A0(A0), 
+        .A1(A1),
+        .A2(A2),
+        .A3(A3),
+        .S0(S[0]),
+        .S1(S[1]),
+        .X(X)
+    );
+endmodule
+
+module PASS (
+`ifdef USE_POWER_PINS
+    input VPWR,
+    input VGND,
+`endif
+    input [31:0] A,
+    output [31:0] X
+);
+    assign X = A;
+endmodule
+
+module SRAM64x32(
+`ifdef USE_POWER_PINS
+    input VPWR,
+    input VGND,
+`endif
+    input CLK,
+    input [3:0] WE,
+    input EN,
+    input [31:0] Di,
+    output [31:0] Do,
+    input [5:0] A
+);
+
+    wire [63:0]     SEL;
+    wire [31:0]     Do_pre;
+    wire [31:0]     Di_buf;
+    wire            CLK_buf;
+    wire [3:0]      WE_buf;
+
+    sky130_fd_sc_hd__clkbuf_16 CLKBUF (
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(CLK_buf),
+        .A(CLK)
+    );
+    
+    sky130_fd_sc_hd__clkbuf_16 WEBUF[3:0] (
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(WE_buf),
+        .A(WE)
+    );
+
+    sky130_fd_sc_hd__clkbuf_16 DIBUF[31:0] (
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(Di_buf),
+        .A(Di)
+    );
+
+    DEC6x64 DEC  ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+    `endif
+        .EN(EN),
+        .A(A),
+        .SEL(SEL)
+    );
+
+    generate
+        genvar i;
+        for (i=0; i< 64; i=i+1) begin : WORD
+            WORD32 W ( 
+            `ifdef USE_POWER_PINS
+                .VPWR(VPWR),
+                .VGND(VGND),
+            `endif
+                .CLK(CLK_buf),
+                .WE(WE_buf),
+                .SEL(SEL[i]),
+                .Di(Di_buf),
+                .Do(Do_pre)
+            );
+        end
+    endgenerate
+
+    // Ensure that the Do_pre lines are not floating when EN = 0
+    wire lo;
+    wire float_buf_en;
+    sky130_fd_sc_hd__clkbuf_4 FBUFENBUF( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(float_buf_en),
+        .A(EN)
+    );
+
+    sky130_fd_sc_hd__conb_1 TIE (
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .LO(lo),
+        .HI()
+    );
+
+    sky130_fd_sc_hd__ebufn_4 FLOATBUF[31:0] ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .A( lo ),
+        .Z(Do_pre),
+        .TE_B(float_buf_en)
+    );
+
+    generate 
+        //genvar i;
+        for(i=0; i<32; i=i+1) begin : OUT
+            sky130_fd_sc_hd__dfxtp_1 FF ( 
+            `ifdef USE_POWER_PINS
+                .VPWR(VPWR),
+                .VGND(VGND),
+                .VPB(VPWR),
+                .VNB(VGND),
+            `endif
+                .D(Do_pre[i]),
+                .Q(Do[i]),
+                .CLK(CLK)
+            );
+        end
+    endgenerate 
+
+endmodule
+
+module DFFRAM_COL4 
+(
+`ifdef USE_POWER_PINS
+    VPWR,
+    VGND,
+`endif
+    CLK,
+    WE,
+    EN,
+    Di,
+    Do,
+    A
+);
+
+    input           CLK;
+    input   [3:0]   WE;
+    input           EN;
+    input   [31:0]  Di;
+    output  [31:0]  Do;
+    input   [7:0]   A;
+
+`ifdef USE_POWER_PINS
+    input VPWR;
+    input VGND;
+`endif
+
+    wire [31:0]     Di_buf;
+    wire [31:0]     Do_pre;
+    wire            CLK_buf;
+    wire [3:0]      WE_buf;
+    wire [5:3]      A_buf;
+
+    wire [31:0]     Do_B_0_0;
+    wire [31:0]     Do_B_0_1;
+    wire [31:0]     Do_B_0_2;
+    wire [31:0]     Do_B_0_3;
+
+    wire [3:0]      row_sel;
+
+    sky130_fd_sc_hd__clkbuf_8 CLKBUF (
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(CLK_buf),
+        .A(CLK)
+    );
+
+    sky130_fd_sc_hd__clkbuf_8 WEBUF[3:0] (
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(WE_buf),
+        .A(WE)
+    );
+
+    sky130_fd_sc_hd__clkbuf_8 DIBUF[31:0] (
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(Di_buf), 
+        .A(Di)
+    );
+
+    sky130_fd_sc_hd__clkbuf_16 ABUF[2:0] ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+        .VPB(VPWR),
+        .VNB(VGND),
+    `endif
+        .X(A_buf),
+        .A(A[5:3])
+    );
+    
+    DEC2x4 DEC ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR), 
+        .VGND(VGND),
+    `endif
+        .EN(EN),
+        .A(A[7:6]),
+        .SEL(row_sel)
+    );
+
+    SRAM64x32 B_0_0 ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+    `endif
+        .CLK(CLK_buf),
+        .WE(WE_buf),
+        .EN(row_sel[0]),
+        .Di(Di_buf),
+        .Do(Do_B_0_0),
+        .A({A_buf,A[2:0]})
+    );
+
+    SRAM64x32 B_0_1 ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR), 
+        .VGND(VGND),
+    `endif
+        .CLK(CLK_buf),
+        .WE(WE_buf),
+        .EN(row_sel[1]),
+        .Di(Di_buf),
+        .Do(Do_B_0_1),
+        .A({A_buf,A[2:0]})
+    );
+
+    SRAM64x32 B_0_2 ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+    `endif
+        .CLK(CLK_buf),
+        .WE(WE_buf),
+        .EN(row_sel[2]),
+        .Di(Di_buf),
+        .Do(Do_B_0_2), 
+        .A({A_buf,A[2:0]}) 
+    );
+
+    SRAM64x32 B_0_3 ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+    `endif
+        .CLK(CLK_buf),
+        .WE(WE_buf),
+        .EN(row_sel[3]),
+        .Di(Di_buf),
+        .Do(Do_B_0_3),
+        .A({A_buf,A[2:0]})
+    );
+
+    MUX4x1_32 MUX ( 
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+    `endif
+        .A0(Do_B_0_0),
+        .A1(Do_B_0_1),
+        .A2(Do_B_0_2),
+        .A3(Do_B_0_3),
+        .S(A[7:6]),
+        .X(Do)
+    );
+
+endmodule
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/.gitignore b/verilog/rtl/softshell/third_party/picorv32/.gitignore
new file mode 100644
index 0000000..487adcc
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/.gitignore
@@ -0,0 +1,37 @@
+/tests/*.o
+/firmware/*.o
+/firmware/firmware.bin
+/firmware/firmware.elf
+/firmware/firmware.hex
+/firmware/firmware.map
+/dhrystone/dhry.bin
+/dhrystone/dhry.elf
+/dhrystone/dhry.hex
+/dhrystone/dhry.map
+/dhrystone/testbench.vvp
+/dhrystone/testbench.vcd
+/dhrystone/testbench_nola.vvp
+/dhrystone/testbench_nola.vcd
+/dhrystone/timing.vvp
+/dhrystone/timing.txt
+/dhrystone/*.d
+/dhrystone/*.o
+/riscv-gnu-toolchain-riscv32i
+/riscv-gnu-toolchain-riscv32ic
+/riscv-gnu-toolchain-riscv32im
+/riscv-gnu-toolchain-riscv32imc
+/testbench.vvp
+/testbench_wb.vvp
+/testbench_ez.vvp
+/testbench_sp.vvp
+/testbench_rvf.vvp
+/testbench_synth.vvp
+/testbench.gtkw
+/testbench.vcd
+/testbench.trace
+/testbench_verilator*
+/check.smt2
+/check.vcd
+/synth.log
+/synth.v
+.*.swp
diff --git a/verilog/rtl/softshell/third_party/picorv32/Makefile b/verilog/rtl/softshell/third_party/picorv32/Makefile
new file mode 100644
index 0000000..dd2fbce
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/Makefile
@@ -0,0 +1,184 @@
+
+RISCV_GNU_TOOLCHAIN_GIT_REVISION = 411d134
+RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX = /opt/riscv32
+
+# Give the user some easy overrides for local configuration quirks.
+# If you change one of these and it breaks, then you get to keep both pieces.
+SHELL = bash
+PYTHON = python3
+VERILATOR = verilator
+ICARUS_SUFFIX =
+IVERILOG = iverilog$(ICARUS_SUFFIX)
+VVP = vvp$(ICARUS_SUFFIX)
+
+TEST_OBJS = $(addsuffix .o,$(basename $(wildcard tests/*.S)))
+FIRMWARE_OBJS = firmware/start.o firmware/irq.o firmware/print.o firmware/hello.o firmware/sieve.o firmware/multest.o firmware/stats.o
+GCC_WARNS  = -Werror -Wall -Wextra -Wshadow -Wundef -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings
+GCC_WARNS += -Wredundant-decls -Wstrict-prototypes -Wmissing-prototypes -pedantic # -Wconversion
+TOOLCHAIN_PREFIX = $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)i/bin/riscv32-unknown-elf-
+COMPRESSED_ISA = C
+
+# Add things like "export http_proxy=... https_proxy=..." here
+GIT_ENV = true
+
+test: testbench.vvp firmware/firmware.hex
+	$(VVP) -N $<
+
+test_vcd: testbench.vvp firmware/firmware.hex
+	$(VVP) -N $< +vcd +trace +noerror
+
+test_rvf: testbench_rvf.vvp firmware/firmware.hex
+	$(VVP) -N $< +vcd +trace +noerror
+
+test_wb: testbench_wb.vvp firmware/firmware.hex
+	$(VVP) -N $<
+
+test_wb_vcd: testbench_wb.vvp firmware/firmware.hex
+	$(VVP) -N $< +vcd +trace +noerror
+
+test_ez: testbench_ez.vvp
+	$(VVP) -N $<
+
+test_ez_vcd: testbench_ez.vvp
+	$(VVP) -N $< +vcd
+
+test_sp: testbench_sp.vvp firmware/firmware.hex
+	$(VVP) -N $<
+
+test_axi: testbench.vvp firmware/firmware.hex
+	$(VVP) -N $< +axi_test
+
+test_synth: testbench_synth.vvp firmware/firmware.hex
+	$(VVP) -N $<
+
+test_verilator: testbench_verilator firmware/firmware.hex
+	./testbench_verilator
+
+testbench.vvp: testbench.v picorv32.v
+	$(IVERILOG) -o $@ $(subst C,-DCOMPRESSED_ISA,$(COMPRESSED_ISA)) $^
+	chmod -x $@
+
+testbench_rvf.vvp: testbench.v picorv32.v rvfimon.v
+	$(IVERILOG) -o $@ -D RISCV_FORMAL $(subst C,-DCOMPRESSED_ISA,$(COMPRESSED_ISA)) $^
+	chmod -x $@
+
+testbench_wb.vvp: testbench_wb.v picorv32.v
+	$(IVERILOG) -o $@ $(subst C,-DCOMPRESSED_ISA,$(COMPRESSED_ISA)) $^
+	chmod -x $@
+
+testbench_ez.vvp: testbench_ez.v picorv32.v
+	$(IVERILOG) -o $@ $(subst C,-DCOMPRESSED_ISA,$(COMPRESSED_ISA)) $^
+	chmod -x $@
+
+testbench_sp.vvp: testbench.v picorv32.v
+	$(IVERILOG) -o $@ $(subst C,-DCOMPRESSED_ISA,$(COMPRESSED_ISA)) -DSP_TEST $^
+	chmod -x $@
+
+testbench_synth.vvp: testbench.v synth.v
+	$(IVERILOG) -o $@ -DSYNTH_TEST $^
+	chmod -x $@
+
+testbench_verilator: testbench.v picorv32.v testbench.cc
+	$(VERILATOR) --cc --exe -Wno-lint -trace --top-module picorv32_wrapper testbench.v picorv32.v testbench.cc \
+			$(subst C,-DCOMPRESSED_ISA,$(COMPRESSED_ISA)) --Mdir testbench_verilator_dir
+	$(MAKE) -C testbench_verilator_dir -f Vpicorv32_wrapper.mk
+	cp testbench_verilator_dir/Vpicorv32_wrapper testbench_verilator
+
+check: check-yices
+
+check-%: check.smt2
+	yosys-smtbmc -s $(subst check-,,$@) -t 30 --dump-vcd check.vcd check.smt2
+	yosys-smtbmc -s $(subst check-,,$@) -t 25 --dump-vcd check.vcd -i check.smt2
+
+check.smt2: picorv32.v
+	yosys -v2 -p 'read_verilog -formal picorv32.v' \
+	          -p 'prep -top picorv32 -nordff' \
+		  -p 'assertpmux -noinit; opt -fast' \
+		  -p 'write_smt2 -wires check.smt2'
+
+synth.v: picorv32.v scripts/yosys/synth_sim.ys
+	yosys -qv3 -l synth.log scripts/yosys/synth_sim.ys
+
+firmware/firmware.hex: firmware/firmware.bin firmware/makehex.py
+	$(PYTHON) firmware/makehex.py $< 32768 > $@
+
+firmware/firmware.bin: firmware/firmware.elf
+	$(TOOLCHAIN_PREFIX)objcopy -O binary $< $@
+	chmod -x $@
+
+firmware/firmware.elf: $(FIRMWARE_OBJS) $(TEST_OBJS) firmware/sections.lds
+	$(TOOLCHAIN_PREFIX)gcc -Os -ffreestanding -nostdlib -o $@ \
+		-Wl,-Bstatic,-T,firmware/sections.lds,-Map,firmware/firmware.map,--strip-debug \
+		$(FIRMWARE_OBJS) $(TEST_OBJS) -lgcc
+	chmod -x $@
+
+firmware/start.o: firmware/start.S
+	$(TOOLCHAIN_PREFIX)gcc -c -march=rv32im$(subst C,c,$(COMPRESSED_ISA)) -o $@ $<
+
+firmware/%.o: firmware/%.c
+	$(TOOLCHAIN_PREFIX)gcc -c -march=rv32i$(subst C,c,$(COMPRESSED_ISA)) -Os --std=c99 $(GCC_WARNS) -ffreestanding -nostdlib -o $@ $<
+
+tests/%.o: tests/%.S tests/riscv_test.h tests/test_macros.h
+	$(TOOLCHAIN_PREFIX)gcc -c -march=rv32im -o $@ -DTEST_FUNC_NAME=$(notdir $(basename $<)) \
+		-DTEST_FUNC_TXT='"$(notdir $(basename $<))"' -DTEST_FUNC_RET=$(notdir $(basename $<))_ret $<
+
+download-tools:
+	sudo bash -c 'set -ex; mkdir -p /var/cache/distfiles; $(GIT_ENV); \
+	$(foreach REPO,riscv-gnu-toolchain riscv-binutils-gdb riscv-gcc riscv-glibc riscv-newlib, \
+		if ! test -d /var/cache/distfiles/$(REPO).git; then rm -rf /var/cache/distfiles/$(REPO).git.part; \
+			git clone --bare https://github.com/riscv/$(REPO) /var/cache/distfiles/$(REPO).git.part; \
+			mv /var/cache/distfiles/$(REPO).git.part /var/cache/distfiles/$(REPO).git; else \
+			(cd /var/cache/distfiles/$(REPO).git; git fetch https://github.com/riscv/$(REPO)); fi;)'
+
+define build_tools_template
+build-$(1)-tools:
+	@read -p "This will remove all existing data from $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)$(subst riscv32,,$(1)). Type YES to continue: " reply && [[ "$$$$reply" == [Yy][Ee][Ss] || "$$$$reply" == [Yy] ]]
+	sudo bash -c "set -ex; rm -rf $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)$(subst riscv32,,$(1)); mkdir -p $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)$(subst riscv32,,$(1)); chown $$$${USER}: $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)$(subst riscv32,,$(1))"
+	+$(MAKE) build-$(1)-tools-bh
+
+build-$(1)-tools-bh:
+	+set -ex; $(GIT_ENV); \
+	if [ -d /var/cache/distfiles/riscv-gnu-toolchain.git ]; then reference_riscv_gnu_toolchain="--reference /var/cache/distfiles/riscv-gnu-toolchain.git"; else reference_riscv_gnu_toolchain=""; fi; \
+	if [ -d /var/cache/distfiles/riscv-binutils-gdb.git ]; then reference_riscv_binutils_gdb="--reference /var/cache/distfiles/riscv-binutils-gdb.git"; else reference_riscv_binutils_gdb=""; fi; \
+	if [ -d /var/cache/distfiles/riscv-gcc.git ]; then reference_riscv_gcc="--reference /var/cache/distfiles/riscv-gcc.git"; else reference_riscv_gcc=""; fi; \
+	if [ -d /var/cache/distfiles/riscv-glibc.git ]; then reference_riscv_glibc="--reference /var/cache/distfiles/riscv-glibc.git"; else reference_riscv_glibc=""; fi; \
+	if [ -d /var/cache/distfiles/riscv-newlib.git ]; then reference_riscv_newlib="--reference /var/cache/distfiles/riscv-newlib.git"; else reference_riscv_newlib=""; fi; \
+	rm -rf riscv-gnu-toolchain-$(1); git clone $$$$reference_riscv_gnu_toolchain https://github.com/riscv/riscv-gnu-toolchain riscv-gnu-toolchain-$(1); \
+	cd riscv-gnu-toolchain-$(1); git checkout $(RISCV_GNU_TOOLCHAIN_GIT_REVISION); \
+	git submodule update --init $$$$reference_riscv_binutils_gdb riscv-binutils; \
+	git submodule update --init $$$$reference_riscv_binutils_gdb riscv-gdb; \
+	git submodule update --init $$$$reference_riscv_gcc riscv-gcc; \
+	git submodule update --init $$$$reference_riscv_glibc riscv-glibc; \
+	git submodule update --init $$$$reference_riscv_newlib riscv-newlib; \
+	mkdir build; cd build; ../configure --with-arch=$(2) --prefix=$(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)$(subst riscv32,,$(1)); make
+
+.PHONY: build-$(1)-tools
+endef
+
+$(eval $(call build_tools_template,riscv32i,rv32i))
+$(eval $(call build_tools_template,riscv32ic,rv32ic))
+$(eval $(call build_tools_template,riscv32im,rv32im))
+$(eval $(call build_tools_template,riscv32imc,rv32imc))
+
+build-tools:
+	@echo "This will remove all existing data from $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)i, $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)ic, $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)im, and $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)imc."
+	@read -p "Type YES to continue: " reply && [[ "$$reply" == [Yy][Ee][Ss] || "$$reply" == [Yy] ]]
+	sudo bash -c "set -ex; rm -rf $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX){i,ic,im,imc}; mkdir -p $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX){i,ic,im,imc}; chown $${USER}: $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX){i,ic,im,imc}"
+	+$(MAKE) build-riscv32i-tools-bh
+	+$(MAKE) build-riscv32ic-tools-bh
+	+$(MAKE) build-riscv32im-tools-bh
+	+$(MAKE) build-riscv32imc-tools-bh
+
+toc:
+	gawk '/^-+$$/ { y=tolower(x); gsub("[^a-z0-9]+", "-", y); gsub("-$$", "", y); printf("- [%s](#%s)\n", x, y); } { x=$$0; }' README.md
+
+clean:
+	rm -rf riscv-gnu-toolchain-riscv32i riscv-gnu-toolchain-riscv32ic \
+		riscv-gnu-toolchain-riscv32im riscv-gnu-toolchain-riscv32imc
+	rm -vrf $(FIRMWARE_OBJS) $(TEST_OBJS) check.smt2 check.vcd synth.v synth.log \
+		firmware/firmware.elf firmware/firmware.bin firmware/firmware.hex firmware/firmware.map \
+		testbench.vvp testbench_sp.vvp testbench_synth.vvp testbench_ez.vvp \
+		testbench_rvf.vvp testbench_wb.vvp testbench.vcd testbench.trace \
+		testbench_verilator testbench_verilator_dir
+
+.PHONY: test test_vcd test_sp test_axi test_wb test_wb_vcd test_ez test_ez_vcd test_synth download-tools build-tools toc clean
diff --git a/verilog/rtl/softshell/third_party/picorv32/README.md b/verilog/rtl/softshell/third_party/picorv32/README.md
new file mode 100644
index 0000000..3f41f0c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/README.md
@@ -0,0 +1,735 @@
+
+PicoRV32 - A Size-Optimized RISC-V CPU
+======================================
+
+PicoRV32 is a CPU core that implements the [RISC-V RV32IMC Instruction Set](http://riscv.org/).
+It can be configured as RV32E, RV32I, RV32IC, RV32IM, or RV32IMC core, and optionally
+contains a built-in interrupt controller.
+
+Tools (gcc, binutils, etc..) can be obtained via the [RISC-V Website](https://riscv.org/software-status/).
+The examples bundled with PicoRV32 expect various RV32 toolchains to be installed in `/opt/riscv32i[m][c]`. See
+the [build instructions below](#building-a-pure-rv32i-toolchain) for details.
+
+PicoRV32 is free and open hardware licensed under the [ISC license](http://en.wikipedia.org/wiki/ISC_license)
+(a license that is similar in terms to the MIT license or the 2-clause BSD license).
+
+#### Table of Contents
+
+- [Features and Typical Applications](#features-and-typical-applications)
+- [Files in this Repository](#files-in-this-repository)
+- [Verilog Module Parameters](#verilog-module-parameters)
+- [Cycles per Instruction Performance](#cycles-per-instruction-performance)
+- [PicoRV32 Native Memory Interface](#picorv32-native-memory-interface)
+- [Pico Co-Processor Interface (PCPI)](#pico-co-processor-interface-pcpi)
+- [Custom Instructions for IRQ Handling](#custom-instructions-for-irq-handling)
+- [Building a pure RV32I Toolchain](#building-a-pure-rv32i-toolchain)
+- [Linking binaries with newlib for PicoRV32](#linking-binaries-with-newlib-for-picorv32)
+- [Evaluation: Timing and Utilization on Xilinx 7-Series FPGAs](#evaluation-timing-and-utilization-on-xilinx-7-series-fpgas)
+
+
+Features and Typical Applications
+---------------------------------
+
+- Small (750-2000 LUTs in 7-Series Xilinx Architecture)
+- High f<sub>max</sub> (250-450 MHz on 7-Series Xilinx FPGAs)
+- Selectable native memory interface or AXI4-Lite master
+- Optional IRQ support (using a simple custom ISA)
+- Optional Co-Processor Interface
+
+This CPU is meant to be used as auxiliary processor in FPGA designs and ASICs. Due
+to its high f<sub>max</sub> it can be integrated in most existing designs without crossing
+clock domains. When operated on a lower frequency, it will have a lot of timing
+slack and thus can be added to a design without compromising timing closure.
+
+For even smaller size it is possible disable support for registers `x16`..`x31` as
+well as `RDCYCLE[H]`, `RDTIME[H]`, and `RDINSTRET[H]` instructions, turning the
+processor into an RV32E core.
+
+Furthermore it is possible to choose between a dual-port and a single-port
+register file implementation. The former provides better performance while
+the latter results in a smaller core.
+
+*Note: In architectures that implement the register file in dedicated memory
+resources, such as many FPGAs, disabling the 16 upper registers and/or
+disabling the dual-port register file may not further reduce the core size.*
+
+The core exists in three variations: `picorv32`, `picorv32_axi` and `picorv32_wb`.
+The first provides a simple native memory interface, that is easy to use in simple
+environments. `picorv32_axi` provides an AXI-4 Lite Master interface that can
+easily be integrated with existing systems that are already using the AXI
+standard. `picorv32_wb` provides a Wishbone master interface.
+
+A separate core `picorv32_axi_adapter` is provided to bridge between the native
+memory interface and AXI4. This core can be used to create custom cores that
+include one or more PicoRV32 cores together with local RAM, ROM, and
+memory-mapped peripherals, communicating with each other using the native
+interface, and communicating with the outside world via AXI4.
+
+The optional IRQ feature can be used to react to events from the outside, implement
+fault handlers, or catch instructions from a larger ISA and emulate them in
+software.
+
+The optional Pico Co-Processor Interface (PCPI) can be used to implement
+non-branching instructions in an external coprocessor. Implementations
+of PCPI cores that implement the M Standard Extension instructions
+`MUL[H[SU|U]]` and `DIV[U]/REM[U]` are included in this package.
+
+
+Files in this Repository
+------------------------
+
+#### README.md
+
+You are reading it right now.
+
+#### picorv32.v
+
+This Verilog file contains the following Verilog modules:
+
+| Module                   | Description                                                           |
+| ------------------------ | --------------------------------------------------------------------- |
+| `picorv32`               | The PicoRV32 CPU                                                      |
+| `picorv32_axi`           | The version of the CPU with AXI4-Lite interface                       |
+| `picorv32_axi_adapter`   | Adapter from PicoRV32 Memory Interface to AXI4-Lite                   |
+| `picorv32_wb`            | The version of the CPU with Wishbone Master interface                 |
+| `picorv32_pcpi_mul`      | A PCPI core that implements the `MUL[H[SU\|U]]` instructions          |
+| `picorv32_pcpi_fast_mul` | A version of `picorv32_pcpi_fast_mul` using a single cycle multiplier |
+| `picorv32_pcpi_div`      | A PCPI core that implements the `DIV[U]/REM[U]` instructions          |
+
+Simply copy this file into your project.
+
+#### Makefile and testbenches
+
+A basic test environment. Run `make test` to run the standard test bench (`testbench.v`)
+in the standard configurations. There are other test benches and configurations. See
+the `test_*` make target in the Makefile for details.
+
+Run `make test_ez` to run `testbench_ez.v`, a very simple test bench that does
+not require an external firmware .hex file. This can be useful in environments
+where the RISC-V compiler toolchain is not available.
+
+*Note: The test bench is using Icarus Verilog. However, Icarus Verilog 0.9.7
+(the latest release at the time of writing) has a few bugs that prevent the
+test bench from running. Upgrade to the latest github master of Icarus Verilog
+to run the test bench.*
+
+#### firmware/
+
+A simple test firmware. This runs the basic tests from `tests/`, some C code, tests IRQ
+handling and the multiply PCPI core.
+
+All the code in `firmware/` is in the public domain. Simply copy whatever you can use.
+
+#### tests/
+
+Simple instruction-level tests from [riscv-tests](https://github.com/riscv/riscv-tests).
+
+#### dhrystone/
+
+Another simple test firmware that runs the Dhrystone benchmark.
+
+#### picosoc/
+
+A simple example SoC using PicoRV32 that can execute code directly from a
+memory mapped SPI flash.
+
+#### scripts/
+
+Various scripts and examples for different (synthesis) tools and hardware architectures.
+
+
+Verilog Module Parameters
+-------------------------
+
+The following Verilog module parameters can be used to configure the PicoRV32
+core.
+
+#### ENABLE_COUNTERS (default = 1)
+
+This parameter enables support for the `RDCYCLE[H]`, `RDTIME[H]`, and
+`RDINSTRET[H]` instructions. This instructions will cause a hardware
+trap (like any other unsupported instruction) if `ENABLE_COUNTERS` is set to zero.
+
+*Note: Strictly speaking the `RDCYCLE[H]`, `RDTIME[H]`, and `RDINSTRET[H]`
+instructions are not optional for an RV32I core. But chances are they are not
+going to be missed after the application code has been debugged and profiled.
+This instructions are optional for an RV32E core.*
+
+#### ENABLE_COUNTERS64 (default = 1)
+
+This parameter enables support for the `RDCYCLEH`, `RDTIMEH`, and `RDINSTRETH`
+instructions. If this parameter is set to 0, and `ENABLE_COUNTERS` is set to 1,
+then only the `RDCYCLE`, `RDTIME`, and `RDINSTRET` instructions are available.
+
+#### ENABLE_REGS_16_31 (default = 1)
+
+This parameter enables support for registers the `x16`..`x31`. The RV32E ISA
+excludes this registers. However, the RV32E ISA spec requires a hardware trap
+for when code tries to access this registers. This is not implemented in PicoRV32.
+
+#### ENABLE_REGS_DUALPORT (default = 1)
+
+The register file can be implemented with two or one read ports. A dual ported
+register file improves performance a bit, but can also increase the size of
+the core.
+
+#### LATCHED_MEM_RDATA (default = 0)
+
+Set this to 1 if the `mem_rdata` is kept stable by the external circuit after a
+transaction. In the default configuration the PicoRV32 core only expects the
+`mem_rdata` input to be valid in the cycle with `mem_valid && mem_ready` and
+latches the value internally.
+
+This parameter is only available for the `picorv32` core. In the
+`picorv32_axi` and `picorv32_wb` core this is implicitly set to 0.
+
+#### TWO_STAGE_SHIFT (default = 1)
+
+By default shift operations are performed in two stages: first shifts in units
+of 4 bits and then shifts in units of 1 bit. This speeds up shift operations,
+but adds additional hardware. Set this parameter to 0 to disable the two-stage
+shift to further reduce the size of the core.
+
+#### BARREL_SHIFTER (default = 0)
+
+By default shift operations are performed by successively shifting by a
+small amount (see `TWO_STAGE_SHIFT` above). With this option set, a barrel
+shifter is used instead.
+
+#### TWO_CYCLE_COMPARE (default = 0)
+
+This relaxes the longest data path a bit by adding an additional FF stage
+at the cost of adding an additional clock cycle delay to the conditional
+branch instructions.
+
+*Note: Enabling this parameter will be most effective when retiming (aka
+"register balancing") is enabled in the synthesis flow.*
+
+#### TWO_CYCLE_ALU (default = 0)
+
+This adds an additional FF stage in the ALU data path, improving timing
+at the cost of an additional clock cycle for all instructions that use
+the ALU.
+
+*Note: Enabling this parameter will be most effective when retiming (aka
+"register balancing") is enabled in the synthesis flow.*
+
+#### COMPRESSED_ISA (default = 0)
+
+This enables support for the RISC-V Compressed Instruction Set.
+
+#### CATCH_MISALIGN (default = 1)
+
+Set this to 0 to disable the circuitry for catching misaligned memory
+accesses.
+
+#### CATCH_ILLINSN (default = 1)
+
+Set this to 0 to disable the circuitry for catching illegal instructions.
+
+The core will still trap on `EBREAK` instructions with this option
+set to 0. With IRQs enabled, an `EBREAK` normally triggers an IRQ 1. With
+this option set to 0, an `EBREAK` will trap the processor without
+triggering an interrupt.
+
+#### ENABLE_PCPI (default = 0)
+
+Set this to 1 to enable the Pico Co-Processor Interface (PCPI).
+
+#### ENABLE_MUL (default = 0)
+
+This parameter internally enables PCPI and instantiates the `picorv32_pcpi_mul`
+core that implements the `MUL[H[SU|U]]` instructions. The external PCPI
+interface only becomes functional when ENABLE_PCPI is set as well.
+
+#### ENABLE_FAST_MUL (default = 0)
+
+This parameter internally enables PCPI and instantiates the `picorv32_pcpi_fast_mul`
+core that implements the `MUL[H[SU|U]]` instructions. The external PCPI
+interface only becomes functional when ENABLE_PCPI is set as well.
+
+If both ENABLE_MUL and ENABLE_FAST_MUL are set then the ENABLE_MUL setting
+will be ignored and the fast multiplier core will be instantiated.
+
+#### ENABLE_DIV (default = 0)
+
+This parameter internally enables PCPI and instantiates the `picorv32_pcpi_div`
+core that implements the `DIV[U]/REM[U]` instructions. The external PCPI
+interface only becomes functional when ENABLE_PCPI is set as well.
+
+#### ENABLE_IRQ (default = 0)
+
+Set this to 1 to enable IRQs. (see "Custom Instructions for IRQ Handling" below
+for a discussion of IRQs)
+
+#### ENABLE_IRQ_QREGS (default = 1)
+
+Set this to 0 to disable support for the `getq` and `setq` instructions. Without
+the q-registers, the irq return address will be stored in x3 (gp) and the IRQ
+bitmask in x4 (tp), the global pointer and thread pointer registers according
+to the RISC-V ABI.  Code generated from ordinary C code will not interact with
+those registers.
+
+Support for q-registers is always disabled when ENABLE_IRQ is set to 0.
+
+#### ENABLE_IRQ_TIMER (default = 1)
+
+Set this to 0 to disable support for the `timer` instruction.
+
+Support for the timer is always disabled when ENABLE_IRQ is set to 0.
+
+#### ENABLE_TRACE (default = 0)
+
+Produce an execution trace using the `trace_valid` and `trace_data` output ports.
+For a demontration of this feature run `make test_vcd` to create a trace file
+and then run `python3 showtrace.py testbench.trace firmware/firmware.elf` to decode
+it.
+
+#### REGS_INIT_ZERO (default = 0)
+
+Set this to 1 to initialize all registers to zero (using a Verilog `initial` block).
+This can be useful for simulation or formal verification.
+
+#### MASKED_IRQ (default = 32'h 0000_0000)
+
+A 1 bit in this bitmask corresponds to a permanently disabled IRQ.
+
+#### LATCHED_IRQ (default = 32'h ffff_ffff)
+
+A 1 bit in this bitmask indicates that the corresponding IRQ is "latched", i.e.
+when the IRQ line is high for only one cycle, the interrupt will be marked as
+pending and stay pending until the interrupt handler is called (aka "pulse
+interrupts" or "edge-triggered interrupts").
+
+Set a bit in this bitmask to 0 to convert an interrupt line to operate
+as "level sensitive" interrupt.
+
+#### PROGADDR_RESET (default = 32'h 0000_0000)
+
+The start address of the program.
+
+#### PROGADDR_IRQ (default = 32'h 0000_0010)
+
+The start address of the interrupt handler.
+
+#### STACKADDR (default = 32'h ffff_ffff)
+
+When this parameter has a value different from 0xffffffff, then register `x2` (the
+stack pointer) is initialized to this value on reset. (All other registers remain
+uninitialized.) Note that the RISC-V calling convention requires the stack pointer
+to be aligned on 16 bytes boundaries (4 bytes for the RV32I soft float calling
+convention).
+
+
+Cycles per Instruction Performance
+----------------------------------
+
+*A short reminder: This core is optimized for size and f<sub>max</sub>, not performance.*
+
+Unless stated otherwise, the following numbers apply to a PicoRV32 with
+ENABLE_REGS_DUALPORT active and connected to a memory that can accommodate
+requests within one clock cycle.
+
+The average Cycles per Instruction (CPI) is approximately 4, depending on the mix of
+instructions in the code. The CPI numbers for the individual instructions can
+be found in the table below. The column "CPI (SP)" contains the CPI numbers for
+a core built without ENABLE_REGS_DUALPORT.
+
+| Instruction          |  CPI | CPI (SP) |
+| ---------------------| ----:| --------:|
+| direct jump (jal)    |    3 |        3 |
+| ALU reg + immediate  |    3 |        3 |
+| ALU reg + reg        |    3 |        4 |
+| branch (not taken)   |    3 |        4 |
+| memory load          |    5 |        5 |
+| memory store         |    5 |        6 |
+| branch (taken)       |    5 |        6 |
+| indirect jump (jalr) |    6 |        6 |
+| shift operations     | 4-14 |     4-15 |
+
+When `ENABLE_MUL` is activated, then a `MUL` instruction will execute
+in 40 cycles and a `MULH[SU|U]` instruction will execute in 72 cycles.
+
+When `ENABLE_DIV` is activated, then a `DIV[U]/REM[U]` instruction will
+execute in 40 cycles.
+
+When `BARREL_SHIFTER` is activated, a shift operation takes as long as
+any other ALU operation.
+
+The following dhrystone benchmark results are for a core with enabled
+`ENABLE_FAST_MUL`, `ENABLE_DIV`, and `BARREL_SHIFTER` options.
+
+Dhrystone benchmark results: 0.516 DMIPS/MHz (908 Dhrystones/Second/MHz)
+
+For the Dhrystone benchmark the average CPI is 4.100.
+
+Without using the look-ahead memory interface (usually required for max
+clock speed), this results drop to 0.305 DMIPS/MHz and 5.232 CPI.
+
+
+PicoRV32 Native Memory Interface
+--------------------------------
+
+The native memory interface of PicoRV32 is a simple valid-ready interface
+that can run one memory transfer at a time:
+
+    output        mem_valid
+    output        mem_instr
+    input         mem_ready
+
+    output [31:0] mem_addr
+    output [31:0] mem_wdata
+    output [ 3:0] mem_wstrb
+    input  [31:0] mem_rdata
+
+The core initiates a memory transfer by asserting `mem_valid`. The valid
+signal stays high until the peer asserts `mem_ready`. All core outputs
+are stable over the `mem_valid` period. If the memory transfer is an
+instruction fetch, the core asserts `mem_instr`.
+
+#### Read Transfer
+
+In a read transfer `mem_wstrb` has the value 0 and `mem_wdata` is unused.
+
+The memory reads the address `mem_addr` and makes the read value available on
+`mem_rdata` in the cycle `mem_ready` is high.
+
+There is no need for an external wait cycle. The memory read can be implemented
+asynchronously with `mem_ready` going high in the same cycle as `mem_valid`, or
+`mem_ready` being tied to constant 1.
+
+#### Write Transfer
+
+In a write transfer `mem_wstrb` is not 0 and `mem_rdata` is unused. The memory
+write the data at `mem_wdata` to the address `mem_addr` and acknowledges the
+transfer by asserting `mem_ready`.
+
+The 4 bits of `mem_wstrb` are write enables for the four bytes in the addressed
+word. Only the 8 values `0000`, `1111`, `1100`, `0011`, `1000`, `0100`, `0010`,
+and `0001` are possible, i.e. no write, write 32 bits, write upper 16 bits,
+write lower 16, or write a single byte respectively.
+
+There is no need for an external wait cycle. The memory can acknowledge the
+write immediately  with `mem_ready` going high in the same cycle as
+`mem_valid`, or `mem_ready` being tied to constant 1.
+
+#### Look-Ahead Interface
+
+The PicoRV32 core also provides a "Look-Ahead Memory Interface" that provides
+all information about the next memory transfer one clock cycle earlier than the
+normal interface.
+
+    output        mem_la_read
+    output        mem_la_write
+    output [31:0] mem_la_addr
+    output [31:0] mem_la_wdata
+    output [ 3:0] mem_la_wstrb
+
+In the clock cycle before `mem_valid` goes high, this interface will output a
+pulse on `mem_la_read` or `mem_la_write` to indicate the start of a read or
+write transaction in the next clock cycle.
+
+*Note: The signals `mem_la_read`, `mem_la_write`, and `mem_la_addr` are driven
+by combinatorial circuits within the PicoRV32 core. It might be harder to
+achieve timing closure with the look-ahead interface than with the normal
+memory interface described above.*
+
+
+Pico Co-Processor Interface (PCPI)
+----------------------------------
+
+The Pico Co-Processor Interface (PCPI) can be used to implement non-branching
+instructions in external cores:
+
+    output        pcpi_valid
+    output [31:0] pcpi_insn
+    output [31:0] pcpi_rs1
+    output [31:0] pcpi_rs2
+    input         pcpi_wr
+    input  [31:0] pcpi_rd
+    input         pcpi_wait
+    input         pcpi_ready
+
+When an unsupported instruction is encountered and the PCPI feature is
+activated (see ENABLE_PCPI above), then `pcpi_valid` is asserted, the
+instruction word itself is output on `pcpi_insn`, the `rs1` and `rs2`
+fields are decoded and the values in those registers are output
+on `pcpi_rs1` and `pcpi_rs2`.
+
+An external PCPI core can then decode the instruction, execute it, and assert
+`pcpi_ready` when execution of the instruction is finished. Optionally a
+result value can be written to `pcpi_rd` and `pcpi_wr` asserted. The
+PicoRV32 core will then decode the `rd` field of the instruction and
+write the value from `pcpi_rd` to the respective register.
+
+When no external PCPI core acknowledges the instruction within 16 clock
+cycles, then an illegal instruction exception is raised and the respective
+interrupt handler is called. A PCPI core that needs more than a couple of
+cycles to execute an instruction, should assert `pcpi_wait` as soon as
+the instruction has been decoded successfully and keep it asserted until
+it asserts `pcpi_ready`. This will prevent the PicoRV32 core from raising
+an illegal instruction exception.
+
+
+Custom Instructions for IRQ Handling
+------------------------------------
+
+*Note: The IRQ handling features in PicoRV32 do not follow the RISC-V
+Privileged ISA specification. Instead a small set of very simple custom
+instructions is used to implement IRQ handling with minimal hardware
+overhead.*
+
+The following custom instructions are only supported when IRQs are enabled
+via the `ENABLE_IRQ` parameter (see above).
+
+The PicoRV32 core has a built-in interrupt controller with 32 interrupt inputs. An
+interrupt can be triggered by asserting the corresponding bit in the `irq`
+input of the core.
+
+When the interrupt handler is started, the `eoi` End Of Interrupt (EOI) signals
+for the handled interrupts go high. The `eoi` signals go low again when the
+interrupt handler returns.
+
+The IRQs 0-2 can be triggered internally by the following built-in interrupt sources:
+
+| IRQ | Interrupt Source                    |
+| ---:| ------------------------------------|
+|   0 | Timer Interrupt                     |
+|   1 | EBREAK/ECALL or Illegal Instruction |
+|   2 | BUS Error (Unalign Memory Access)   |
+
+This interrupts can also be triggered by external sources, such as co-processors
+connected via PCPI.
+
+The core has 4 additional 32-bit registers `q0 .. q3` that are used for IRQ
+handling. When the IRQ handler is called, the register `q0` contains the return
+address and `q1` contains a bitmask of all IRQs to be handled. This means one
+call to the interrupt handler needs to service more than one IRQ when more than
+one bit is set in `q1`.
+
+When support for compressed instructions is enabled, then the LSB of q0 is set
+when the interrupted instruction is a compressed instruction. This can be used if
+the IRQ handler wants to decode the interrupted instruction.
+
+Registers `q2` and `q3` are uninitialized and can be used as temporary storage
+when saving/restoring register values in the IRQ handler.
+
+All of the following instructions are encoded under the `custom0` opcode. The f3
+and rs2 fields are ignored in all this instructions.
+
+See [firmware/custom_ops.S](firmware/custom_ops.S) for GNU assembler macros that
+implement mnemonics for this instructions.
+
+See [firmware/start.S](firmware/start.S) for an example implementation of an
+interrupt handler assembler wrapper, and [firmware/irq.c](firmware/irq.c) for
+the actual interrupt handler.
+
+#### getq rd, qs
+
+This instruction copies the value from a q-register to a general-purpose
+register.
+
+    0000000 ----- 000XX --- XXXXX 0001011
+    f7      rs2   qs    f3  rd    opcode
+
+Example:
+
+    getq x5, q2
+
+#### setq qd, rs
+
+This instruction copies the value from a general-purpose register to a
+q-register.
+
+    0000001 ----- XXXXX --- 000XX 0001011
+    f7      rs2   rs    f3  qd    opcode
+
+Example:
+
+    setq q2, x5
+
+#### retirq
+
+Return from interrupt. This instruction copies the value from `q0`
+to the program counter and re-enables interrupts.
+
+    0000010 ----- 00000 --- 00000 0001011
+    f7      rs2   rs    f3  rd    opcode
+
+Example:
+
+    retirq
+
+#### maskirq
+
+The "IRQ Mask" register contains a bitmask of masked (disabled) interrupts.
+This instruction writes a new value to the irq mask register and reads the old
+value.
+
+    0000011 ----- XXXXX --- XXXXX 0001011
+    f7      rs2   rs    f3  rd    opcode
+
+Example:
+
+    maskirq x1, x2
+
+The processor starts with all interrupts disabled.
+
+An illegal instruction or bus error while the illegal instruction or bus error
+interrupt is disabled will cause the processor to halt.
+
+#### waitirq
+
+Pause execution until an interrupt becomes pending. The bitmask of pending IRQs
+is written to `rd`.
+
+    0000100 ----- 00000 --- XXXXX 0001011
+    f7      rs2   rs    f3  rd    opcode
+
+Example:
+
+    waitirq x1
+
+#### timer
+
+Reset the timer counter to a new value. The counter counts down clock cycles and
+triggers the timer interrupt when transitioning from 1 to 0. Setting the
+counter to zero disables the timer. The old value of the counter is written to
+`rd`.
+
+    0000101 ----- XXXXX --- XXXXX 0001011
+    f7      rs2   rs    f3  rd    opcode
+
+Example:
+
+    timer x1, x2
+
+
+Building a pure RV32I Toolchain
+-------------------------------
+
+TL;DR: Run the following commands to build the complete toolchain:
+
+    make download-tools
+    make -j$(nproc) build-tools
+
+The default settings in the [riscv-tools](https://github.com/riscv/riscv-tools) build
+scripts will build a compiler, assembler and linker that can target any RISC-V ISA,
+but the libraries are built for RV32G and RV64G targets. Follow the instructions
+below to build a complete toolchain (including libraries) that target a pure RV32I
+CPU.
+
+The following commands will build the RISC-V GNU toolchain and libraries for a
+pure RV32I target, and install it in `/opt/riscv32i`:
+
+    # Ubuntu packages needed:
+    sudo apt-get install autoconf automake autotools-dev curl libmpc-dev \
+            libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo \
+	    gperf libtool patchutils bc zlib1g-dev git libexpat1-dev
+
+    sudo mkdir /opt/riscv32i
+    sudo chown $USER /opt/riscv32i
+
+    git clone https://github.com/riscv/riscv-gnu-toolchain riscv-gnu-toolchain-rv32i
+    cd riscv-gnu-toolchain-rv32i
+    git checkout 411d134
+    git submodule update --init --recursive
+
+    mkdir build; cd build
+    ../configure --with-arch=rv32i --prefix=/opt/riscv32i
+    make -j$(nproc)
+
+The commands will all be named using the prefix `riscv32-unknown-elf-`, which
+makes it easy to install them side-by-side with the regular riscv-tools (those
+are using the name prefix `riscv64-unknown-elf-` by default).
+
+Alternatively you can simply use one of the following make targets from PicoRV32's
+Makefile to build a `RV32I[M][C]` toolchain. You still need to install all
+prerequisites, as described above. Then run any of the following commands in the
+PicoRV32 source directory:
+
+| Command                                  | Install Directory  | ISA       |
+|:---------------------------------------- |:------------------ |:--------  |
+| `make -j$(nproc) build-riscv32i-tools`   | `/opt/riscv32i/`   | `RV32I`   |
+| `make -j$(nproc) build-riscv32ic-tools`  | `/opt/riscv32ic/`  | `RV32IC`  |
+| `make -j$(nproc) build-riscv32im-tools`  | `/opt/riscv32im/`  | `RV32IM`  |
+| `make -j$(nproc) build-riscv32imc-tools` | `/opt/riscv32imc/` | `RV32IMC` |
+
+Or simply run `make -j$(nproc) build-tools` to build and install all four tool chains.
+
+By default calling any of those make targets will (re-)download the toolchain
+sources. Run `make download-tools` to download the sources to `/var/cache/distfiles/`
+once in advance.
+
+*Note: These instructions are for git rev 411d134 (2018-02-14) of riscv-gnu-toolchain.*
+
+
+Linking binaries with newlib for PicoRV32
+-----------------------------------------
+
+The tool chains (see last section for install instructions) come with a version of
+the newlib C standard library.
+
+Use the linker script [firmware/riscv.ld](firmware/riscv.ld) for linking binaries
+against the newlib library. Using this linker script will create a binary that
+has its entry point at 0x10000. (The default linker script does not have a static
+entry point, thus a proper ELF loader would be needed that can determine the
+entry point at runtime while loading the program.)
+
+Newlib comes with a few syscall stubs. You need to provide your own implementation
+of those syscalls and link your program with this implementation, overwriting the
+default stubs from newlib. See `syscalls.c` in [scripts/cxxdemo/](scripts/cxxdemo/)
+for an example of how to do that.
+
+
+Evaluation: Timing and Utilization on Xilinx 7-Series FPGAs
+-----------------------------------------------------------
+
+The following evaluations have been performed with Vivado 2017.3.
+
+#### Timing on Xilinx 7-Series FPGAs
+
+The `picorv32_axi` module with enabled `TWO_CYCLE_ALU` has been placed and
+routed for Xilinx Artix-7T, Kintex-7T, Virtex-7T, Kintex UltraScale, and Virtex
+UltraScale devices in all speed grades. A binary search is used to find the
+shortest clock period for which the design meets timing.
+
+See `make table.txt` in [scripts/vivado/](scripts/vivado/).
+
+| Device                    | Device               | Speedgrade | Clock Period (Freq.) |
+|:------------------------- |:---------------------|:----------:| --------------------:|
+| Xilinx Kintex-7T          | xc7k70t-fbg676-2     | -2         |     2.4 ns (416 MHz) |
+| Xilinx Kintex-7T          | xc7k70t-fbg676-3     | -3         |     2.2 ns (454 MHz) |
+| Xilinx Virtex-7T          | xc7v585t-ffg1761-2   | -2         |     2.3 ns (434 MHz) |
+| Xilinx Virtex-7T          | xc7v585t-ffg1761-3   | -3         |     2.2 ns (454 MHz) |
+| Xilinx Kintex UltraScale  | xcku035-fbva676-2-e  | -2         |     2.0 ns (500 MHz) |
+| Xilinx Kintex UltraScale  | xcku035-fbva676-3-e  | -3         |     1.8 ns (555 MHz) |
+| Xilinx Virtex UltraScale  | xcvu065-ffvc1517-2-e | -2         |     2.1 ns (476 MHz) |
+| Xilinx Virtex UltraScale  | xcvu065-ffvc1517-3-e | -3         |     2.0 ns (500 MHz) |
+| Xilinx Kintex UltraScale+ | xcku3p-ffva676-2-e   | -2         |     1.4 ns (714 MHz) |
+| Xilinx Kintex UltraScale+ | xcku3p-ffva676-3-e   | -3         |     1.3 ns (769 MHz) |
+| Xilinx Virtex UltraScale+ | xcvu3p-ffvc1517-2-e  | -2         |     1.5 ns (666 MHz) |
+| Xilinx Virtex UltraScale+ | xcvu3p-ffvc1517-3-e  | -3         |     1.4 ns (714 MHz) |
+
+#### Utilization on Xilinx 7-Series FPGAs
+
+The following table lists the resource utilization in area-optimized synthesis
+for the following three cores:
+
+- **PicoRV32 (small):** The `picorv32` module without counter instructions,
+  without two-stage shifts, with externally latched `mem_rdata`, and without
+  catching of misaligned memory accesses and illegal instructions.
+
+- **PicoRV32 (regular):** The `picorv32` module in its default configuration.
+
+- **PicoRV32 (large):** The `picorv32` module with enabled PCPI, IRQ, MUL,
+  DIV, BARREL_SHIFTER, and COMPRESSED_ISA features.
+
+See `make area` in [scripts/vivado/](scripts/vivado/).
+
+| Core Variant       | Slice LUTs | LUTs as Memory | Slice Registers |
+|:------------------ | ----------:| --------------:| ---------------:|
+| PicoRV32 (small)   |        761 |             48 |             442 |
+| PicoRV32 (regular) |        917 |             48 |             583 |
+| PicoRV32 (large)   |       2019 |             88 |            1085 |
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/dhrystone/Makefile b/verilog/rtl/softshell/third_party/picorv32/dhrystone/Makefile
new file mode 100644
index 0000000..4dc0361
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/dhrystone/Makefile
@@ -0,0 +1,69 @@
+USE_MYSTDLIB = 0
+OBJS = dhry_1.o dhry_2.o stdlib.o
+CFLAGS = -MD -O3 -march=rv32im -DTIME -DRISCV
+TOOLCHAIN_PREFIX = /opt/riscv32im/bin/riscv32-unknown-elf-
+
+ifeq ($(USE_MYSTDLIB),1)
+CFLAGS += -DUSE_MYSTDLIB -ffreestanding -nostdlib
+OBJS += start.o
+else
+OBJS += syscalls.o
+endif
+
+test: testbench.vvp dhry.hex
+	vvp -N testbench.vvp
+
+test_trace: testbench.vvp dhry.hex
+	vvp -N $< +trace
+	python3 ../showtrace.py testbench.trace dhry.elf > testbench.ins
+
+test_nola: testbench_nola.vvp dhry.hex
+	vvp -N testbench_nola.vvp
+
+timing: timing.txt
+	grep '^##' timing.txt | gawk 'x != "" {print x,$$3-y;} {x=$$2;y=$$3;}' | sort | uniq -c | \
+		gawk '{printf("%03d-%-7s %2d %-8s (%d)\n",$$3,$$2,$$3,$$2,$$1);}' | sort | cut -c13-
+
+timing.txt: timing.vvp dhry.hex
+	vvp -N timing.vvp > timing.txt
+
+testbench.vvp: testbench.v ../picorv32.v
+	iverilog -o testbench.vvp testbench.v ../picorv32.v
+	chmod -x testbench.vvp
+
+testbench_nola.vvp: testbench_nola.v ../picorv32.v
+	iverilog -o testbench_nola.vvp testbench_nola.v ../picorv32.v
+	chmod -x testbench_nola.vvp
+
+timing.vvp: testbench.v ../picorv32.v
+	iverilog -o timing.vvp -DTIMING testbench.v ../picorv32.v
+	chmod -x timing.vvp
+
+dhry.hex: dhry.elf
+	$(TOOLCHAIN_PREFIX)objcopy -O verilog $< $@
+
+ifeq ($(USE_MYSTDLIB),1)
+dhry.elf: $(OBJS) sections.lds
+	$(TOOLCHAIN_PREFIX)gcc $(CFLAGS) -Wl,-Bstatic,-T,sections.lds,-Map,dhry.map,--strip-debug -o $@ $(OBJS) -lgcc
+	chmod -x $@
+else
+dhry.elf: $(OBJS)
+	$(TOOLCHAIN_PREFIX)gcc $(CFLAGS) -Wl,-Bstatic,-T,../firmware/riscv.ld,-Map,dhry.map,--strip-debug -o $@ $(OBJS) -lgcc -lc
+	chmod -x $@
+endif
+
+%.o: %.c
+	$(TOOLCHAIN_PREFIX)gcc -c $(CFLAGS) $<
+
+%.o: %.S
+	$(TOOLCHAIN_PREFIX)gcc -c $(CFLAGS) $<
+
+dhry_1.o dhry_2.o: CFLAGS += -Wno-implicit-int -Wno-implicit-function-declaration
+
+clean:
+	rm -rf *.o *.d dhry.elf dhry.map dhry.bin dhry.hex testbench.vvp testbench.vcd timing.vvp timing.txt testbench_nola.vvp
+
+.PHONY: test clean
+
+-include *.d
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/dhrystone/README b/verilog/rtl/softshell/third_party/picorv32/dhrystone/README
new file mode 100644
index 0000000..e08b25b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/dhrystone/README
@@ -0,0 +1 @@
+The Dhrystone benchmark and a verilog testbench to run it.
diff --git a/verilog/rtl/softshell/third_party/picorv32/dhrystone/dhry.h b/verilog/rtl/softshell/third_party/picorv32/dhrystone/dhry.h
new file mode 100644
index 0000000..bafacc6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/dhrystone/dhry.h
@@ -0,0 +1,423 @@
+/*
+ ****************************************************************************
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *
+ *  Version:    C, Version 2.1
+ *
+ *  File:       dhry.h (part 1 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *                      Siemens AG, AUT E 51
+ *                      Postfach 3220
+ *                      8520 Erlangen
+ *                      Germany (West)
+ *                              Phone:  [+49]-9131-7-20330
+ *                                      (8-17 Central European Time)
+ *                              Usenet: ..!mcsun!unido!estevax!weicker
+ *
+ *              Original Version (in Ada) published in
+ *              "Communications of the ACM" vol. 27., no. 10 (Oct. 1984),
+ *              pp. 1013 - 1030, together with the statistics
+ *              on which the distribution of statements etc. is based.
+ *
+ *              In this C version, the following C library functions are used:
+ *              - strcpy, strcmp (inside the measurement loop)
+ *              - printf, scanf (outside the measurement loop)
+ *              In addition, Berkeley UNIX system calls "times ()" or "time ()"
+ *              are used for execution time measurement. For measurements
+ *              on other systems, these calls have to be changed.
+ *
+ *  Collection of Results:
+ *              Reinhold Weicker (address see above) and
+ *
+ *              Rick Richardson
+ *              PC Research. Inc.
+ *              94 Apple Orchard Drive
+ *              Tinton Falls, NJ 07724
+ *                      Phone:  (201) 389-8963 (9-17 EST)
+ *                      Usenet: ...!uunet!pcrat!rick
+ *
+ *      Please send results to Rick Richardson and/or Reinhold Weicker.
+ *      Complete information should be given on hardware and software used.
+ *      Hardware information includes: Machine type, CPU, type and size
+ *      of caches; for microprocessors: clock frequency, memory speed
+ *      (number of wait states).
+ *      Software information includes: Compiler (and runtime library)
+ *      manufacturer and version, compilation switches, OS version.
+ *      The Operating System version may give an indication about the
+ *      compiler; Dhrystone itself performs no OS calls in the measurement loop.
+ *
+ *      The complete output generated by the program should be mailed
+ *      such that at least some checks for correctness can be made.
+ *
+ ***************************************************************************
+ *
+ *  History:    This version C/2.1 has been made for two reasons:
+ *
+ *              1) There is an obvious need for a common C version of
+ *              Dhrystone, since C is at present the most popular system
+ *              programming language for the class of processors
+ *              (microcomputers, minicomputers) where Dhrystone is used most.
+ *              There should be, as far as possible, only one C version of
+ *              Dhrystone such that results can be compared without
+ *              restrictions. In the past, the C versions distributed
+ *              by Rick Richardson (Version 1.1) and by Reinhold Weicker
+ *              had small (though not significant) differences.
+ *
+ *              2) As far as it is possible without changes to the Dhrystone
+ *              statistics, optimizing compilers should be prevented from
+ *              removing significant statements.
+ *
+ *              This C version has been developed in cooperation with
+ *              Rick Richardson (Tinton Falls, NJ), it incorporates many
+ *              ideas from the "Version 1.1" distributed previously by
+ *              him over the UNIX network Usenet.
+ *              I also thank Chaim Benedelac (National Semiconductor),
+ *              David Ditzel (SUN), Earl Killian and John Mashey (MIPS),
+ *              Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley)
+ *              for their help with comments on earlier versions of the
+ *              benchmark.
+ *
+ *  Changes:    In the initialization part, this version follows mostly
+ *              Rick Richardson's version distributed via Usenet, not the
+ *              version distributed earlier via floppy disk by Reinhold Weicker.
+ *              As a concession to older compilers, names have been made
+ *              unique within the first 8 characters.
+ *              Inside the measurement loop, this version follows the
+ *              version previously distributed by Reinhold Weicker.
+ *
+ *              At several places in the benchmark, code has been added,
+ *              but within the measurement loop only in branches that
+ *              are not executed. The intention is that optimizing compilers
+ *              should be prevented from moving code out of the measurement
+ *              loop, or from removing code altogether. Since the statements
+ *              that are executed within the measurement loop have NOT been
+ *              changed, the numbers defining the "Dhrystone distribution"
+ *              (distribution of statements, operand types and locality)
+ *              still hold. Except for sophisticated optimizing compilers,
+ *              execution times for this version should be the same as
+ *              for previous versions.
+ *
+ *              Since it has proven difficult to subtract the time for the
+ *              measurement loop overhead in a correct way, the loop check
+ *              has been made a part of the benchmark. This does have
+ *              an impact - though a very minor one - on the distribution
+ *              statistics which have been updated for this version.
+ *
+ *              All changes within the measurement loop are described
+ *              and discussed in the companion paper "Rationale for
+ *              Dhrystone version 2".
+ *
+ *              Because of the self-imposed limitation that the order and
+ *              distribution of the executed statements should not be
+ *              changed, there are still cases where optimizing compilers
+ *              may not generate code for some statements. To a certain
+ *              degree, this is unavoidable for small synthetic benchmarks.
+ *              Users of the benchmark are advised to check code listings
+ *              whether code is generated for all statements of Dhrystone.
+ *
+ *              Version 2.1 is identical to version 2.0 distributed via
+ *              the UNIX network Usenet in March 1988 except that it corrects
+ *              some minor deficiencies that were found by users of version 2.0.
+ *              The only change within the measurement loop is that a
+ *              non-executed "else" part was added to the "if" statement in
+ *              Func_3, and a non-executed "else" part removed from Proc_3.
+ *
+ ***************************************************************************
+ *
+ * Defines:     The following "Defines" are possible:
+ *              -DREG=register          (default: Not defined)
+ *                      As an approximation to what an average C programmer
+ *                      might do, the "register" storage class is applied
+ *                      (if enabled by -DREG=register)
+ *                      - for local variables, if they are used (dynamically)
+ *                        five or more times
+ *                      - for parameters if they are used (dynamically)
+ *                        six or more times
+ *                      Note that an optimal "register" strategy is
+ *                      compiler-dependent, and that "register" declarations
+ *                      do not necessarily lead to faster execution.
+ *              -DNOSTRUCTASSIGN        (default: Not defined)
+ *                      Define if the C compiler does not support
+ *                      assignment of structures.
+ *              -DNOENUMS               (default: Not defined)
+ *                      Define if the C compiler does not support
+ *                      enumeration types.
+ *              -DTIMES                 (default)
+ *              -DTIME
+ *                      The "times" function of UNIX (returning process times)
+ *                      or the "time" function (returning wallclock time)
+ *                      is used for measurement.
+ *                      For single user machines, "time ()" is adequate. For
+ *                      multi-user machines where you cannot get single-user
+ *                      access, use the "times ()" function. If you have
+ *                      neither, use a stopwatch in the dead of night.
+ *                      "printf"s are provided marking the points "Start Timer"
+ *                      and "Stop Timer". DO NOT use the UNIX "time(1)"
+ *                      command, as this will measure the total time to
+ *                      run this program, which will (erroneously) include
+ *                      the time to allocate storage (malloc) and to perform
+ *                      the initialization.
+ *              -DHZ=nnn
+ *                      In Berkeley UNIX, the function "times" returns process
+ *                      time in 1/HZ seconds, with HZ = 60 for most systems.
+ *                      CHECK YOUR SYSTEM DESCRIPTION BEFORE YOU JUST APPLY
+ *                      A VALUE.
+ *
+ ***************************************************************************
+ *
+ *  Compilation model and measurement (IMPORTANT):
+ *
+ *  This C version of Dhrystone consists of three files:
+ *  - dhry.h (this file, containing global definitions and comments)
+ *  - dhry_1.c (containing the code corresponding to Ada package Pack_1)
+ *  - dhry_2.c (containing the code corresponding to Ada package Pack_2)
+ *
+ *  The following "ground rules" apply for measurements:
+ *  - Separate compilation
+ *  - No procedure merging
+ *  - Otherwise, compiler optimizations are allowed but should be indicated
+ *  - Default results are those without register declarations
+ *  See the companion paper "Rationale for Dhrystone Version 2" for a more
+ *  detailed discussion of these ground rules.
+ *
+ *  For 16-Bit processors (e.g. 80186, 80286), times for all compilation
+ *  models ("small", "medium", "large" etc.) should be given if possible,
+ *  together with a definition of these models for the compiler system used.
+ *
+ **************************************************************************
+ *
+ *  Dhrystone (C version) statistics:
+ *
+ *  [Comment from the first distribution, updated for version 2.
+ *   Note that because of language differences, the numbers are slightly
+ *   different from the Ada version.]
+ *
+ *  The following program contains statements of a high level programming
+ *  language (here: C) in a distribution considered representative:
+ *
+ *    assignments                  52 (51.0 %)
+ *    control statements           33 (32.4 %)
+ *    procedure, function calls    17 (16.7 %)
+ *
+ *  103 statements are dynamically executed. The program is balanced with
+ *  respect to the three aspects:
+ *
+ *    - statement type
+ *    - operand type
+ *    - operand locality
+ *         operand global, local, parameter, or constant.
+ *
+ *  The combination of these three aspects is balanced only approximately.
+ *
+ *  1. Statement Type:
+ *  -----------------             number
+ *
+ *     V1 = V2                     9
+ *       (incl. V1 = F(..)
+ *     V = Constant               12
+ *     Assignment,                 7
+ *       with array element
+ *     Assignment,                 6
+ *       with record component
+ *                                --
+ *                                34       34
+ *
+ *     X = Y +|-|"&&"|"|" Z        5
+ *     X = Y +|-|"==" Constant     6
+ *     X = X +|- 1                 3
+ *     X = Y *|/ Z                 2
+ *     X = Expression,             1
+ *           two operators
+ *     X = Expression,             1
+ *           three operators
+ *                                --
+ *                                18       18
+ *
+ *     if ....                    14
+ *       with "else"      7
+ *       without "else"   7
+ *           executed        3
+ *           not executed    4
+ *     for ...                     7  |  counted every time
+ *     while ...                   4  |  the loop condition
+ *     do ... while                1  |  is evaluated
+ *     switch ...                  1
+ *     break                       1
+ *     declaration with            1
+ *       initialization
+ *                                --
+ *                                34       34
+ *
+ *     P (...)  procedure call    11
+ *       user procedure      10
+ *       library procedure    1
+ *     X = F (...)
+ *             function  call      6
+ *       user function        5
+ *       library function     1
+ *                                --
+ *                                17       17
+ *                                        ---
+ *                                        103
+ *
+ *    The average number of parameters in procedure or function calls
+ *    is 1.82 (not counting the function values as implicit parameters).
+ *
+ *
+ *  2. Operators
+ *  ------------
+ *                          number    approximate
+ *                                    percentage
+ *
+ *    Arithmetic             32          50.8
+ *
+ *       +                     21          33.3
+ *       -                      7          11.1
+ *       *                      3           4.8
+ *       / (int div)            1           1.6
+ *
+ *    Comparison             27           42.8
+ *
+ *       ==                     9           14.3
+ *       /=                     4            6.3
+ *       >                      1            1.6
+ *       <                      3            4.8
+ *       >=                     1            1.6
+ *       <=                     9           14.3
+ *
+ *    Logic                   4            6.3
+ *
+ *       && (AND-THEN)          1            1.6
+ *       |  (OR)                1            1.6
+ *       !  (NOT)               2            3.2
+ *
+ *                           --          -----
+ *                           63          100.1
+ *
+ *
+ *  3. Operand Type (counted once per operand reference):
+ *  ---------------
+ *                          number    approximate
+ *                                    percentage
+ *
+ *     Integer               175        72.3 %
+ *     Character              45        18.6 %
+ *     Pointer                12         5.0 %
+ *     String30                6         2.5 %
+ *     Array                   2         0.8 %
+ *     Record                  2         0.8 %
+ *                           ---       -------
+ *                           242       100.0 %
+ *
+ *  When there is an access path leading to the final operand (e.g. a record
+ *  component), only the final data type on the access path is counted.
+ *
+ *
+ *  4. Operand Locality:
+ *  -------------------
+ *                                number    approximate
+ *                                          percentage
+ *
+ *     local variable              114        47.1 %
+ *     global variable              22         9.1 %
+ *     parameter                    45        18.6 %
+ *        value                        23         9.5 %
+ *        reference                    22         9.1 %
+ *     function result               6         2.5 %
+ *     constant                     55        22.7 %
+ *                                 ---       -------
+ *                                 242       100.0 %
+ *
+ *
+ *  The program does not compute anything meaningful, but it is syntactically
+ *  and semantically correct. All variables have a value assigned to them
+ *  before they are used as a source operand.
+ *
+ *  There has been no explicit effort to account for the effects of a
+ *  cache, or to balance the use of long or short displacements for code or
+ *  data.
+ *
+ ***************************************************************************
+ */
+
+/* Compiler and system dependent definitions: */
+
+#ifndef TIME
+#define TIMES
+#endif
+                /* Use times(2) time function unless    */
+                /* explicitly defined otherwise         */
+
+#ifdef TIMES
+#include <sys/types.h>
+#include <sys/times.h>
+                /* for "times" */
+#endif
+
+#define Mic_secs_Per_Second     1000000.0
+                /* Berkeley UNIX C returns process times in seconds/HZ */
+
+#ifdef  NOSTRUCTASSIGN
+#define structassign(d, s)      memcpy(&(d), &(s), sizeof(d))
+#else
+#define structassign(d, s)      d = s
+#endif
+
+#ifdef  NOENUM
+#define Ident_1 0
+#define Ident_2 1
+#define Ident_3 2
+#define Ident_4 3
+#define Ident_5 4
+  typedef int   Enumeration;
+#else
+  typedef       enum    {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5}
+                Enumeration;
+#endif
+        /* for boolean and enumeration types in Ada, Pascal */
+
+/* General definitions: */
+
+#include <stdio.h>
+                /* for strcpy, strcmp */
+
+#define Null 0
+                /* Value of a Null pointer */
+#define true  1
+#define false 0
+
+typedef int     One_Thirty;
+typedef int     One_Fifty;
+typedef char    Capital_Letter;
+typedef int     Boolean;
+typedef char    Str_30 [31];
+typedef int     Arr_1_Dim [50];
+typedef int     Arr_2_Dim [50] [50];
+
+typedef struct record
+    {
+    struct record *Ptr_Comp;
+    Enumeration    Discr;
+    union {
+          struct {
+                  Enumeration Enum_Comp;
+                  int         Int_Comp;
+                  char        Str_Comp [31];
+                  } var_1;
+          struct {
+                  Enumeration E_Comp_2;
+                  char        Str_2_Comp [31];
+                  } var_2;
+          struct {
+                  char        Ch_1_Comp;
+                  char        Ch_2_Comp;
+                  } var_3;
+          } variant;
+      } Rec_Type, *Rec_Pointer;
+
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/dhrystone/dhry_1.c b/verilog/rtl/softshell/third_party/picorv32/dhrystone/dhry_1.c
new file mode 100644
index 0000000..fa0d4d9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/dhrystone/dhry_1.c
@@ -0,0 +1,427 @@
+/*
+ ****************************************************************************
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *
+ *  Version:    C, Version 2.1
+ *
+ *  File:       dhry_1.c (part 2 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *
+ ****************************************************************************
+ */
+
+#include "dhry.h"
+
+#ifdef USE_MYSTDLIB
+extern char     *malloc ();
+#else
+#  include <stdlib.h>
+#  include <string.h>
+#endif
+
+/* Global Variables: */
+
+Rec_Pointer     Ptr_Glob,
+                Next_Ptr_Glob;
+int             Int_Glob;
+Boolean         Bool_Glob;
+char            Ch_1_Glob,
+                Ch_2_Glob;
+int             Arr_1_Glob [50];
+int             Arr_2_Glob [50] [50];
+
+Enumeration     Func_1 ();
+  /* forward declaration necessary since Enumeration may not simply be int */
+
+#ifndef REG
+        Boolean Reg = false;
+#define REG
+        /* REG becomes defined as empty */
+        /* i.e. no register variables   */
+#else
+        Boolean Reg = true;
+#endif
+
+/* variables for time measurement: */
+
+#ifdef IGN_TIMES
+struct tms      time_info;
+extern  int     times ();
+                /* see library function "times" */
+#define Too_Small_Time 120
+                /* Measurements should last at least about 2 seconds */
+#endif
+#ifdef TIME
+extern long     time();
+#ifdef RISCV
+extern long     insn();
+#endif
+                /* see library function "time"  */
+#define Too_Small_Time 2
+                /* Measurements should last at least 2 seconds */
+#endif
+
+long            Begin_Time,
+                End_Time,
+                User_Time;
+#ifdef RISCV
+long            Begin_Insn,
+                End_Insn,
+                User_Insn;
+#endif
+float           Microseconds,
+                Dhrystones_Per_Second;
+
+/* end of variables for time measurement */
+
+
+main ()
+/*****/
+
+  /* main program, corresponds to procedures        */
+  /* Main and Proc_0 in the Ada version             */
+{
+        One_Fifty       Int_1_Loc;
+  REG   One_Fifty       Int_2_Loc;
+        One_Fifty       Int_3_Loc;
+  REG   char            Ch_Index;
+        Enumeration     Enum_Loc;
+        Str_30          Str_1_Loc;
+        Str_30          Str_2_Loc;
+  REG   int             Run_Index;
+  REG   int             Number_Of_Runs;
+
+  /* Initializations */
+
+  Next_Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
+  Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
+
+  Ptr_Glob->Ptr_Comp                    = Next_Ptr_Glob;
+  Ptr_Glob->Discr                       = Ident_1;
+  Ptr_Glob->variant.var_1.Enum_Comp     = Ident_3;
+  Ptr_Glob->variant.var_1.Int_Comp      = 40;
+  strcpy (Ptr_Glob->variant.var_1.Str_Comp,
+          "DHRYSTONE PROGRAM, SOME STRING");
+  strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING");
+
+  Arr_2_Glob [8][7] = 10;
+        /* Was missing in published program. Without this statement,    */
+        /* Arr_2_Glob [8][7] would have an undefined value.             */
+        /* Warning: With 16-Bit processors and Number_Of_Runs > 32000,  */
+        /* overflow may occur for this array element.                   */
+
+  printf ("\n");
+  printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n");
+  printf ("\n");
+  if (Reg)
+  {
+    printf ("Program compiled with 'register' attribute\n");
+    printf ("\n");
+  }
+  else
+  {
+    printf ("Program compiled without 'register' attribute\n");
+    printf ("\n");
+  }
+  printf ("Please give the number of runs through the benchmark: ");
+  {
+    // int n;
+    // scanf ("%d", &n);
+    Number_Of_Runs = 100;
+  }
+  printf ("\n");
+
+  printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs);
+
+  /***************/
+  /* Start timer */
+  /***************/
+
+#ifdef IGN_TIMES
+  times (&time_info);
+  Begin_Time = (long) time_info.tms_utime;
+#endif
+#ifdef TIME
+  Begin_Time = time ( (long *) 0);
+#ifdef RISCV
+  Begin_Insn = insn ( (long *) 0);
+#endif
+#endif
+
+  for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index)
+  {
+
+    Proc_5();
+    Proc_4();
+      /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */
+    Int_1_Loc = 2;
+    Int_2_Loc = 3;
+    strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
+    Enum_Loc = Ident_2;
+    Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc);
+      /* Bool_Glob == 1 */
+    while (Int_1_Loc < Int_2_Loc)  /* loop body executed once */
+    {
+      Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc;
+        /* Int_3_Loc == 7 */
+      Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc);
+        /* Int_3_Loc == 7 */
+      Int_1_Loc += 1;
+    } /* while */
+      /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+    Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc);
+      /* Int_Glob == 5 */
+    Proc_1 (Ptr_Glob);
+    for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index)
+                             /* loop body executed twice */
+    {
+      if (Enum_Loc == Func_1 (Ch_Index, 'C'))
+          /* then, not executed */
+        {
+        Proc_6 (Ident_1, &Enum_Loc);
+        strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING");
+        Int_2_Loc = Run_Index;
+        Int_Glob = Run_Index;
+        }
+    }
+      /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+    Int_2_Loc = Int_2_Loc * Int_1_Loc;
+    Int_1_Loc = Int_2_Loc / Int_3_Loc;
+    Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc;
+      /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */
+    Proc_2 (&Int_1_Loc);
+      /* Int_1_Loc == 5 */
+
+  } /* loop "for Run_Index" */
+
+  /**************/
+  /* Stop timer */
+  /**************/
+
+#ifdef IGN_TIMES
+  times (&time_info);
+  End_Time = (long) time_info.tms_utime;
+#endif
+#ifdef TIME
+  End_Time = time ( (long *) 0);
+#ifdef RISCV
+  End_Insn = insn ( (long *) 0);
+#endif
+#endif
+
+  printf ("Execution ends\n");
+  printf ("\n");
+  printf ("Final values of the variables used in the benchmark:\n");
+  printf ("\n");
+  printf ("Int_Glob:            %d\n", Int_Glob);
+  printf ("        should be:   %d\n", 5);
+  printf ("Bool_Glob:           %d\n", Bool_Glob);
+  printf ("        should be:   %d\n", 1);
+  printf ("Ch_1_Glob:           %c\n", Ch_1_Glob);
+  printf ("        should be:   %c\n", 'A');
+  printf ("Ch_2_Glob:           %c\n", Ch_2_Glob);
+  printf ("        should be:   %c\n", 'B');
+  printf ("Arr_1_Glob[8]:       %d\n", Arr_1_Glob[8]);
+  printf ("        should be:   %d\n", 7);
+  printf ("Arr_2_Glob[8][7]:    %d\n", Arr_2_Glob[8][7]);
+  printf ("        should be:   Number_Of_Runs + 10\n");
+  printf ("Ptr_Glob->\n");
+  printf ("  Ptr_Comp:          %d\n", (int) Ptr_Glob->Ptr_Comp);
+  printf ("        should be:   (implementation-dependent)\n");
+  printf ("  Discr:             %d\n", Ptr_Glob->Discr);
+  printf ("        should be:   %d\n", 0);
+  printf ("  Enum_Comp:         %d\n", Ptr_Glob->variant.var_1.Enum_Comp);
+  printf ("        should be:   %d\n", 2);
+  printf ("  Int_Comp:          %d\n", Ptr_Glob->variant.var_1.Int_Comp);
+  printf ("        should be:   %d\n", 17);
+  printf ("  Str_Comp:          %s\n", Ptr_Glob->variant.var_1.Str_Comp);
+  printf ("        should be:   DHRYSTONE PROGRAM, SOME STRING\n");
+  printf ("Next_Ptr_Glob->\n");
+  printf ("  Ptr_Comp:          %d\n", (int) Next_Ptr_Glob->Ptr_Comp);
+  printf ("        should be:   (implementation-dependent), same as above\n");
+  printf ("  Discr:             %d\n", Next_Ptr_Glob->Discr);
+  printf ("        should be:   %d\n", 0);
+  printf ("  Enum_Comp:         %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp);
+  printf ("        should be:   %d\n", 1);
+  printf ("  Int_Comp:          %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp);
+  printf ("        should be:   %d\n", 18);
+  printf ("  Str_Comp:          %s\n",
+                                Next_Ptr_Glob->variant.var_1.Str_Comp);
+  printf ("        should be:   DHRYSTONE PROGRAM, SOME STRING\n");
+  printf ("Int_1_Loc:           %d\n", Int_1_Loc);
+  printf ("        should be:   %d\n", 5);
+  printf ("Int_2_Loc:           %d\n", Int_2_Loc);
+  printf ("        should be:   %d\n", 13);
+  printf ("Int_3_Loc:           %d\n", Int_3_Loc);
+  printf ("        should be:   %d\n", 7);
+  printf ("Enum_Loc:            %d\n", Enum_Loc);
+  printf ("        should be:   %d\n", 1);
+  printf ("Str_1_Loc:           %s\n", Str_1_Loc);
+  printf ("        should be:   DHRYSTONE PROGRAM, 1'ST STRING\n");
+  printf ("Str_2_Loc:           %s\n", Str_2_Loc);
+  printf ("        should be:   DHRYSTONE PROGRAM, 2'ND STRING\n");
+  printf ("\n");
+
+  User_Time = End_Time - Begin_Time;
+
+#ifdef RISCV
+  User_Insn = End_Insn - Begin_Insn;
+
+  printf("Number_Of_Runs: %d\n", Number_Of_Runs);
+  printf("User_Time: %d cycles, %d insn\n", User_Time, User_Insn);
+
+  int Cycles_Per_Instruction_x1000 = (1000 * User_Time) / User_Insn;
+  printf("Cycles_Per_Instruction: %d.%d%d%d\n", Cycles_Per_Instruction_x1000 / 1000,
+		(Cycles_Per_Instruction_x1000 / 100) % 10,
+		(Cycles_Per_Instruction_x1000 / 10) % 10,
+		(Cycles_Per_Instruction_x1000 / 1) % 10);
+
+  int Dhrystones_Per_Second_Per_MHz = (Number_Of_Runs * 1000000) / User_Time;
+  printf("Dhrystones_Per_Second_Per_MHz: %d\n", Dhrystones_Per_Second_Per_MHz);
+
+  int DMIPS_Per_MHz_x1000 = (1000 * Dhrystones_Per_Second_Per_MHz) / 1757;
+  printf("DMIPS_Per_MHz: %d.%d%d%d\n", DMIPS_Per_MHz_x1000 / 1000,
+		(DMIPS_Per_MHz_x1000 / 100) % 10,
+		(DMIPS_Per_MHz_x1000 / 10) % 10,
+		(DMIPS_Per_MHz_x1000 / 1) % 10);
+#else
+  if (User_Time < Too_Small_Time)
+  {
+    printf ("Measured time too small to obtain meaningful results\n");
+    printf ("Please increase number of runs\n");
+    printf ("\n");
+  }
+  else
+  {
+#ifdef TIME
+    Microseconds = (float) User_Time * Mic_secs_Per_Second
+                        / (float) Number_Of_Runs;
+    Dhrystones_Per_Second = (float) Number_Of_Runs / (float) User_Time;
+#else
+    Microseconds = (float) User_Time * Mic_secs_Per_Second
+                        / ((float) HZ * ((float) Number_Of_Runs));
+    Dhrystones_Per_Second = ((float) HZ * (float) Number_Of_Runs)
+                        / (float) User_Time;
+#endif
+    printf ("Microseconds for one run through Dhrystone: ");
+    printf ("%6.1f \n", Microseconds);
+    printf ("Dhrystones per Second:                      ");
+    printf ("%6.1f \n", Dhrystones_Per_Second);
+    printf ("\n");
+  }
+#endif
+
+}
+
+
+Proc_1 (Ptr_Val_Par)
+/******************/
+
+REG Rec_Pointer Ptr_Val_Par;
+    /* executed once */
+{
+  REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp;
+                                        /* == Ptr_Glob_Next */
+  /* Local variable, initialized with Ptr_Val_Par->Ptr_Comp,    */
+  /* corresponds to "rename" in Ada, "with" in Pascal           */
+
+  structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob);
+  Ptr_Val_Par->variant.var_1.Int_Comp = 5;
+  Next_Record->variant.var_1.Int_Comp
+        = Ptr_Val_Par->variant.var_1.Int_Comp;
+  Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp;
+  Proc_3 (&Next_Record->Ptr_Comp);
+    /* Ptr_Val_Par->Ptr_Comp->Ptr_Comp
+                        == Ptr_Glob->Ptr_Comp */
+  if (Next_Record->Discr == Ident_1)
+    /* then, executed */
+  {
+    Next_Record->variant.var_1.Int_Comp = 6;
+    Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp,
+           &Next_Record->variant.var_1.Enum_Comp);
+    Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp;
+    Proc_7 (Next_Record->variant.var_1.Int_Comp, 10,
+           &Next_Record->variant.var_1.Int_Comp);
+  }
+  else /* not executed */
+    structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp);
+} /* Proc_1 */
+
+
+Proc_2 (Int_Par_Ref)
+/******************/
+    /* executed once */
+    /* *Int_Par_Ref == 1, becomes 4 */
+
+One_Fifty   *Int_Par_Ref;
+{
+  One_Fifty  Int_Loc;
+  Enumeration   Enum_Loc;
+
+  Int_Loc = *Int_Par_Ref + 10;
+  do /* executed once */
+    if (Ch_1_Glob == 'A')
+      /* then, executed */
+    {
+      Int_Loc -= 1;
+      *Int_Par_Ref = Int_Loc - Int_Glob;
+      Enum_Loc = Ident_1;
+    } /* if */
+  while (Enum_Loc != Ident_1); /* true */
+} /* Proc_2 */
+
+
+Proc_3 (Ptr_Ref_Par)
+/******************/
+    /* executed once */
+    /* Ptr_Ref_Par becomes Ptr_Glob */
+
+Rec_Pointer *Ptr_Ref_Par;
+
+{
+  if (Ptr_Glob != Null)
+    /* then, executed */
+    *Ptr_Ref_Par = Ptr_Glob->Ptr_Comp;
+  Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp);
+} /* Proc_3 */
+
+
+Proc_4 () /* without parameters */
+/*******/
+    /* executed once */
+{
+  Boolean Bool_Loc;
+
+  Bool_Loc = Ch_1_Glob == 'A';
+  Bool_Glob = Bool_Loc | Bool_Glob;
+  Ch_2_Glob = 'B';
+} /* Proc_4 */
+
+
+Proc_5 () /* without parameters */
+/*******/
+    /* executed once */
+{
+  Ch_1_Glob = 'A';
+  Bool_Glob = false;
+} /* Proc_5 */
+
+
+        /* Procedure for the assignment of structures,          */
+        /* if the C compiler doesn't support this feature       */
+#ifdef  NOSTRUCTASSIGN
+memcpy (d, s, l)
+register char   *d;
+register char   *s;
+register int    l;
+{
+        while (l--) *d++ = *s++;
+}
+#endif
+
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/dhrystone/dhry_1_orig.c b/verilog/rtl/softshell/third_party/picorv32/dhrystone/dhry_1_orig.c
new file mode 100644
index 0000000..848fc5b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/dhrystone/dhry_1_orig.c
@@ -0,0 +1,385 @@
+/*
+ ****************************************************************************
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *
+ *  Version:    C, Version 2.1
+ *
+ *  File:       dhry_1.c (part 2 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *
+ ****************************************************************************
+ */
+
+#include "dhry.h"
+
+/* Global Variables: */
+
+Rec_Pointer     Ptr_Glob,
+                Next_Ptr_Glob;
+int             Int_Glob;
+Boolean         Bool_Glob;
+char            Ch_1_Glob,
+                Ch_2_Glob;
+int             Arr_1_Glob [50];
+int             Arr_2_Glob [50] [50];
+
+extern char     *malloc ();
+Enumeration     Func_1 ();
+  /* forward declaration necessary since Enumeration may not simply be int */
+
+#ifndef REG
+        Boolean Reg = false;
+#define REG
+        /* REG becomes defined as empty */
+        /* i.e. no register variables   */
+#else
+        Boolean Reg = true;
+#endif
+
+/* variables for time measurement: */
+
+#ifdef TIMES
+struct tms      time_info;
+extern  int     times ();
+                /* see library function "times" */
+#define Too_Small_Time 120
+                /* Measurements should last at least about 2 seconds */
+#endif
+#ifdef TIME
+extern long     time();
+                /* see library function "time"  */
+#define Too_Small_Time 2
+                /* Measurements should last at least 2 seconds */
+#endif
+
+long            Begin_Time,
+                End_Time,
+                User_Time;
+float           Microseconds,
+                Dhrystones_Per_Second;
+
+/* end of variables for time measurement */
+
+
+main ()
+/*****/
+
+  /* main program, corresponds to procedures        */
+  /* Main and Proc_0 in the Ada version             */
+{
+        One_Fifty       Int_1_Loc;
+  REG   One_Fifty       Int_2_Loc;
+        One_Fifty       Int_3_Loc;
+  REG   char            Ch_Index;
+        Enumeration     Enum_Loc;
+        Str_30          Str_1_Loc;
+        Str_30          Str_2_Loc;
+  REG   int             Run_Index;
+  REG   int             Number_Of_Runs;
+
+  /* Initializations */
+
+  Next_Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
+  Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
+
+  Ptr_Glob->Ptr_Comp                    = Next_Ptr_Glob;
+  Ptr_Glob->Discr                       = Ident_1;
+  Ptr_Glob->variant.var_1.Enum_Comp     = Ident_3;
+  Ptr_Glob->variant.var_1.Int_Comp      = 40;
+  strcpy (Ptr_Glob->variant.var_1.Str_Comp,
+          "DHRYSTONE PROGRAM, SOME STRING");
+  strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING");
+
+  Arr_2_Glob [8][7] = 10;
+        /* Was missing in published program. Without this statement,    */
+        /* Arr_2_Glob [8][7] would have an undefined value.             */
+        /* Warning: With 16-Bit processors and Number_Of_Runs > 32000,  */
+        /* overflow may occur for this array element.                   */
+
+  printf ("\n");
+  printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n");
+  printf ("\n");
+  if (Reg)
+  {
+    printf ("Program compiled with 'register' attribute\n");
+    printf ("\n");
+  }
+  else
+  {
+    printf ("Program compiled without 'register' attribute\n");
+    printf ("\n");
+  }
+  printf ("Please give the number of runs through the benchmark: ");
+  {
+    int n;
+    scanf ("%d", &n);
+    Number_Of_Runs = n;
+  }
+  printf ("\n");
+
+  printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs);
+
+  /***************/
+  /* Start timer */
+  /***************/
+
+#ifdef TIMES
+  times (&time_info);
+  Begin_Time = (long) time_info.tms_utime;
+#endif
+#ifdef TIME
+  Begin_Time = time ( (long *) 0);
+#endif
+
+  for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index)
+  {
+
+    Proc_5();
+    Proc_4();
+      /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */
+    Int_1_Loc = 2;
+    Int_2_Loc = 3;
+    strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
+    Enum_Loc = Ident_2;
+    Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc);
+      /* Bool_Glob == 1 */
+    while (Int_1_Loc < Int_2_Loc)  /* loop body executed once */
+    {
+      Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc;
+        /* Int_3_Loc == 7 */
+      Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc);
+        /* Int_3_Loc == 7 */
+      Int_1_Loc += 1;
+    } /* while */
+      /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+    Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc);
+      /* Int_Glob == 5 */
+    Proc_1 (Ptr_Glob);
+    for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index)
+                             /* loop body executed twice */
+    {
+      if (Enum_Loc == Func_1 (Ch_Index, 'C'))
+          /* then, not executed */
+        {
+        Proc_6 (Ident_1, &Enum_Loc);
+        strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING");
+        Int_2_Loc = Run_Index;
+        Int_Glob = Run_Index;
+        }
+    }
+      /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+    Int_2_Loc = Int_2_Loc * Int_1_Loc;
+    Int_1_Loc = Int_2_Loc / Int_3_Loc;
+    Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc;
+      /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */
+    Proc_2 (&Int_1_Loc);
+      /* Int_1_Loc == 5 */
+
+  } /* loop "for Run_Index" */
+
+  /**************/
+  /* Stop timer */
+  /**************/
+
+#ifdef TIMES
+  times (&time_info);
+  End_Time = (long) time_info.tms_utime;
+#endif
+#ifdef TIME
+  End_Time = time ( (long *) 0);
+#endif
+
+  printf ("Execution ends\n");
+  printf ("\n");
+  printf ("Final values of the variables used in the benchmark:\n");
+  printf ("\n");
+  printf ("Int_Glob:            %d\n", Int_Glob);
+  printf ("        should be:   %d\n", 5);
+  printf ("Bool_Glob:           %d\n", Bool_Glob);
+  printf ("        should be:   %d\n", 1);
+  printf ("Ch_1_Glob:           %c\n", Ch_1_Glob);
+  printf ("        should be:   %c\n", 'A');
+  printf ("Ch_2_Glob:           %c\n", Ch_2_Glob);
+  printf ("        should be:   %c\n", 'B');
+  printf ("Arr_1_Glob[8]:       %d\n", Arr_1_Glob[8]);
+  printf ("        should be:   %d\n", 7);
+  printf ("Arr_2_Glob[8][7]:    %d\n", Arr_2_Glob[8][7]);
+  printf ("        should be:   Number_Of_Runs + 10\n");
+  printf ("Ptr_Glob->\n");
+  printf ("  Ptr_Comp:          %d\n", (int) Ptr_Glob->Ptr_Comp);
+  printf ("        should be:   (implementation-dependent)\n");
+  printf ("  Discr:             %d\n", Ptr_Glob->Discr);
+  printf ("        should be:   %d\n", 0);
+  printf ("  Enum_Comp:         %d\n", Ptr_Glob->variant.var_1.Enum_Comp);
+  printf ("        should be:   %d\n", 2);
+  printf ("  Int_Comp:          %d\n", Ptr_Glob->variant.var_1.Int_Comp);
+  printf ("        should be:   %d\n", 17);
+  printf ("  Str_Comp:          %s\n", Ptr_Glob->variant.var_1.Str_Comp);
+  printf ("        should be:   DHRYSTONE PROGRAM, SOME STRING\n");
+  printf ("Next_Ptr_Glob->\n");
+  printf ("  Ptr_Comp:          %d\n", (int) Next_Ptr_Glob->Ptr_Comp);
+  printf ("        should be:   (implementation-dependent), same as above\n");
+  printf ("  Discr:             %d\n", Next_Ptr_Glob->Discr);
+  printf ("        should be:   %d\n", 0);
+  printf ("  Enum_Comp:         %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp);
+  printf ("        should be:   %d\n", 1);
+  printf ("  Int_Comp:          %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp);
+  printf ("        should be:   %d\n", 18);
+  printf ("  Str_Comp:          %s\n",
+                                Next_Ptr_Glob->variant.var_1.Str_Comp);
+  printf ("        should be:   DHRYSTONE PROGRAM, SOME STRING\n");
+  printf ("Int_1_Loc:           %d\n", Int_1_Loc);
+  printf ("        should be:   %d\n", 5);
+  printf ("Int_2_Loc:           %d\n", Int_2_Loc);
+  printf ("        should be:   %d\n", 13);
+  printf ("Int_3_Loc:           %d\n", Int_3_Loc);
+  printf ("        should be:   %d\n", 7);
+  printf ("Enum_Loc:            %d\n", Enum_Loc);
+  printf ("        should be:   %d\n", 1);
+  printf ("Str_1_Loc:           %s\n", Str_1_Loc);
+  printf ("        should be:   DHRYSTONE PROGRAM, 1'ST STRING\n");
+  printf ("Str_2_Loc:           %s\n", Str_2_Loc);
+  printf ("        should be:   DHRYSTONE PROGRAM, 2'ND STRING\n");
+  printf ("\n");
+
+  User_Time = End_Time - Begin_Time;
+
+  if (User_Time < Too_Small_Time)
+  {
+    printf ("Measured time too small to obtain meaningful results\n");
+    printf ("Please increase number of runs\n");
+    printf ("\n");
+  }
+  else
+  {
+#ifdef TIME
+    Microseconds = (float) User_Time * Mic_secs_Per_Second
+                        / (float) Number_Of_Runs;
+    Dhrystones_Per_Second = (float) Number_Of_Runs / (float) User_Time;
+#else
+    Microseconds = (float) User_Time * Mic_secs_Per_Second
+                        / ((float) HZ * ((float) Number_Of_Runs));
+    Dhrystones_Per_Second = ((float) HZ * (float) Number_Of_Runs)
+                        / (float) User_Time;
+#endif
+    printf ("Microseconds for one run through Dhrystone: ");
+    printf ("%6.1f \n", Microseconds);
+    printf ("Dhrystones per Second:                      ");
+    printf ("%6.1f \n", Dhrystones_Per_Second);
+    printf ("\n");
+  }
+
+}
+
+
+Proc_1 (Ptr_Val_Par)
+/******************/
+
+REG Rec_Pointer Ptr_Val_Par;
+    /* executed once */
+{
+  REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp;
+                                        /* == Ptr_Glob_Next */
+  /* Local variable, initialized with Ptr_Val_Par->Ptr_Comp,    */
+  /* corresponds to "rename" in Ada, "with" in Pascal           */
+
+  structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob);
+  Ptr_Val_Par->variant.var_1.Int_Comp = 5;
+  Next_Record->variant.var_1.Int_Comp
+        = Ptr_Val_Par->variant.var_1.Int_Comp;
+  Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp;
+  Proc_3 (&Next_Record->Ptr_Comp);
+    /* Ptr_Val_Par->Ptr_Comp->Ptr_Comp
+                        == Ptr_Glob->Ptr_Comp */
+  if (Next_Record->Discr == Ident_1)
+    /* then, executed */
+  {
+    Next_Record->variant.var_1.Int_Comp = 6;
+    Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp,
+           &Next_Record->variant.var_1.Enum_Comp);
+    Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp;
+    Proc_7 (Next_Record->variant.var_1.Int_Comp, 10,
+           &Next_Record->variant.var_1.Int_Comp);
+  }
+  else /* not executed */
+    structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp);
+} /* Proc_1 */
+
+
+Proc_2 (Int_Par_Ref)
+/******************/
+    /* executed once */
+    /* *Int_Par_Ref == 1, becomes 4 */
+
+One_Fifty   *Int_Par_Ref;
+{
+  One_Fifty  Int_Loc;
+  Enumeration   Enum_Loc;
+
+  Int_Loc = *Int_Par_Ref + 10;
+  do /* executed once */
+    if (Ch_1_Glob == 'A')
+      /* then, executed */
+    {
+      Int_Loc -= 1;
+      *Int_Par_Ref = Int_Loc - Int_Glob;
+      Enum_Loc = Ident_1;
+    } /* if */
+  while (Enum_Loc != Ident_1); /* true */
+} /* Proc_2 */
+
+
+Proc_3 (Ptr_Ref_Par)
+/******************/
+    /* executed once */
+    /* Ptr_Ref_Par becomes Ptr_Glob */
+
+Rec_Pointer *Ptr_Ref_Par;
+
+{
+  if (Ptr_Glob != Null)
+    /* then, executed */
+    *Ptr_Ref_Par = Ptr_Glob->Ptr_Comp;
+  Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp);
+} /* Proc_3 */
+
+
+Proc_4 () /* without parameters */
+/*******/
+    /* executed once */
+{
+  Boolean Bool_Loc;
+
+  Bool_Loc = Ch_1_Glob == 'A';
+  Bool_Glob = Bool_Loc | Bool_Glob;
+  Ch_2_Glob = 'B';
+} /* Proc_4 */
+
+
+Proc_5 () /* without parameters */
+/*******/
+    /* executed once */
+{
+  Ch_1_Glob = 'A';
+  Bool_Glob = false;
+} /* Proc_5 */
+
+
+        /* Procedure for the assignment of structures,          */
+        /* if the C compiler doesn't support this feature       */
+#ifdef  NOSTRUCTASSIGN
+memcpy (d, s, l)
+register char   *d;
+register char   *s;
+register int    l;
+{
+        while (l--) *d++ = *s++;
+}
+#endif
+
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/dhrystone/dhry_2.c b/verilog/rtl/softshell/third_party/picorv32/dhrystone/dhry_2.c
new file mode 100644
index 0000000..ac5be3b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/dhrystone/dhry_2.c
@@ -0,0 +1,192 @@
+/*
+ ****************************************************************************
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *
+ *  Version:    C, Version 2.1
+ *
+ *  File:       dhry_2.c (part 3 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *
+ ****************************************************************************
+ */
+
+#include "dhry.h"
+
+#ifndef REG
+#define REG
+        /* REG becomes defined as empty */
+        /* i.e. no register variables   */
+#endif
+
+extern  int     Int_Glob;
+extern  char    Ch_1_Glob;
+
+
+Proc_6 (Enum_Val_Par, Enum_Ref_Par)
+/*********************************/
+    /* executed once */
+    /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */
+
+Enumeration  Enum_Val_Par;
+Enumeration *Enum_Ref_Par;
+{
+  *Enum_Ref_Par = Enum_Val_Par;
+  if (! Func_3 (Enum_Val_Par))
+    /* then, not executed */
+    *Enum_Ref_Par = Ident_4;
+  switch (Enum_Val_Par)
+  {
+    case Ident_1:
+      *Enum_Ref_Par = Ident_1;
+      break;
+    case Ident_2:
+      if (Int_Glob > 100)
+        /* then */
+      *Enum_Ref_Par = Ident_1;
+      else *Enum_Ref_Par = Ident_4;
+      break;
+    case Ident_3: /* executed */
+      *Enum_Ref_Par = Ident_2;
+      break;
+    case Ident_4: break;
+    case Ident_5:
+      *Enum_Ref_Par = Ident_3;
+      break;
+  } /* switch */
+} /* Proc_6 */
+
+
+Proc_7 (Int_1_Par_Val, Int_2_Par_Val, Int_Par_Ref)
+/**********************************************/
+    /* executed three times                                      */
+    /* first call:      Int_1_Par_Val == 2, Int_2_Par_Val == 3,  */
+    /*                  Int_Par_Ref becomes 7                    */
+    /* second call:     Int_1_Par_Val == 10, Int_2_Par_Val == 5, */
+    /*                  Int_Par_Ref becomes 17                   */
+    /* third call:      Int_1_Par_Val == 6, Int_2_Par_Val == 10, */
+    /*                  Int_Par_Ref becomes 18                   */
+One_Fifty       Int_1_Par_Val;
+One_Fifty       Int_2_Par_Val;
+One_Fifty      *Int_Par_Ref;
+{
+  One_Fifty Int_Loc;
+
+  Int_Loc = Int_1_Par_Val + 2;
+  *Int_Par_Ref = Int_2_Par_Val + Int_Loc;
+} /* Proc_7 */
+
+
+Proc_8 (Arr_1_Par_Ref, Arr_2_Par_Ref, Int_1_Par_Val, Int_2_Par_Val)
+/*********************************************************************/
+    /* executed once      */
+    /* Int_Par_Val_1 == 3 */
+    /* Int_Par_Val_2 == 7 */
+Arr_1_Dim       Arr_1_Par_Ref;
+Arr_2_Dim       Arr_2_Par_Ref;
+int             Int_1_Par_Val;
+int             Int_2_Par_Val;
+{
+  REG One_Fifty Int_Index;
+  REG One_Fifty Int_Loc;
+
+  Int_Loc = Int_1_Par_Val + 5;
+  Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val;
+  Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc];
+  Arr_1_Par_Ref [Int_Loc+30] = Int_Loc;
+  for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index)
+    Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc;
+  Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1;
+  Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc];
+  Int_Glob = 5;
+} /* Proc_8 */
+
+
+Enumeration Func_1 (Ch_1_Par_Val, Ch_2_Par_Val)
+/*************************************************/
+    /* executed three times                                         */
+    /* first call:      Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R'    */
+    /* second call:     Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C'    */
+    /* third call:      Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C'    */
+
+Capital_Letter   Ch_1_Par_Val;
+Capital_Letter   Ch_2_Par_Val;
+{
+  Capital_Letter        Ch_1_Loc;
+  Capital_Letter        Ch_2_Loc;
+
+  Ch_1_Loc = Ch_1_Par_Val;
+  Ch_2_Loc = Ch_1_Loc;
+  if (Ch_2_Loc != Ch_2_Par_Val)
+    /* then, executed */
+    return (Ident_1);
+  else  /* not executed */
+  {
+    Ch_1_Glob = Ch_1_Loc;
+    return (Ident_2);
+   }
+} /* Func_1 */
+
+
+Boolean Func_2 (Str_1_Par_Ref, Str_2_Par_Ref)
+/*************************************************/
+    /* executed once */
+    /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */
+    /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */
+
+Str_30  Str_1_Par_Ref;
+Str_30  Str_2_Par_Ref;
+{
+  REG One_Thirty        Int_Loc;
+      Capital_Letter    Ch_Loc;
+
+  Int_Loc = 2;
+  while (Int_Loc <= 2) /* loop body executed once */
+    if (Func_1 (Str_1_Par_Ref[Int_Loc],
+                Str_2_Par_Ref[Int_Loc+1]) == Ident_1)
+      /* then, executed */
+    {
+      Ch_Loc = 'A';
+      Int_Loc += 1;
+    } /* if, while */
+  if (Ch_Loc >= 'W' && Ch_Loc < 'Z')
+    /* then, not executed */
+    Int_Loc = 7;
+  if (Ch_Loc == 'R')
+    /* then, not executed */
+    return (true);
+  else /* executed */
+  {
+    if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0)
+      /* then, not executed */
+    {
+      Int_Loc += 7;
+      Int_Glob = Int_Loc;
+      return (true);
+    }
+    else /* executed */
+      return (false);
+  } /* if Ch_Loc */
+} /* Func_2 */
+
+
+Boolean Func_3 (Enum_Par_Val)
+/***************************/
+    /* executed once        */
+    /* Enum_Par_Val == Ident_3 */
+Enumeration Enum_Par_Val;
+{
+  Enumeration Enum_Loc;
+
+  Enum_Loc = Enum_Par_Val;
+  if (Enum_Loc == Ident_3)
+    /* then, executed */
+    return (true);
+  else /* not executed */
+    return (false);
+} /* Func_3 */
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/dhrystone/sections.lds b/verilog/rtl/softshell/third_party/picorv32/dhrystone/sections.lds
new file mode 100644
index 0000000..3efb873
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/dhrystone/sections.lds
@@ -0,0 +1,18 @@
+/*
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+*/
+
+SECTIONS {
+	.memory : {
+		. = 0x10000;
+		start*(.text);
+		*(.text);
+		*(*);
+		end = .;
+	}
+}
diff --git a/verilog/rtl/softshell/third_party/picorv32/dhrystone/start.S b/verilog/rtl/softshell/third_party/picorv32/dhrystone/start.S
new file mode 100644
index 0000000..9fb2359
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/dhrystone/start.S
@@ -0,0 +1,51 @@
+	.section .text
+	.global start
+	.global main
+
+start:
+	/* print "START\n" */
+	lui a0,0x10000000>>12
+	addi a1,zero,'S'
+	addi a2,zero,'T'
+	addi a3,zero,'A'
+	addi a4,zero,'R'
+	addi a5,zero,'\n'
+	sw a1,0(a0)
+	sw a2,0(a0)
+	sw a3,0(a0)
+	sw a4,0(a0)
+	sw a2,0(a0)
+	sw a5,0(a0)
+
+	/* execute some insns for "make timing" */
+	lui a0,0
+	auipc a0,0
+	slli a0,a0,0
+	slli a0,a0,31
+	addi a1,zero,0
+	sll a0,a0,a1
+	addi a1,zero,31
+	sll a0,a0,a1
+
+	/* set stack pointer */
+	lui sp,(64*1024)>>12
+
+	/* jump to main C code */
+	jal ra,main
+
+	/* print "DONE\n" */
+	lui a0,0x10000000>>12
+	addi a1,zero,'D'
+	addi a2,zero,'O'
+	addi a3,zero,'N'
+	addi a4,zero,'E'
+	addi a5,zero,'\n'
+	sw a1,0(a0)
+	sw a2,0(a0)
+	sw a3,0(a0)
+	sw a4,0(a0)
+	sw a5,0(a0)
+
+	/* trap */
+	ebreak
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/dhrystone/stdlib.c b/verilog/rtl/softshell/third_party/picorv32/dhrystone/stdlib.c
new file mode 100644
index 0000000..f88023b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/dhrystone/stdlib.c
@@ -0,0 +1,210 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+
+#include <stdarg.h>
+#include <stdint.h>
+
+extern long time();
+extern long insn();
+
+#ifdef USE_MYSTDLIB
+extern char *malloc();
+extern int printf(const char *format, ...);
+
+extern void *memcpy(void *dest, const void *src, long n);
+extern char *strcpy(char *dest, const char *src);
+extern int strcmp(const char *s1, const char *s2);
+
+char heap_memory[1024];
+int heap_memory_used = 0;
+#endif
+
+long time()
+{
+	int cycles;
+	asm volatile ("rdcycle %0" : "=r"(cycles));
+	// printf("[time() -> %d]", cycles);
+	return cycles;
+}
+
+long insn()
+{
+	int insns;
+	asm volatile ("rdinstret %0" : "=r"(insns));
+	// printf("[insn() -> %d]", insns);
+	return insns;
+}
+
+#ifdef USE_MYSTDLIB
+char *malloc(int size)
+{
+	char *p = heap_memory + heap_memory_used;
+	// printf("[malloc(%d) -> %d (%d..%d)]", size, (int)p, heap_memory_used, heap_memory_used + size);
+	heap_memory_used += size;
+	if (heap_memory_used > 1024)
+		asm volatile ("ebreak");
+	return p;
+}
+
+static void printf_c(int c)
+{
+	*((volatile int*)0x10000000) = c;
+}
+
+static void printf_s(char *p)
+{
+	while (*p)
+		*((volatile int*)0x10000000) = *(p++);
+}
+
+static void printf_d(int val)
+{
+	char buffer[32];
+	char *p = buffer;
+	if (val < 0) {
+		printf_c('-');
+		val = -val;
+	}
+	while (val || p == buffer) {
+		*(p++) = '0' + val % 10;
+		val = val / 10;
+	}
+	while (p != buffer)
+		printf_c(*(--p));
+}
+
+int printf(const char *format, ...)
+{
+	int i;
+	va_list ap;
+
+	va_start(ap, format);
+
+	for (i = 0; format[i]; i++)
+		if (format[i] == '%') {
+			while (format[++i]) {
+				if (format[i] == 'c') {
+					printf_c(va_arg(ap,int));
+					break;
+				}
+				if (format[i] == 's') {
+					printf_s(va_arg(ap,char*));
+					break;
+				}
+				if (format[i] == 'd') {
+					printf_d(va_arg(ap,int));
+					break;
+				}
+			}
+		} else
+			printf_c(format[i]);
+
+	va_end(ap);
+}
+
+void *memcpy(void *aa, const void *bb, long n)
+{
+	// printf("**MEMCPY**\n");
+	char *a = aa;
+	const char *b = bb;
+	while (n--) *(a++) = *(b++);
+	return aa;
+}
+
+char *strcpy(char* dst, const char* src)
+{
+	char *r = dst;
+
+	while ((((uint32_t)dst | (uint32_t)src) & 3) != 0)
+	{
+		char c = *(src++);
+		*(dst++) = c;
+		if (!c) return r;
+	}
+
+	while (1)
+	{
+		uint32_t v = *(uint32_t*)src;
+
+		if (__builtin_expect((((v) - 0x01010101UL) & ~(v) & 0x80808080UL), 0))
+		{
+			dst[0] = v & 0xff;
+			if ((v & 0xff) == 0)
+				return r;
+			v = v >> 8;
+
+			dst[1] = v & 0xff;
+			if ((v & 0xff) == 0)
+				return r;
+			v = v >> 8;
+
+			dst[2] = v & 0xff;
+			if ((v & 0xff) == 0)
+				return r;
+			v = v >> 8;
+
+			dst[3] = v & 0xff;
+			return r;
+		}
+
+		*(uint32_t*)dst = v;
+		src += 4;
+		dst += 4;
+	}
+}
+
+int strcmp(const char *s1, const char *s2)
+{
+	while ((((uint32_t)s1 | (uint32_t)s2) & 3) != 0)
+	{
+		char c1 = *(s1++);
+		char c2 = *(s2++);
+
+		if (c1 != c2)
+			return c1 < c2 ? -1 : +1;
+		else if (!c1)
+			return 0;
+	}
+
+	while (1)
+	{
+		uint32_t v1 = *(uint32_t*)s1;
+		uint32_t v2 = *(uint32_t*)s2;
+
+		if (__builtin_expect(v1 != v2, 0))
+		{
+			char c1, c2;
+
+			c1 = v1 & 0xff, c2 = v2 & 0xff;
+			if (c1 != c2) return c1 < c2 ? -1 : +1;
+			if (!c1) return 0;
+			v1 = v1 >> 8, v2 = v2 >> 8;
+
+			c1 = v1 & 0xff, c2 = v2 & 0xff;
+			if (c1 != c2) return c1 < c2 ? -1 : +1;
+			if (!c1) return 0;
+			v1 = v1 >> 8, v2 = v2 >> 8;
+
+			c1 = v1 & 0xff, c2 = v2 & 0xff;
+			if (c1 != c2) return c1 < c2 ? -1 : +1;
+			if (!c1) return 0;
+			v1 = v1 >> 8, v2 = v2 >> 8;
+
+			c1 = v1 & 0xff, c2 = v2 & 0xff;
+			if (c1 != c2) return c1 < c2 ? -1 : +1;
+			return 0;
+		}
+
+		if (__builtin_expect((((v1) - 0x01010101UL) & ~(v1) & 0x80808080UL), 0))
+			return 0;
+
+		s1 += 4;
+		s2 += 4;
+	}
+}
+#endif
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/dhrystone/syscalls.c b/verilog/rtl/softshell/third_party/picorv32/dhrystone/syscalls.c
new file mode 100644
index 0000000..8ea84ca
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/dhrystone/syscalls.c
@@ -0,0 +1,95 @@
+// An extremely minimalist syscalls.c for newlib
+// Based on riscv newlib libgloss/riscv/sys_*.c
+// Written by Clifford Wolf.
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define UNIMPL_FUNC(_f) ".globl " #_f "\n.type " #_f ", @function\n" #_f ":\n"
+
+asm (
+	".text\n"
+	".align 2\n"
+	UNIMPL_FUNC(_open)
+	UNIMPL_FUNC(_openat)
+	UNIMPL_FUNC(_lseek)
+	UNIMPL_FUNC(_stat)
+	UNIMPL_FUNC(_lstat)
+	UNIMPL_FUNC(_fstatat)
+	UNIMPL_FUNC(_isatty)
+	UNIMPL_FUNC(_access)
+	UNIMPL_FUNC(_faccessat)
+	UNIMPL_FUNC(_link)
+	UNIMPL_FUNC(_unlink)
+	UNIMPL_FUNC(_execve)
+	UNIMPL_FUNC(_getpid)
+	UNIMPL_FUNC(_fork)
+	UNIMPL_FUNC(_kill)
+	UNIMPL_FUNC(_wait)
+	UNIMPL_FUNC(_times)
+	UNIMPL_FUNC(_gettimeofday)
+	UNIMPL_FUNC(_ftime)
+	UNIMPL_FUNC(_utime)
+	UNIMPL_FUNC(_chown)
+	UNIMPL_FUNC(_chmod)
+	UNIMPL_FUNC(_chdir)
+	UNIMPL_FUNC(_getcwd)
+	UNIMPL_FUNC(_sysconf)
+	"j unimplemented_syscall\n"
+);
+
+void unimplemented_syscall()
+{
+	const char *p = "Unimplemented system call called!\n";
+	while (*p)
+		*(volatile int*)0x10000000 = *(p++);
+	asm volatile ("ebreak");
+	__builtin_unreachable();
+}
+
+ssize_t _read(int file, void *ptr, size_t len)
+{
+	// always EOF
+	return 0;
+}
+
+ssize_t _write(int file, const void *ptr, size_t len)
+{
+	const void *eptr = ptr + len;
+	while (ptr != eptr)
+		*(volatile int*)0x10000000 = *(char*)(ptr++);
+	return len;
+}
+
+int _close(int file)
+{
+	// close is called before _exit()
+	return 0;
+}
+
+int _fstat(int file, struct stat *st)
+{
+	// fstat is called during libc startup
+	errno = ENOENT;
+	return -1;
+}
+
+void *_sbrk(ptrdiff_t incr)
+{
+	extern unsigned char _end[];   // Defined by linker
+	static unsigned long heap_end;
+
+	if (heap_end == 0)
+		heap_end = (long)_end;
+
+	heap_end += incr;
+	return (void *)(heap_end - incr);
+}
+
+void _exit(int exit_status)
+{
+	asm volatile ("ebreak");
+	__builtin_unreachable();
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/dhrystone/testbench.v b/verilog/rtl/softshell/third_party/picorv32/dhrystone/testbench.v
new file mode 100644
index 0000000..9c365a6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/dhrystone/testbench.v
@@ -0,0 +1,126 @@
+`timescale 1 ns / 1 ps
+
+module testbench;
+	reg clk = 1;
+	reg resetn = 0;
+	wire trap;
+
+	always #5 clk = ~clk;
+
+	initial begin
+		repeat (100) @(posedge clk);
+		resetn <= 1;
+	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;
+	reg  [31:0] mem_rdata;
+
+	wire mem_la_read;
+	wire mem_la_write;
+	wire [31:0] mem_la_addr;
+	wire [31:0] mem_la_wdata;
+	wire [3:0] mem_la_wstrb;
+
+	wire trace_valid;
+	wire [35:0] trace_data;
+
+	picorv32 #(
+		.BARREL_SHIFTER(1),
+		.ENABLE_FAST_MUL(1),
+		.ENABLE_DIV(1),
+		.PROGADDR_RESET('h10000),
+		.STACKADDR('h10000),
+		.ENABLE_TRACE(1)
+	) uut (
+		.clk         (clk        ),
+		.resetn      (resetn     ),
+		.trap        (trap       ),
+		.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  ),
+		.mem_la_read (mem_la_read ),
+		.mem_la_write(mem_la_write),
+		.mem_la_addr (mem_la_addr ),
+		.mem_la_wdata(mem_la_wdata),
+		.mem_la_wstrb(mem_la_wstrb),
+		.trace_valid (trace_valid),
+		.trace_data  (trace_data )
+	);
+
+	reg [7:0] memory [0:256*1024-1];
+	initial $readmemh("dhry.hex", memory);
+
+	assign mem_ready = 1;
+
+	always @(posedge clk) begin
+		mem_rdata[ 7: 0] <= mem_la_read ? memory[mem_la_addr + 0] : 'bx;
+		mem_rdata[15: 8] <= mem_la_read ? memory[mem_la_addr + 1] : 'bx;
+		mem_rdata[23:16] <= mem_la_read ? memory[mem_la_addr + 2] : 'bx;
+		mem_rdata[31:24] <= mem_la_read ? memory[mem_la_addr + 3] : 'bx;
+		if (mem_la_write) begin
+			case (mem_la_addr)
+				32'h1000_0000: begin
+`ifndef TIMING
+					$write("%c", mem_la_wdata);
+					$fflush();
+`endif
+				end
+				default: begin
+					if (mem_la_wstrb[0]) memory[mem_la_addr + 0] <= mem_la_wdata[ 7: 0];
+					if (mem_la_wstrb[1]) memory[mem_la_addr + 1] <= mem_la_wdata[15: 8];
+					if (mem_la_wstrb[2]) memory[mem_la_addr + 2] <= mem_la_wdata[23:16];
+					if (mem_la_wstrb[3]) memory[mem_la_addr + 3] <= mem_la_wdata[31:24];
+				end
+			endcase
+		end
+	end
+
+	initial begin
+		$dumpfile("testbench.vcd");
+		$dumpvars(0, testbench);
+	end
+
+	integer trace_file;
+
+	initial begin
+		if ($test$plusargs("trace")) begin
+			trace_file = $fopen("testbench.trace", "w");
+			repeat (10) @(posedge clk);
+			while (!trap) begin
+				@(posedge clk);
+				if (trace_valid)
+					$fwrite(trace_file, "%x\n", trace_data);
+			end
+			$fclose(trace_file);
+			$display("Finished writing testbench.trace.");
+		end
+	end
+
+	always @(posedge clk) begin
+		if (resetn && trap) begin
+			repeat (10) @(posedge clk);
+			$display("TRAP");
+			$finish;
+		end
+	end
+
+`ifdef TIMING
+	initial begin
+		repeat (100000) @(posedge clk);
+		$finish;
+	end
+	always @(posedge clk) begin
+		if (uut.dbg_next)
+			$display("## %-s %d", uut.dbg_ascii_instr ? uut.dbg_ascii_instr : "pcpi", uut.count_cycle);
+	end
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/dhrystone/testbench_nola.v b/verilog/rtl/softshell/third_party/picorv32/dhrystone/testbench_nola.v
new file mode 100644
index 0000000..b1a154c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/dhrystone/testbench_nola.v
@@ -0,0 +1,95 @@
+// A version of the dhrystone test bench that isn't using the look-ahead interface
+
+`timescale 1 ns / 1 ps
+
+module testbench;
+	reg clk = 1;
+	reg resetn = 0;
+	wire trap;
+
+	always #5 clk = ~clk;
+
+	initial begin
+		repeat (100) @(posedge clk);
+		resetn <= 1;
+	end
+
+	wire mem_valid;
+	wire mem_instr;
+	reg  mem_ready;
+	wire [31:0] mem_addr;
+	wire [31:0] mem_wdata;
+	wire [3:0]  mem_wstrb;
+	reg  [31:0] mem_rdata;
+
+	picorv32 #(
+		.BARREL_SHIFTER(1),
+		.ENABLE_FAST_MUL(1),
+		.ENABLE_DIV(1),
+		.PROGADDR_RESET('h10000),
+		.STACKADDR('h10000)
+	) uut (
+		.clk         (clk        ),
+		.resetn      (resetn     ),
+		.trap        (trap       ),
+		.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  )
+	);
+
+	reg [7:0] memory [0:256*1024-1];
+	initial $readmemh("dhry.hex", memory);
+
+	always @(posedge clk) begin
+		mem_ready <= 1'b0;
+
+		mem_rdata[ 7: 0] <= 'bx;
+		mem_rdata[15: 8] <= 'bx;
+		mem_rdata[23:16] <= 'bx;
+		mem_rdata[31:24] <= 'bx;
+
+		if (mem_valid & !mem_ready) begin
+			if (|mem_wstrb) begin
+				mem_ready <= 1'b1;
+
+				case (mem_addr)
+					32'h1000_0000: begin
+						$write("%c", mem_wdata);
+						$fflush();
+					end
+					default: begin
+						if (mem_wstrb[0]) memory[mem_addr + 0] <= mem_wdata[ 7: 0];
+						if (mem_wstrb[1]) memory[mem_addr + 1] <= mem_wdata[15: 8];
+						if (mem_wstrb[2]) memory[mem_addr + 2] <= mem_wdata[23:16];
+						if (mem_wstrb[3]) memory[mem_addr + 3] <= mem_wdata[31:24];
+					end
+				endcase
+			end
+			else begin
+				mem_ready <= 1'b1;
+
+				mem_rdata[ 7: 0] <= memory[mem_addr + 0];
+				mem_rdata[15: 8] <= memory[mem_addr + 1];
+				mem_rdata[23:16] <= memory[mem_addr + 2];
+				mem_rdata[31:24] <= memory[mem_addr + 3];
+			end
+		end
+	end
+
+	initial begin
+		$dumpfile("testbench_nola.vcd");
+		$dumpvars(0, testbench);
+	end
+
+	always @(posedge clk) begin
+		if (resetn && trap) begin
+			repeat (10) @(posedge clk);
+			$display("TRAP");
+			$finish;
+		end
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/firmware/README b/verilog/rtl/softshell/third_party/picorv32/firmware/README
new file mode 100644
index 0000000..2ade487
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/firmware/README
@@ -0,0 +1,2 @@
+A simple test firmware. This code is in the public domain. Simply copy whatever
+you can use.
diff --git a/verilog/rtl/softshell/third_party/picorv32/firmware/custom_ops.S b/verilog/rtl/softshell/third_party/picorv32/firmware/custom_ops.S
new file mode 100644
index 0000000..71889b9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/firmware/custom_ops.S
@@ -0,0 +1,102 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+
+#define regnum_q0   0
+#define regnum_q1   1
+#define regnum_q2   2
+#define regnum_q3   3
+
+#define regnum_x0   0
+#define regnum_x1   1
+#define regnum_x2   2
+#define regnum_x3   3
+#define regnum_x4   4
+#define regnum_x5   5
+#define regnum_x6   6
+#define regnum_x7   7
+#define regnum_x8   8
+#define regnum_x9   9
+#define regnum_x10 10
+#define regnum_x11 11
+#define regnum_x12 12
+#define regnum_x13 13
+#define regnum_x14 14
+#define regnum_x15 15
+#define regnum_x16 16
+#define regnum_x17 17
+#define regnum_x18 18
+#define regnum_x19 19
+#define regnum_x20 20
+#define regnum_x21 21
+#define regnum_x22 22
+#define regnum_x23 23
+#define regnum_x24 24
+#define regnum_x25 25
+#define regnum_x26 26
+#define regnum_x27 27
+#define regnum_x28 28
+#define regnum_x29 29
+#define regnum_x30 30
+#define regnum_x31 31
+
+#define regnum_zero 0
+#define regnum_ra   1
+#define regnum_sp   2
+#define regnum_gp   3
+#define regnum_tp   4
+#define regnum_t0   5
+#define regnum_t1   6
+#define regnum_t2   7
+#define regnum_s0   8
+#define regnum_s1   9
+#define regnum_a0  10
+#define regnum_a1  11
+#define regnum_a2  12
+#define regnum_a3  13
+#define regnum_a4  14
+#define regnum_a5  15
+#define regnum_a6  16
+#define regnum_a7  17
+#define regnum_s2  18
+#define regnum_s3  19
+#define regnum_s4  20
+#define regnum_s5  21
+#define regnum_s6  22
+#define regnum_s7  23
+#define regnum_s8  24
+#define regnum_s9  25
+#define regnum_s10 26
+#define regnum_s11 27
+#define regnum_t3  28
+#define regnum_t4  29
+#define regnum_t5  30
+#define regnum_t6  31
+
+// x8 is s0 and also fp
+#define regnum_fp   8
+
+#define r_type_insn(_f7, _rs2, _rs1, _f3, _rd, _opc) \
+.word (((_f7) << 25) | ((_rs2) << 20) | ((_rs1) << 15) | ((_f3) << 12) | ((_rd) << 7) | ((_opc) << 0))
+
+#define picorv32_getq_insn(_rd, _qs) \
+r_type_insn(0b0000000, 0, regnum_ ## _qs, 0b100, regnum_ ## _rd, 0b0001011)
+
+#define picorv32_setq_insn(_qd, _rs) \
+r_type_insn(0b0000001, 0, regnum_ ## _rs, 0b010, regnum_ ## _qd, 0b0001011)
+
+#define picorv32_retirq_insn() \
+r_type_insn(0b0000010, 0, 0, 0b000, 0, 0b0001011)
+
+#define picorv32_maskirq_insn(_rd, _rs) \
+r_type_insn(0b0000011, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)
+
+#define picorv32_waitirq_insn(_rd) \
+r_type_insn(0b0000100, 0, 0, 0b100, regnum_ ## _rd, 0b0001011)
+
+#define picorv32_timer_insn(_rd, _rs) \
+r_type_insn(0b0000101, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/firmware/firmware.h b/verilog/rtl/softshell/third_party/picorv32/firmware/firmware.h
new file mode 100644
index 0000000..59d3f11
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/firmware/firmware.h
@@ -0,0 +1,43 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+
+#ifndef FIRMWARE_H
+#define FIRMWARE_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+// irq.c
+uint32_t *irq(uint32_t *regs, uint32_t irqs);
+
+// print.c
+void print_chr(char ch);
+void print_str(const char *p);
+void print_dec(unsigned int val);
+void print_hex(unsigned int val, int digits);
+
+// hello.c
+void hello(void);
+
+// sieve.c
+void sieve(void);
+
+// multest.c
+uint32_t hard_mul(uint32_t a, uint32_t b);
+uint32_t hard_mulh(uint32_t a, uint32_t b);
+uint32_t hard_mulhsu(uint32_t a, uint32_t b);
+uint32_t hard_mulhu(uint32_t a, uint32_t b);
+uint32_t hard_div(uint32_t a, uint32_t b);
+uint32_t hard_divu(uint32_t a, uint32_t b);
+uint32_t hard_rem(uint32_t a, uint32_t b);
+uint32_t hard_remu(uint32_t a, uint32_t b);
+void multest(void);
+
+// stats.c
+void stats(void);
+
+#endif
diff --git a/verilog/rtl/softshell/third_party/picorv32/firmware/hello.c b/verilog/rtl/softshell/third_party/picorv32/firmware/hello.c
new file mode 100644
index 0000000..b7e0b96
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/firmware/hello.c
@@ -0,0 +1,14 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+
+#include "firmware.h"
+
+void hello(void)
+{
+	print_str("hello world\n");
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/firmware/irq.c b/verilog/rtl/softshell/third_party/picorv32/firmware/irq.c
new file mode 100644
index 0000000..9fc1735
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/firmware/irq.c
@@ -0,0 +1,140 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+
+#include "firmware.h"
+
+uint32_t *irq(uint32_t *regs, uint32_t irqs)
+{
+	static unsigned int ext_irq_4_count = 0;
+	static unsigned int ext_irq_5_count = 0;
+	static unsigned int timer_irq_count = 0;
+
+	// checking compressed isa q0 reg handling
+	if ((irqs & 6) != 0) {
+		uint32_t pc = (regs[0] & 1) ? regs[0] - 3 : regs[0] - 4;
+		uint32_t instr = *(uint16_t*)pc;
+
+		if ((instr & 3) == 3)
+			instr = instr | (*(uint16_t*)(pc + 2)) << 16;
+
+		if (((instr & 3) != 3) != (regs[0] & 1)) {
+			print_str("Mismatch between q0 LSB and decoded instruction word! q0=0x");
+			print_hex(regs[0], 8);
+			print_str(", instr=0x");
+			if ((instr & 3) == 3)
+				print_hex(instr, 8);
+			else
+				print_hex(instr, 4);
+			print_str("\n");
+			__asm__ volatile ("ebreak");
+		}
+	}
+
+	if ((irqs & (1<<4)) != 0) {
+		ext_irq_4_count++;
+		// print_str("[EXT-IRQ-4]");
+	}
+
+	if ((irqs & (1<<5)) != 0) {
+		ext_irq_5_count++;
+		// print_str("[EXT-IRQ-5]");
+	}
+
+	if ((irqs & 1) != 0) {
+		timer_irq_count++;
+		// print_str("[TIMER-IRQ]");
+	}
+
+	if ((irqs & 6) != 0)
+	{
+		uint32_t pc = (regs[0] & 1) ? regs[0] - 3 : regs[0] - 4;
+		uint32_t instr = *(uint16_t*)pc;
+
+		if ((instr & 3) == 3)
+			instr = instr | (*(uint16_t*)(pc + 2)) << 16;
+
+		print_str("\n");
+		print_str("------------------------------------------------------------\n");
+
+		if ((irqs & 2) != 0) {
+			if (instr == 0x00100073 || instr == 0x9002) {
+				print_str("EBREAK instruction at 0x");
+				print_hex(pc, 8);
+				print_str("\n");
+			} else {
+				print_str("Illegal Instruction at 0x");
+				print_hex(pc, 8);
+				print_str(": 0x");
+				print_hex(instr, ((instr & 3) == 3) ? 8 : 4);
+				print_str("\n");
+			}
+		}
+
+		if ((irqs & 4) != 0) {
+			print_str("Bus error in Instruction at 0x");
+			print_hex(pc, 8);
+			print_str(": 0x");
+			print_hex(instr, ((instr & 3) == 3) ? 8 : 4);
+			print_str("\n");
+		}
+
+		for (int i = 0; i < 8; i++)
+		for (int k = 0; k < 4; k++)
+		{
+			int r = i + k*8;
+
+			if (r == 0) {
+				print_str("pc  ");
+			} else
+			if (r < 10) {
+				print_chr('x');
+				print_chr('0' + r);
+				print_chr(' ');
+				print_chr(' ');
+			} else
+			if (r < 20) {
+				print_chr('x');
+				print_chr('1');
+				print_chr('0' + r - 10);
+				print_chr(' ');
+			} else
+			if (r < 30) {
+				print_chr('x');
+				print_chr('2');
+				print_chr('0' + r - 20);
+				print_chr(' ');
+			} else {
+				print_chr('x');
+				print_chr('3');
+				print_chr('0' + r - 30);
+				print_chr(' ');
+			}
+
+			print_hex(regs[r], 8);
+			print_str(k == 3 ? "\n" : "    ");
+		}
+
+		print_str("------------------------------------------------------------\n");
+
+		print_str("Number of fast external IRQs counted: ");
+		print_dec(ext_irq_4_count);
+		print_str("\n");
+
+		print_str("Number of slow external IRQs counted: ");
+		print_dec(ext_irq_5_count);
+		print_str("\n");
+
+		print_str("Number of timer IRQs counted: ");
+		print_dec(timer_irq_count);
+		print_str("\n");
+
+		__asm__ volatile ("ebreak");
+	}
+
+	return regs;
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/firmware/makehex.py b/verilog/rtl/softshell/third_party/picorv32/firmware/makehex.py
new file mode 100644
index 0000000..419b378
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/firmware/makehex.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python3
+#
+# This is free and unencumbered software released into the public domain.
+#
+# Anyone is free to copy, modify, publish, use, compile, sell, or
+# distribute this software, either in source code form or as a compiled
+# binary, for any purpose, commercial or non-commercial, and by any
+# means.
+
+from sys import argv
+
+binfile = argv[1]
+nwords = int(argv[2])
+
+with open(binfile, "rb") as f:
+    bindata = f.read()
+
+assert len(bindata) < 4*nwords
+assert len(bindata) % 4 == 0
+
+for i in range(nwords):
+    if i < len(bindata) // 4:
+        w = bindata[4*i : 4*i+4]
+        print("%02x%02x%02x%02x" % (w[3], w[2], w[1], w[0]))
+    else:
+        print("0")
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/firmware/multest.c b/verilog/rtl/softshell/third_party/picorv32/firmware/multest.c
new file mode 100644
index 0000000..1706400
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/firmware/multest.c
@@ -0,0 +1,151 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+
+#include "firmware.h"
+
+static uint32_t xorshift32(void) {
+	static uint32_t x = 314159265;
+	x ^= x << 13;
+	x ^= x >> 17;
+	x ^= x << 5;
+	return x;
+}
+
+void multest(void)
+{
+	for (int i = 0; i < 15; i++)
+	{
+		uint32_t a = xorshift32();
+		uint32_t b = xorshift32();
+
+		switch (i)
+		{
+		case 0:
+			a = 0x80000000;
+			b = 0xFFFFFFFF;
+			break;
+		case 1:
+			a = 0;
+			b = 0;
+			break;
+		case 2:
+			a |= 0x80000000;
+			b = 0;
+			break;
+		case 3:
+			a &= 0x7FFFFFFF;
+			b = 0;
+			break;
+		}
+
+		uint64_t au = a, bu = b;
+		int64_t as = (int32_t)a, bs = (int32_t)b;
+
+		print_str("input     [");
+		print_hex(as >> 32, 8);
+		print_str("] ");
+		print_hex(a, 8);
+		print_str(" [");
+		print_hex(bs >> 32, 8);
+		print_str("] ");
+		print_hex(b, 8);
+		print_chr('\n');
+
+		uint32_t h_mul, h_mulh, h_mulhsu, h_mulhu;
+		print_str("hard mul   ");
+
+		h_mul = hard_mul(a, b);
+		print_hex(h_mul, 8);
+		print_str("  ");
+
+		h_mulh = hard_mulh(a, b);
+		print_hex(h_mulh, 8);
+		print_str("  ");
+
+		h_mulhsu = hard_mulhsu(a, b);
+		print_hex(h_mulhsu, 8);
+		print_str("  ");
+
+		h_mulhu = hard_mulhu(a, b);
+		print_hex(h_mulhu, 8);
+		print_chr('\n');
+
+		uint32_t s_mul, s_mulh, s_mulhsu, s_mulhu;
+		print_str("soft mul   ");
+
+		s_mul = a * b;
+		print_hex(s_mul, 8);
+		print_str("  ");
+
+		s_mulh = (as * bs) >> 32;
+		print_hex(s_mulh, 8);
+		print_str("  ");
+
+		s_mulhsu = (as * bu) >> 32;
+		print_hex(s_mulhsu, 8);
+		print_str("  ");
+
+		s_mulhu = (au * bu) >> 32;
+		print_hex(s_mulhu, 8);
+		print_str("  ");
+
+		if (s_mul != h_mul || s_mulh != h_mulh || s_mulhsu != h_mulhsu || s_mulhu != h_mulhu) {
+			print_str("ERROR!\n");
+			__asm__ volatile ("ebreak");
+			return;
+		}
+
+		print_str(" OK\n");
+
+		uint32_t h_div, h_divu, h_rem, h_remu;
+		print_str("hard div   ");
+
+		h_div = hard_div(a, b);
+		print_hex(h_div, 8);
+		print_str("  ");
+
+		h_divu = hard_divu(a, b);
+		print_hex(h_divu, 8);
+		print_str("  ");
+
+		h_rem = hard_rem(a, b);
+		print_hex(h_rem, 8);
+		print_str("  ");
+
+		h_remu = hard_remu(a, b);
+		print_hex(h_remu, 8);
+		print_chr('\n');
+
+		uint32_t s_div, s_divu, s_rem, s_remu;
+		print_str("soft div   ");
+
+		s_div = b ? as / bs : 0xffffffff;
+		print_hex(s_div, 8);
+		print_str("  ");
+
+		s_divu = b ? au / bu : 0xffffffff;
+		print_hex(s_divu, 8);
+		print_str("  ");
+
+		s_rem = b ? as % bs : a;
+		print_hex(s_rem, 8);
+		print_str("  ");
+
+		s_remu = b ? au % bu : a;
+		print_hex(s_remu, 8);
+		print_str("  ");
+
+		if (s_div != h_div || s_divu != h_divu || s_rem != h_rem || s_remu != h_remu) {
+			print_str("ERROR!\n");
+			__asm__ volatile ("ebreak");
+			return;
+		}
+
+		print_str(" OK\n");
+	}
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/firmware/print.c b/verilog/rtl/softshell/third_party/picorv32/firmware/print.c
new file mode 100644
index 0000000..accce26
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/firmware/print.c
@@ -0,0 +1,41 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+
+#include "firmware.h"
+
+#define OUTPORT 0x10000000
+
+void print_chr(char ch)
+{
+	*((volatile uint32_t*)OUTPORT) = ch;
+}
+
+void print_str(const char *p)
+{
+	while (*p != 0)
+		*((volatile uint32_t*)OUTPORT) = *(p++);
+}
+
+void print_dec(unsigned int val)
+{
+	char buffer[10];
+	char *p = buffer;
+	while (val || p == buffer) {
+		*(p++) = val % 10;
+		val = val / 10;
+	}
+	while (p != buffer) {
+		*((volatile uint32_t*)OUTPORT) = '0' + *(--p);
+	}
+}
+
+void print_hex(unsigned int val, int digits)
+{
+	for (int i = (4*digits)-4; i >= 0; i -= 4)
+		*((volatile uint32_t*)OUTPORT) = "0123456789ABCDEF"[(val >> i) % 16];
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/firmware/riscv.ld b/verilog/rtl/softshell/third_party/picorv32/firmware/riscv.ld
new file mode 100644
index 0000000..16fde8d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/firmware/riscv.ld
@@ -0,0 +1,200 @@
+/* ---- Original Script: /opt/riscv32i/riscv32-unknown-elf/lib/ldscripts/elf32lriscv.x ---- */
+/* Default linker script, for normal executables */
+/* Copyright (C) 2014-2017 Free Software Foundation, Inc.
+   Copying and distribution of this script, with or without modification,
+   are permitted in any medium without royalty provided the copyright
+   notice and this notice are preserved.  */
+OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv",
+	      "elf32-littleriscv")
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+SECTIONS
+{
+  . = 0x00010000;
+  .text           :
+  {
+    *(.text)
+    *(.text.unlikely .text.*_unlikely .text.unlikely.*)
+    *(.text.exit .text.exit.*)
+    *(.text.startup .text.startup.*)
+    *(.text.hot .text.hot.*)
+    *(.stub .text.* .gnu.linkonce.t.*)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+  }
+  .init           :
+  {
+    KEEP (*(SORT_NONE(.init)))
+  }
+  .plt            : { *(.plt) }
+  .iplt           : { *(.iplt) }
+  .fini           :
+  {
+    KEEP (*(SORT_NONE(.fini)))
+  }
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .sdata2         :
+  {
+    *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+  }
+  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
+  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
+  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table
+  .gcc_except_table.*) }
+  .gnu_extab   : ONLY_IF_RO { *(.gnu_extab*) }
+  /* These sections are generated by the Sun/Oracle C++ compiler.  */
+  .exception_ranges   : ONLY_IF_RO { *(.exception_ranges
+  .exception_ranges*) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
+  /* Exception handling  */
+  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
+  .gnu_extab      : ONLY_IF_RW { *(.gnu_extab) }
+  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+  .exception_ranges   : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
+  /* Thread Local Storage sections  */
+  .tdata          : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss           : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .preinit_array  :
+  {
+    PROVIDE_HIDDEN (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE_HIDDEN (__preinit_array_end = .);
+  }
+  .init_array     :
+  {
+    PROVIDE_HIDDEN (__init_array_start = .);
+    KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
+    KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
+    PROVIDE_HIDDEN (__init_array_end = .);
+  }
+  .fini_array     :
+  {
+    PROVIDE_HIDDEN (__fini_array_start = .);
+    KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
+    KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
+    PROVIDE_HIDDEN (__fini_array_end = .);
+  }
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin.o(.ctors))
+    KEEP (*crtbegin?.o(.ctors))
+    /* We don't want to include the .ctor section from
+       the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*crtbegin?.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
+  .dynamic        : { *(.dynamic) }
+  . = DATA_SEGMENT_RELRO_END (0, .);
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  .got            : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata          :
+  {
+    __global_pointer$ = . + 0x800;
+    *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*)
+    *(.sdata .sdata.* .gnu.linkonce.s.*)
+  }
+  _edata = .; PROVIDE (edata = .);
+  . = .;
+  __bss_start = .;
+  .sbss           :
+  {
+    *(.dynsbss)
+    *(.sbss .sbss.* .gnu.linkonce.sb.*)
+    *(.scommon)
+  }
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.
+      FIXME: Why do we need it? When there is no .bss section, we don't
+      pad the .data section.  */
+   . = ALIGN(. != 0 ? 32 / 8 : 1);
+  }
+  . = ALIGN(32 / 8);
+  . = SEGMENT_START("ldata-segment", .);
+  . = ALIGN(32 / 8);
+  _end = .; PROVIDE (end = .);
+  . = DATA_SEGMENT_END (.);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end ) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* DWARF 3 */
+  .debug_pubtypes 0 : { *(.debug_pubtypes) }
+  .debug_ranges   0 : { *(.debug_ranges) }
+  /* DWARF Extension.  */
+  .debug_macro    0 : { *(.debug_macro) }
+  .debug_addr     0 : { *(.debug_addr) }
+  .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+  /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
+}
diff --git a/verilog/rtl/softshell/third_party/picorv32/firmware/riscv.ld.orig b/verilog/rtl/softshell/third_party/picorv32/firmware/riscv.ld.orig
new file mode 100644
index 0000000..6d40e3d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/firmware/riscv.ld.orig
@@ -0,0 +1,236 @@
+/* ---- Original Script: /opt/riscv32i/riscv32-unknown-elf/lib/ldscripts/elf32lriscv.x ---- */
+/* Default linker script, for normal executables */
+/* Copyright (C) 2014-2017 Free Software Foundation, Inc.
+   Copying and distribution of this script, with or without modification,
+   are permitted in any medium without royalty provided the copyright
+   notice and this notice are preserved.  */
+OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv",
+	      "elf32-littleriscv")
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+SEARCH_DIR("/opt/riscv32i/riscv32-unknown-elf/lib");
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x10000)); . = SEGMENT_START("text-segment", 0x10000) + SIZEOF_HEADERS;
+  .interp         : { *(.interp) }
+  .note.gnu.build-id : { *(.note.gnu.build-id) }
+  .hash           : { *(.hash) }
+  .gnu.hash       : { *(.gnu.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rela.init      : { *(.rela.init) }
+  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+  .rela.fini      : { *(.rela.fini) }
+  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+  .rela.data.rel.ro   : { *(.rela.data.rel.ro .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*) }
+  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+  .rela.tdata	  : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+  .rela.tbss	  : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+  .rela.ctors     : { *(.rela.ctors) }
+  .rela.dtors     : { *(.rela.dtors) }
+  .rela.got       : { *(.rela.got) }
+  .rela.sdata     : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
+  .rela.sbss      : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
+  .rela.sdata2    : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
+  .rela.sbss2     : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
+  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+  .rela.iplt      :
+    {
+      PROVIDE_HIDDEN (__rela_iplt_start = .);
+      *(.rela.iplt)
+      PROVIDE_HIDDEN (__rela_iplt_end = .);
+    }
+  .rela.plt       :
+    {
+      *(.rela.plt)
+    }
+  .init           :
+  {
+    KEEP (*(SORT_NONE(.init)))
+  }
+  .plt            : { *(.plt) }
+  .iplt           : { *(.iplt) }
+  .text           :
+  {
+    *(.text.unlikely .text.*_unlikely .text.unlikely.*)
+    *(.text.exit .text.exit.*)
+    *(.text.startup .text.startup.*)
+    *(.text.hot .text.hot.*)
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+  }
+  .fini           :
+  {
+    KEEP (*(SORT_NONE(.fini)))
+  }
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .sdata2         :
+  {
+    *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+  }
+  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
+  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
+  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table
+  .gcc_except_table.*) }
+  .gnu_extab   : ONLY_IF_RO { *(.gnu_extab*) }
+  /* These sections are generated by the Sun/Oracle C++ compiler.  */
+  .exception_ranges   : ONLY_IF_RO { *(.exception_ranges
+  .exception_ranges*) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
+  /* Exception handling  */
+  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
+  .gnu_extab      : ONLY_IF_RW { *(.gnu_extab) }
+  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+  .exception_ranges   : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
+  /* Thread Local Storage sections  */
+  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .preinit_array     :
+  {
+    PROVIDE_HIDDEN (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE_HIDDEN (__preinit_array_end = .);
+  }
+  .init_array     :
+  {
+    PROVIDE_HIDDEN (__init_array_start = .);
+    KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
+    KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
+    PROVIDE_HIDDEN (__init_array_end = .);
+  }
+  .fini_array     :
+  {
+    PROVIDE_HIDDEN (__fini_array_start = .);
+    KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
+    KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
+    PROVIDE_HIDDEN (__fini_array_end = .);
+  }
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin.o(.ctors))
+    KEEP (*crtbegin?.o(.ctors))
+    /* We don't want to include the .ctor section from
+       the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*crtbegin?.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
+  .dynamic        : { *(.dynamic) }
+  . = DATA_SEGMENT_RELRO_END (0, .);
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  .got            : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata          :
+  {
+    __global_pointer$ = . + 0x800;
+    *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*)
+    *(.sdata .sdata.* .gnu.linkonce.s.*)
+  }
+  _edata = .; PROVIDE (edata = .);
+  . = .;
+  __bss_start = .;
+  .sbss           :
+  {
+    *(.dynsbss)
+    *(.sbss .sbss.* .gnu.linkonce.sb.*)
+    *(.scommon)
+  }
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.
+      FIXME: Why do we need it? When there is no .bss section, we don't
+      pad the .data section.  */
+   . = ALIGN(. != 0 ? 32 / 8 : 1);
+  }
+  . = ALIGN(32 / 8);
+  . = SEGMENT_START("ldata-segment", .);
+  . = ALIGN(32 / 8);
+  _end = .; PROVIDE (end = .);
+  . = DATA_SEGMENT_END (.);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end ) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* DWARF 3 */
+  .debug_pubtypes 0 : { *(.debug_pubtypes) }
+  .debug_ranges   0 : { *(.debug_ranges) }
+  /* DWARF Extension.  */
+  .debug_macro    0 : { *(.debug_macro) }
+  .debug_addr     0 : { *(.debug_addr) }
+  .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+  /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
+}
diff --git a/verilog/rtl/softshell/third_party/picorv32/firmware/sections.lds b/verilog/rtl/softshell/third_party/picorv32/firmware/sections.lds
new file mode 100644
index 0000000..f914b46
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/firmware/sections.lds
@@ -0,0 +1,25 @@
+/*
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+*/
+
+MEMORY {
+	/* the memory in the testbench is 128k in size;
+	 * set LENGTH=96k and leave at least 32k for stack */
+	mem : ORIGIN = 0x00000000, LENGTH = 0x00018000
+}
+
+SECTIONS {
+	.memory : {
+		. = 0x000000;
+		start*(.text);
+		*(.text);
+		*(*);
+		end = .;
+		. = ALIGN(4);
+	} > mem
+}
diff --git a/verilog/rtl/softshell/third_party/picorv32/firmware/sieve.c b/verilog/rtl/softshell/third_party/picorv32/firmware/sieve.c
new file mode 100644
index 0000000..ff945eb
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/firmware/sieve.c
@@ -0,0 +1,84 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+
+// A simple Sieve of Eratosthenes
+
+#include "firmware.h"
+
+#define BITMAP_SIZE 64
+
+static uint32_t bitmap[BITMAP_SIZE/32];
+static uint32_t hash;
+
+static uint32_t mkhash(uint32_t a, uint32_t b)
+{
+	// The XOR version of DJB2
+	return ((a << 5) + a) ^ b;
+}
+
+static void bitmap_set(int idx)
+{
+	bitmap[idx/32] |= 1 << (idx % 32);
+}
+
+static bool bitmap_get(int idx)
+{
+	return (bitmap[idx/32] & (1 << (idx % 32))) != 0;
+}
+
+static void print_prime(int idx, int val)
+{
+	if (idx < 10)
+		print_str(" ");
+	print_dec(idx);
+	if (idx / 10 == 1)
+		goto force_th;
+	switch (idx % 10) {
+		case 1: print_str("st"); break;
+		case 2: print_str("nd"); break;
+		case 3: print_str("rd"); break;
+	force_th:
+		default: print_str("th"); break;
+	}
+	print_str(" prime is ");
+	print_dec(val);
+	print_str(".\n");
+
+	hash = mkhash(hash, idx);
+	hash = mkhash(hash, val);
+}
+
+void sieve(void)
+{
+	int idx = 1;
+	hash = 5381;
+	print_prime(idx++, 2);
+	for (int i = 0; i < BITMAP_SIZE; i++) {
+		if (bitmap_get(i))
+			continue;
+		print_prime(idx++, 3+2*i);
+		for (int j = 2*(3+2*i);; j += 3+2*i) {
+			if (j%2 == 0)
+				continue;
+			int k = (j-3)/2;
+			if (k >= BITMAP_SIZE)
+				break;
+			bitmap_set(k);
+		}
+	}
+
+	print_str("checksum: ");
+	print_hex(hash, 8);
+
+	if (hash == 0x1772A48F) {
+		print_str(" OK\n");
+	} else {
+		print_str(" ERROR\n");
+		__asm__ volatile ("ebreak");
+	}
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/firmware/start.S b/verilog/rtl/softshell/third_party/picorv32/firmware/start.S
new file mode 100644
index 0000000..d95f04c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/firmware/start.S
@@ -0,0 +1,537 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+
+#define ENABLE_QREGS
+#define ENABLE_HELLO
+#define ENABLE_RVTST
+#define ENABLE_SIEVE
+#define ENABLE_MULTST
+#define ENABLE_STATS
+
+#ifndef ENABLE_QREGS
+#  undef ENABLE_RVTST
+#endif
+
+// Only save registers in IRQ wrapper that are to be saved by the caller in
+// the RISC-V ABI, with the excpetion of the stack pointer. The IRQ handler
+// will save the rest if necessary. I.e. skip x3, x4, x8, x9, and x18-x27.
+#undef ENABLE_FASTIRQ
+
+#include "custom_ops.S"
+
+	.section .text
+	.global irq
+	.global hello
+	.global sieve
+	.global multest
+	.global hard_mul
+	.global hard_mulh
+	.global hard_mulhsu
+	.global hard_mulhu
+	.global hard_div
+	.global hard_divu
+	.global hard_rem
+	.global hard_remu
+	.global stats
+
+reset_vec:
+	// no more than 16 bytes here !
+	picorv32_waitirq_insn(zero)
+	picorv32_maskirq_insn(zero, zero)
+	j start
+
+
+/* Interrupt handler
+ **********************************/
+
+.balign 16
+irq_vec:
+	/* save registers */
+
+#ifdef ENABLE_QREGS
+
+	picorv32_setq_insn(q2, x1)
+	picorv32_setq_insn(q3, x2)
+
+	lui x1, %hi(irq_regs)
+	addi x1, x1, %lo(irq_regs)
+
+	picorv32_getq_insn(x2, q0)
+	sw x2,   0*4(x1)
+
+	picorv32_getq_insn(x2, q2)
+	sw x2,   1*4(x1)
+
+	picorv32_getq_insn(x2, q3)
+	sw x2,   2*4(x1)
+
+#ifdef ENABLE_FASTIRQ
+	sw x5,   5*4(x1)
+	sw x6,   6*4(x1)
+	sw x7,   7*4(x1)
+	sw x10, 10*4(x1)
+	sw x11, 11*4(x1)
+	sw x12, 12*4(x1)
+	sw x13, 13*4(x1)
+	sw x14, 14*4(x1)
+	sw x15, 15*4(x1)
+	sw x16, 16*4(x1)
+	sw x17, 17*4(x1)
+	sw x28, 28*4(x1)
+	sw x29, 29*4(x1)
+	sw x30, 30*4(x1)
+	sw x31, 31*4(x1)
+#else
+	sw x3,   3*4(x1)
+	sw x4,   4*4(x1)
+	sw x5,   5*4(x1)
+	sw x6,   6*4(x1)
+	sw x7,   7*4(x1)
+	sw x8,   8*4(x1)
+	sw x9,   9*4(x1)
+	sw x10, 10*4(x1)
+	sw x11, 11*4(x1)
+	sw x12, 12*4(x1)
+	sw x13, 13*4(x1)
+	sw x14, 14*4(x1)
+	sw x15, 15*4(x1)
+	sw x16, 16*4(x1)
+	sw x17, 17*4(x1)
+	sw x18, 18*4(x1)
+	sw x19, 19*4(x1)
+	sw x20, 20*4(x1)
+	sw x21, 21*4(x1)
+	sw x22, 22*4(x1)
+	sw x23, 23*4(x1)
+	sw x24, 24*4(x1)
+	sw x25, 25*4(x1)
+	sw x26, 26*4(x1)
+	sw x27, 27*4(x1)
+	sw x28, 28*4(x1)
+	sw x29, 29*4(x1)
+	sw x30, 30*4(x1)
+	sw x31, 31*4(x1)
+#endif
+
+#else // ENABLE_QREGS
+
+#ifdef ENABLE_FASTIRQ
+	sw gp,   0*4+0x200(zero)
+	sw x1,   1*4+0x200(zero)
+	sw x2,   2*4+0x200(zero)
+	sw x5,   5*4+0x200(zero)
+	sw x6,   6*4+0x200(zero)
+	sw x7,   7*4+0x200(zero)
+	sw x10, 10*4+0x200(zero)
+	sw x11, 11*4+0x200(zero)
+	sw x12, 12*4+0x200(zero)
+	sw x13, 13*4+0x200(zero)
+	sw x14, 14*4+0x200(zero)
+	sw x15, 15*4+0x200(zero)
+	sw x16, 16*4+0x200(zero)
+	sw x17, 17*4+0x200(zero)
+	sw x28, 28*4+0x200(zero)
+	sw x29, 29*4+0x200(zero)
+	sw x30, 30*4+0x200(zero)
+	sw x31, 31*4+0x200(zero)
+#else
+	sw gp,   0*4+0x200(zero)
+	sw x1,   1*4+0x200(zero)
+	sw x2,   2*4+0x200(zero)
+	sw x3,   3*4+0x200(zero)
+	sw x4,   4*4+0x200(zero)
+	sw x5,   5*4+0x200(zero)
+	sw x6,   6*4+0x200(zero)
+	sw x7,   7*4+0x200(zero)
+	sw x8,   8*4+0x200(zero)
+	sw x9,   9*4+0x200(zero)
+	sw x10, 10*4+0x200(zero)
+	sw x11, 11*4+0x200(zero)
+	sw x12, 12*4+0x200(zero)
+	sw x13, 13*4+0x200(zero)
+	sw x14, 14*4+0x200(zero)
+	sw x15, 15*4+0x200(zero)
+	sw x16, 16*4+0x200(zero)
+	sw x17, 17*4+0x200(zero)
+	sw x18, 18*4+0x200(zero)
+	sw x19, 19*4+0x200(zero)
+	sw x20, 20*4+0x200(zero)
+	sw x21, 21*4+0x200(zero)
+	sw x22, 22*4+0x200(zero)
+	sw x23, 23*4+0x200(zero)
+	sw x24, 24*4+0x200(zero)
+	sw x25, 25*4+0x200(zero)
+	sw x26, 26*4+0x200(zero)
+	sw x27, 27*4+0x200(zero)
+	sw x28, 28*4+0x200(zero)
+	sw x29, 29*4+0x200(zero)
+	sw x30, 30*4+0x200(zero)
+	sw x31, 31*4+0x200(zero)
+#endif
+
+#endif // ENABLE_QREGS
+
+	/* call interrupt handler C function */
+
+	lui sp, %hi(irq_stack)
+	addi sp, sp, %lo(irq_stack)
+
+	// arg0 = address of regs
+	lui a0, %hi(irq_regs)
+	addi a0, a0, %lo(irq_regs)
+
+	// arg1 = interrupt type
+#ifdef ENABLE_QREGS
+	picorv32_getq_insn(a1, q1)
+#else
+	addi a1, tp, 0
+#endif
+
+	// call to C function
+	jal ra, irq
+
+	/* restore registers */
+
+#ifdef ENABLE_QREGS
+
+	// new irq_regs address returned from C code in a0
+	addi x1, a0, 0
+
+	lw x2,   0*4(x1)
+	picorv32_setq_insn(q0, x2)
+
+	lw x2,   1*4(x1)
+	picorv32_setq_insn(q1, x2)
+
+	lw x2,   2*4(x1)
+	picorv32_setq_insn(q2, x2)
+
+#ifdef ENABLE_FASTIRQ
+	lw x5,   5*4(x1)
+	lw x6,   6*4(x1)
+	lw x7,   7*4(x1)
+	lw x10, 10*4(x1)
+	lw x11, 11*4(x1)
+	lw x12, 12*4(x1)
+	lw x13, 13*4(x1)
+	lw x14, 14*4(x1)
+	lw x15, 15*4(x1)
+	lw x16, 16*4(x1)
+	lw x17, 17*4(x1)
+	lw x28, 28*4(x1)
+	lw x29, 29*4(x1)
+	lw x30, 30*4(x1)
+	lw x31, 31*4(x1)
+#else
+	lw x3,   3*4(x1)
+	lw x4,   4*4(x1)
+	lw x5,   5*4(x1)
+	lw x6,   6*4(x1)
+	lw x7,   7*4(x1)
+	lw x8,   8*4(x1)
+	lw x9,   9*4(x1)
+	lw x10, 10*4(x1)
+	lw x11, 11*4(x1)
+	lw x12, 12*4(x1)
+	lw x13, 13*4(x1)
+	lw x14, 14*4(x1)
+	lw x15, 15*4(x1)
+	lw x16, 16*4(x1)
+	lw x17, 17*4(x1)
+	lw x18, 18*4(x1)
+	lw x19, 19*4(x1)
+	lw x20, 20*4(x1)
+	lw x21, 21*4(x1)
+	lw x22, 22*4(x1)
+	lw x23, 23*4(x1)
+	lw x24, 24*4(x1)
+	lw x25, 25*4(x1)
+	lw x26, 26*4(x1)
+	lw x27, 27*4(x1)
+	lw x28, 28*4(x1)
+	lw x29, 29*4(x1)
+	lw x30, 30*4(x1)
+	lw x31, 31*4(x1)
+#endif
+
+	picorv32_getq_insn(x1, q1)
+	picorv32_getq_insn(x2, q2)
+
+#else // ENABLE_QREGS
+
+	// new irq_regs address returned from C code in a0
+	addi a1, zero, 0x200
+	beq a0, a1, 1f
+	ebreak
+1:
+
+#ifdef ENABLE_FASTIRQ
+	lw gp,   0*4+0x200(zero)
+	lw x1,   1*4+0x200(zero)
+	lw x2,   2*4+0x200(zero)
+	lw x5,   5*4+0x200(zero)
+	lw x6,   6*4+0x200(zero)
+	lw x7,   7*4+0x200(zero)
+	lw x10, 10*4+0x200(zero)
+	lw x11, 11*4+0x200(zero)
+	lw x12, 12*4+0x200(zero)
+	lw x13, 13*4+0x200(zero)
+	lw x14, 14*4+0x200(zero)
+	lw x15, 15*4+0x200(zero)
+	lw x16, 16*4+0x200(zero)
+	lw x17, 17*4+0x200(zero)
+	lw x28, 28*4+0x200(zero)
+	lw x29, 29*4+0x200(zero)
+	lw x30, 30*4+0x200(zero)
+	lw x31, 31*4+0x200(zero)
+#else
+	lw gp,   0*4+0x200(zero)
+	lw x1,   1*4+0x200(zero)
+	lw x2,   2*4+0x200(zero)
+	// do not restore x3 (gp)
+	lw x4,   4*4+0x200(zero)
+	lw x5,   5*4+0x200(zero)
+	lw x6,   6*4+0x200(zero)
+	lw x7,   7*4+0x200(zero)
+	lw x8,   8*4+0x200(zero)
+	lw x9,   9*4+0x200(zero)
+	lw x10, 10*4+0x200(zero)
+	lw x11, 11*4+0x200(zero)
+	lw x12, 12*4+0x200(zero)
+	lw x13, 13*4+0x200(zero)
+	lw x14, 14*4+0x200(zero)
+	lw x15, 15*4+0x200(zero)
+	lw x16, 16*4+0x200(zero)
+	lw x17, 17*4+0x200(zero)
+	lw x18, 18*4+0x200(zero)
+	lw x19, 19*4+0x200(zero)
+	lw x20, 20*4+0x200(zero)
+	lw x21, 21*4+0x200(zero)
+	lw x22, 22*4+0x200(zero)
+	lw x23, 23*4+0x200(zero)
+	lw x24, 24*4+0x200(zero)
+	lw x25, 25*4+0x200(zero)
+	lw x26, 26*4+0x200(zero)
+	lw x27, 27*4+0x200(zero)
+	lw x28, 28*4+0x200(zero)
+	lw x29, 29*4+0x200(zero)
+	lw x30, 30*4+0x200(zero)
+	lw x31, 31*4+0x200(zero)
+#endif
+
+#endif // ENABLE_QREGS
+
+	picorv32_retirq_insn()
+
+#ifndef ENABLE_QREGS
+.balign 0x200
+#endif
+irq_regs:
+	// registers are saved to this memory region during interrupt handling
+	// the program counter is saved as register 0
+	.fill 32,4
+
+	// stack for the interrupt handler
+	.fill 128,4
+irq_stack:
+
+
+/* Main program
+ **********************************/
+
+start:
+	/* zero-initialize all registers */
+
+	addi x1, zero, 0
+	addi x2, zero, 0
+	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
+
+#ifdef ENABLE_HELLO
+	/* set stack pointer */
+	lui sp,(128*1024)>>12
+
+	/* call hello C code */
+	jal ra,hello
+#endif
+
+	/* running tests from riscv-tests */
+
+#ifdef ENABLE_RVTST
+#  define TEST(n) \
+	.global n; \
+	addi x1, zero, 1000; \
+	picorv32_timer_insn(zero, x1); \
+	jal zero,n; \
+	.global n ## _ret; \
+	n ## _ret:
+#else
+#  define TEST(n) \
+	.global n ## _ret; \
+	n ## _ret:
+#endif
+
+	TEST(lui)
+	TEST(auipc)
+	TEST(j)
+	TEST(jal)
+	TEST(jalr)
+
+	TEST(beq)
+	TEST(bne)
+	TEST(blt)
+	TEST(bge)
+	TEST(bltu)
+	TEST(bgeu)
+
+	TEST(lb)
+	TEST(lh)
+	TEST(lw)
+	TEST(lbu)
+	TEST(lhu)
+
+	TEST(sb)
+	TEST(sh)
+	TEST(sw)
+
+	TEST(addi)
+	TEST(slti) // also tests sltiu
+	TEST(xori)
+	TEST(ori)
+	TEST(andi)
+	TEST(slli)
+	TEST(srli)
+	TEST(srai)
+
+	TEST(add)
+	TEST(sub)
+	TEST(sll)
+	TEST(slt) // what is with sltu ?
+	TEST(xor)
+	TEST(srl)
+	TEST(sra)
+	TEST(or)
+	TEST(and)
+
+	TEST(mulh)
+	TEST(mulhsu)
+	TEST(mulhu)
+	TEST(mul)
+
+	TEST(div)
+	TEST(divu)
+	TEST(rem)
+	TEST(remu)
+
+	TEST(simple)
+
+	/* set stack pointer */
+	lui sp,(128*1024)>>12
+
+	/* set gp and tp */
+	lui gp, %hi(0xdeadbeef)
+	addi gp, gp, %lo(0xdeadbeef)
+	addi tp, gp, 0
+
+#ifdef ENABLE_SIEVE
+	/* call sieve C code */
+	jal ra,sieve
+#endif
+
+#ifdef ENABLE_MULTST
+	/* call multest C code */
+	jal ra,multest
+#endif
+
+#ifdef ENABLE_STATS
+	/* call stats C code */
+	jal ra,stats
+#endif
+
+	/* print "DONE\n" */
+	lui a0,0x10000000>>12
+	addi a1,zero,'D'
+	addi a2,zero,'O'
+	addi a3,zero,'N'
+	addi a4,zero,'E'
+	addi a5,zero,'\n'
+	sw a1,0(a0)
+	sw a2,0(a0)
+	sw a3,0(a0)
+	sw a4,0(a0)
+	sw a5,0(a0)
+
+	li a0, 0x20000000
+	li a1, 123456789
+	sw a1,0(a0)
+
+	/* trap */
+	ebreak
+
+
+/* Hard mul functions for multest.c
+ **********************************/
+
+hard_mul:
+	mul a0, a0, a1
+	ret
+
+hard_mulh:
+	mulh a0, a0, a1
+	ret
+
+hard_mulhsu:
+	mulhsu a0, a0, a1
+	ret
+
+hard_mulhu:
+	mulhu a0, a0, a1
+	ret
+
+hard_div:
+	div a0, a0, a1
+	ret
+
+hard_divu:
+	divu a0, a0, a1
+	ret
+
+hard_rem:
+	rem a0, a0, a1
+	ret
+
+hard_remu:
+	remu a0, a0, a1
+	ret
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/firmware/stats.c b/verilog/rtl/softshell/third_party/picorv32/firmware/stats.c
new file mode 100644
index 0000000..80e22dd
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/firmware/stats.c
@@ -0,0 +1,42 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+
+#include "firmware.h"
+
+static void stats_print_dec(unsigned int val, int digits, bool zero_pad)
+{
+	char buffer[32];
+	char *p = buffer;
+	while (val || digits > 0) {
+		if (val)
+			*(p++) = '0' + val % 10;
+		else
+			*(p++) = zero_pad ? '0' : ' ';
+		val = val / 10;
+		digits--;
+	}
+	while (p != buffer) {
+		if (p[-1] == ' ' && p[-2] == ' ') p[-1] = '.';
+		print_chr(*(--p));
+	}
+}
+
+void stats(void)
+{
+	unsigned int num_cycles, num_instr;
+	__asm__ volatile ("rdcycle %0; rdinstret %1;" : "=r"(num_cycles), "=r"(num_instr));
+	print_str("Cycle counter ........");
+	stats_print_dec(num_cycles, 8, false);
+	print_str("\nInstruction counter ..");
+	stats_print_dec(num_instr, 8, false);
+	print_str("\nCPI: ");
+	stats_print_dec((num_cycles / num_instr), 0, false);
+	print_str(".");
+	stats_print_dec(((100 * num_cycles) / num_instr) % 100, 2, true);
+	print_str("\n");
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/picorv32.core b/verilog/rtl/softshell/third_party/picorv32/picorv32.core
new file mode 100644
index 0000000..08ee704
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/picorv32.core
@@ -0,0 +1,78 @@
+CAPI=2:
+name : ::picorv32:0-r1
+
+filesets:
+  rtl:
+    files: [picorv32.v]
+    file_type : verilogSource
+  tb:
+    files: [testbench.v]
+    file_type : verilogSource
+    depend:
+  tb_ez:
+    files: [testbench_ez.v]
+    file_type : verilogSource
+  tb_wb:
+    files: [testbench_wb.v]
+    file_type : verilogSource
+  tb_verilator:
+    files:
+      - testbench.cc : {file_type : cppSource}
+
+targets:
+  default:
+    filesets: [rtl]
+  lint:
+    filesets: [rtl]
+    default_tool : verilator
+    tools:
+      verilator:
+        mode : lint-only
+    toplevel : [picorv32_axi]
+  test:
+    default_tool: icarus
+    filesets: [rtl, tb, "tool_verilator? (tb_verilator)"]
+    parameters: [COMPRESSED_ISA, axi_test, firmware, noerror, trace, vcd, verbose]
+    toplevel:
+      - "tool_verilator?  (picorv32_wrapper)"
+      - "!tool_verilator? (testbench)"
+      
+    tools:
+      verilator :
+        cli_parser : fusesoc
+        mode : cc
+        verilator_options : [-Wno-fatal, --trace]
+  test_ez:
+    default_tool: icarus
+    filesets: [rtl, tb_ez]
+    parameters: [vcd]
+    toplevel: [testbench]
+  test_wb:
+    default_tool: icarus
+    filesets: [rtl, tb_wb]
+    parameters: [COMPRESSED_ISA, firmware, noerror, trace, vcd]
+    toplevel: [testbench]
+
+parameters:
+  COMPRESSED_ISA:
+    datatype  : str
+    default   : 1
+    paramtype : vlogdefine
+  axi_test:
+    datatype  :  bool
+    paramtype : plusarg
+  firmware:
+    datatype  :  file
+    paramtype : plusarg
+  noerror:
+    datatype  :  bool
+    paramtype : plusarg
+  trace:
+    datatype  : bool
+    paramtype : plusarg
+  vcd:
+    datatype  : bool
+    paramtype : plusarg
+  verbose:
+    datatype : bool
+    paramtype : plusarg
diff --git a/verilog/rtl/softshell/third_party/picorv32/picorv32.v b/verilog/rtl/softshell/third_party/picorv32/picorv32.v
new file mode 100644
index 0000000..6364cbe
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/picorv32.v
@@ -0,0 +1,3044 @@
+/*
+ *  PicoRV32 -- A Small RISC-V (RV32I) Processor Core
+ *
+ *  Copyright (C) 2015  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/* verilator lint_off WIDTH */
+/* verilator lint_off PINMISSING */
+/* verilator lint_off CASEOVERLAP */
+/* verilator lint_off CASEINCOMPLETE */
+
+`timescale 1 ns / 1 ps
+// `default_nettype none
+// `define DEBUGNETS
+// `define DEBUGREGS
+// `define DEBUGASM
+// `define DEBUG
+
+`ifdef DEBUG
+  `define debug(debug_command) debug_command
+`else
+  `define debug(debug_command)
+`endif
+
+`ifdef FORMAL
+  `define FORMAL_KEEP (* keep *)
+  `define assert(assert_expr) assert(assert_expr)
+`else
+  `ifdef DEBUGNETS
+    `define FORMAL_KEEP (* keep *)
+  `else
+    `define FORMAL_KEEP
+  `endif
+  `define assert(assert_expr) empty_statement
+`endif
+
+// uncomment this for register file in extra module
+// `define PICORV32_REGS picorv32_regs
+
+// this macro can be used to check if the verilog files in your
+// design are read in the correct order.
+`define PICORV32_V
+
+
+/***************************************************************
+ * picorv32
+ ***************************************************************/
+
+module picorv32 #(
+	parameter [ 0:0] ENABLE_COUNTERS = 1,
+	parameter [ 0:0] ENABLE_COUNTERS64 = 1,
+	parameter [ 0:0] ENABLE_REGS_16_31 = 1,
+	parameter [ 0:0] ENABLE_REGS_DUALPORT = 1,
+	parameter [ 0:0] LATCHED_MEM_RDATA = 0,
+	parameter [ 0:0] TWO_STAGE_SHIFT = 1,
+	parameter [ 0:0] BARREL_SHIFTER = 0,
+	parameter [ 0:0] TWO_CYCLE_COMPARE = 0,
+	parameter [ 0:0] TWO_CYCLE_ALU = 0,
+	parameter [ 0:0] COMPRESSED_ISA = 0,
+	parameter [ 0:0] CATCH_MISALIGN = 1,
+	parameter [ 0:0] CATCH_ILLINSN = 1,
+	parameter [ 0:0] ENABLE_PCPI = 0,
+	parameter [ 0:0] ENABLE_MUL = 0,
+	parameter [ 0:0] ENABLE_FAST_MUL = 0,
+	parameter [ 0:0] ENABLE_DIV = 0,
+	parameter [ 0:0] ENABLE_IRQ = 0,
+	parameter [ 0:0] ENABLE_IRQ_QREGS = 1,
+	parameter [ 0:0] ENABLE_IRQ_TIMER = 1,
+	parameter [ 0:0] ENABLE_TRACE = 0,
+	parameter [ 0:0] REGS_INIT_ZERO = 0,
+	parameter [31:0] MASKED_IRQ = 32'h 0000_0000,
+	parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff,
+	parameter [31:0] PROGADDR_RESET = 32'h 0000_0000,
+	parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010,
+	parameter [31:0] STACKADDR = 32'h ffff_ffff
+) (
+	input clk, resetn,
+	output reg trap,
+
+	output reg        mem_valid,
+	output reg        mem_instr,
+	input             mem_ready,
+
+	output reg [31:0] mem_addr,
+	output reg [31:0] mem_wdata,
+	output reg [ 3:0] mem_wstrb,
+	input      [31:0] mem_rdata,
+
+	// Look-Ahead Interface
+	output            mem_la_read,
+	output            mem_la_write,
+	output     [31:0] mem_la_addr,
+	output reg [31:0] mem_la_wdata,
+	output reg [ 3:0] mem_la_wstrb,
+
+	// Pico Co-Processor Interface (PCPI)
+	output reg        pcpi_valid,
+	output reg [31:0] pcpi_insn,
+	output     [31:0] pcpi_rs1,
+	output     [31:0] pcpi_rs2,
+	input             pcpi_wr,
+	input      [31:0] pcpi_rd,
+	input             pcpi_wait,
+	input             pcpi_ready,
+
+	// IRQ Interface
+	input      [31:0] irq,
+	output reg [31:0] eoi,
+
+`ifdef RISCV_FORMAL
+	output reg        rvfi_valid,
+	output reg [63:0] rvfi_order,
+	output reg [31:0] rvfi_insn,
+	output reg        rvfi_trap,
+	output reg        rvfi_halt,
+	output reg        rvfi_intr,
+	output reg [ 1:0] rvfi_mode,
+	output reg [ 1:0] rvfi_ixl,
+	output reg [ 4:0] rvfi_rs1_addr,
+	output reg [ 4:0] rvfi_rs2_addr,
+	output reg [31:0] rvfi_rs1_rdata,
+	output reg [31:0] rvfi_rs2_rdata,
+	output reg [ 4:0] rvfi_rd_addr,
+	output reg [31:0] rvfi_rd_wdata,
+	output reg [31:0] rvfi_pc_rdata,
+	output reg [31:0] rvfi_pc_wdata,
+	output reg [31:0] rvfi_mem_addr,
+	output reg [ 3:0] rvfi_mem_rmask,
+	output reg [ 3:0] rvfi_mem_wmask,
+	output reg [31:0] rvfi_mem_rdata,
+	output reg [31:0] rvfi_mem_wdata,
+
+	output reg [63:0] rvfi_csr_mcycle_rmask,
+	output reg [63:0] rvfi_csr_mcycle_wmask,
+	output reg [63:0] rvfi_csr_mcycle_rdata,
+	output reg [63:0] rvfi_csr_mcycle_wdata,
+
+	output reg [63:0] rvfi_csr_minstret_rmask,
+	output reg [63:0] rvfi_csr_minstret_wmask,
+	output reg [63:0] rvfi_csr_minstret_rdata,
+	output reg [63:0] rvfi_csr_minstret_wdata,
+`endif
+
+	// Trace Interface
+	output reg        trace_valid,
+	output reg [35:0] trace_data
+);
+	localparam integer irq_timer = 0;
+	localparam integer irq_ebreak = 1;
+	localparam integer irq_buserror = 2;
+
+	localparam integer irqregs_offset = ENABLE_REGS_16_31 ? 32 : 16;
+	localparam integer regfile_size = (ENABLE_REGS_16_31 ? 32 : 16) + 4*ENABLE_IRQ*ENABLE_IRQ_QREGS;
+	localparam integer regindex_bits = (ENABLE_REGS_16_31 ? 5 : 4) + ENABLE_IRQ*ENABLE_IRQ_QREGS;
+
+	localparam WITH_PCPI = ENABLE_PCPI || ENABLE_MUL || ENABLE_FAST_MUL || ENABLE_DIV;
+
+	localparam [35:0] TRACE_BRANCH = {4'b 0001, 32'b 0};
+	localparam [35:0] TRACE_ADDR   = {4'b 0010, 32'b 0};
+	localparam [35:0] TRACE_IRQ    = {4'b 1000, 32'b 0};
+
+	reg [63:0] count_cycle, count_instr;
+	reg [31:0] reg_pc, reg_next_pc, reg_op1, reg_op2, reg_out;
+	reg [4:0] reg_sh;
+
+	reg [31:0] next_insn_opcode;
+	reg [31:0] dbg_insn_opcode;
+	reg [31:0] dbg_insn_addr;
+
+	wire dbg_mem_valid = mem_valid;
+	wire dbg_mem_instr = mem_instr;
+	wire dbg_mem_ready = mem_ready;
+	wire [31:0] dbg_mem_addr  = mem_addr;
+	wire [31:0] dbg_mem_wdata = mem_wdata;
+	wire [ 3:0] dbg_mem_wstrb = mem_wstrb;
+	wire [31:0] dbg_mem_rdata = mem_rdata;
+
+	assign pcpi_rs1 = reg_op1;
+	assign pcpi_rs2 = reg_op2;
+
+	wire [31:0] next_pc;
+
+	reg irq_delay;
+	reg irq_active;
+	reg [31:0] irq_mask;
+	reg [31:0] irq_pending;
+	reg [31:0] timer;
+
+`ifndef PICORV32_REGS
+	reg [31:0] cpuregs [0:regfile_size-1];
+
+	integer i;
+	initial begin
+		if (REGS_INIT_ZERO) begin
+			for (i = 0; i < regfile_size; i = i+1)
+				cpuregs[i] = 0;
+		end
+	end
+`endif
+
+	task empty_statement;
+		// This task is used by the `assert directive in non-formal mode to
+		// avoid empty statement (which are unsupported by plain Verilog syntax).
+		begin end
+	endtask
+
+`ifdef DEBUGREGS
+	wire [31:0] dbg_reg_x0  = 0;
+	wire [31:0] dbg_reg_x1  = cpuregs[1];
+	wire [31:0] dbg_reg_x2  = cpuregs[2];
+	wire [31:0] dbg_reg_x3  = cpuregs[3];
+	wire [31:0] dbg_reg_x4  = cpuregs[4];
+	wire [31:0] dbg_reg_x5  = cpuregs[5];
+	wire [31:0] dbg_reg_x6  = cpuregs[6];
+	wire [31:0] dbg_reg_x7  = cpuregs[7];
+	wire [31:0] dbg_reg_x8  = cpuregs[8];
+	wire [31:0] dbg_reg_x9  = cpuregs[9];
+	wire [31:0] dbg_reg_x10 = cpuregs[10];
+	wire [31:0] dbg_reg_x11 = cpuregs[11];
+	wire [31:0] dbg_reg_x12 = cpuregs[12];
+	wire [31:0] dbg_reg_x13 = cpuregs[13];
+	wire [31:0] dbg_reg_x14 = cpuregs[14];
+	wire [31:0] dbg_reg_x15 = cpuregs[15];
+	wire [31:0] dbg_reg_x16 = cpuregs[16];
+	wire [31:0] dbg_reg_x17 = cpuregs[17];
+	wire [31:0] dbg_reg_x18 = cpuregs[18];
+	wire [31:0] dbg_reg_x19 = cpuregs[19];
+	wire [31:0] dbg_reg_x20 = cpuregs[20];
+	wire [31:0] dbg_reg_x21 = cpuregs[21];
+	wire [31:0] dbg_reg_x22 = cpuregs[22];
+	wire [31:0] dbg_reg_x23 = cpuregs[23];
+	wire [31:0] dbg_reg_x24 = cpuregs[24];
+	wire [31:0] dbg_reg_x25 = cpuregs[25];
+	wire [31:0] dbg_reg_x26 = cpuregs[26];
+	wire [31:0] dbg_reg_x27 = cpuregs[27];
+	wire [31:0] dbg_reg_x28 = cpuregs[28];
+	wire [31:0] dbg_reg_x29 = cpuregs[29];
+	wire [31:0] dbg_reg_x30 = cpuregs[30];
+	wire [31:0] dbg_reg_x31 = cpuregs[31];
+`endif
+
+	// Internal PCPI Cores
+
+	wire        pcpi_mul_wr;
+	wire [31:0] pcpi_mul_rd;
+	wire        pcpi_mul_wait;
+	wire        pcpi_mul_ready;
+
+	wire        pcpi_div_wr;
+	wire [31:0] pcpi_div_rd;
+	wire        pcpi_div_wait;
+	wire        pcpi_div_ready;
+
+	reg        pcpi_int_wr;
+	reg [31:0] pcpi_int_rd;
+	reg        pcpi_int_wait;
+	reg        pcpi_int_ready;
+
+	generate if (ENABLE_FAST_MUL) begin
+		picorv32_pcpi_fast_mul pcpi_mul (
+			.clk       (clk            ),
+			.resetn    (resetn         ),
+			.pcpi_valid(pcpi_valid     ),
+			.pcpi_insn (pcpi_insn      ),
+			.pcpi_rs1  (pcpi_rs1       ),
+			.pcpi_rs2  (pcpi_rs2       ),
+			.pcpi_wr   (pcpi_mul_wr    ),
+			.pcpi_rd   (pcpi_mul_rd    ),
+			.pcpi_wait (pcpi_mul_wait  ),
+			.pcpi_ready(pcpi_mul_ready )
+		);
+	end else if (ENABLE_MUL) begin
+		picorv32_pcpi_mul pcpi_mul (
+			.clk       (clk            ),
+			.resetn    (resetn         ),
+			.pcpi_valid(pcpi_valid     ),
+			.pcpi_insn (pcpi_insn      ),
+			.pcpi_rs1  (pcpi_rs1       ),
+			.pcpi_rs2  (pcpi_rs2       ),
+			.pcpi_wr   (pcpi_mul_wr    ),
+			.pcpi_rd   (pcpi_mul_rd    ),
+			.pcpi_wait (pcpi_mul_wait  ),
+			.pcpi_ready(pcpi_mul_ready )
+		);
+	end else begin
+		assign pcpi_mul_wr = 0;
+		assign pcpi_mul_rd = 32'bx;
+		assign pcpi_mul_wait = 0;
+		assign pcpi_mul_ready = 0;
+	end endgenerate
+
+	generate if (ENABLE_DIV) begin
+		picorv32_pcpi_div pcpi_div (
+			.clk       (clk            ),
+			.resetn    (resetn         ),
+			.pcpi_valid(pcpi_valid     ),
+			.pcpi_insn (pcpi_insn      ),
+			.pcpi_rs1  (pcpi_rs1       ),
+			.pcpi_rs2  (pcpi_rs2       ),
+			.pcpi_wr   (pcpi_div_wr    ),
+			.pcpi_rd   (pcpi_div_rd    ),
+			.pcpi_wait (pcpi_div_wait  ),
+			.pcpi_ready(pcpi_div_ready )
+		);
+	end else begin
+		assign pcpi_div_wr = 0;
+		assign pcpi_div_rd = 32'bx;
+		assign pcpi_div_wait = 0;
+		assign pcpi_div_ready = 0;
+	end endgenerate
+
+	always @* begin
+		pcpi_int_wr = 0;
+		pcpi_int_rd = 32'bx;
+		pcpi_int_wait  = |{ENABLE_PCPI && pcpi_wait,  (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_wait,  ENABLE_DIV && pcpi_div_wait};
+		pcpi_int_ready = |{ENABLE_PCPI && pcpi_ready, (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_ready, ENABLE_DIV && pcpi_div_ready};
+
+		(* parallel_case *)
+		case (1'b1)
+			ENABLE_PCPI && pcpi_ready: begin
+				pcpi_int_wr = ENABLE_PCPI ? pcpi_wr : 0;
+				pcpi_int_rd = ENABLE_PCPI ? pcpi_rd : 0;
+			end
+			(ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_ready: begin
+				pcpi_int_wr = pcpi_mul_wr;
+				pcpi_int_rd = pcpi_mul_rd;
+			end
+			ENABLE_DIV && pcpi_div_ready: begin
+				pcpi_int_wr = pcpi_div_wr;
+				pcpi_int_rd = pcpi_div_rd;
+			end
+		endcase
+	end
+
+
+	// Memory Interface
+
+	reg [1:0] mem_state;
+	reg [1:0] mem_wordsize;
+	reg [31:0] mem_rdata_word;
+	reg [31:0] mem_rdata_q;
+	reg mem_do_prefetch;
+	reg mem_do_rinst;
+	reg mem_do_rdata;
+	reg mem_do_wdata;
+
+	wire mem_xfer;
+	reg mem_la_secondword, mem_la_firstword_reg, last_mem_valid;
+	wire mem_la_firstword = COMPRESSED_ISA && (mem_do_prefetch || mem_do_rinst) && next_pc[1] && !mem_la_secondword;
+	wire mem_la_firstword_xfer = COMPRESSED_ISA && mem_xfer && (!last_mem_valid ? mem_la_firstword : mem_la_firstword_reg);
+
+	reg prefetched_high_word;
+	reg clear_prefetched_high_word;
+	reg [15:0] mem_16bit_buffer;
+
+	wire [31:0] mem_rdata_latched_noshuffle;
+	wire [31:0] mem_rdata_latched;
+
+	wire mem_la_use_prefetched_high_word = COMPRESSED_ISA && mem_la_firstword && prefetched_high_word && !clear_prefetched_high_word;
+	assign mem_xfer = (mem_valid && mem_ready) || (mem_la_use_prefetched_high_word && mem_do_rinst);
+
+	wire mem_busy = |{mem_do_prefetch, mem_do_rinst, mem_do_rdata, mem_do_wdata};
+	wire mem_done = resetn && ((mem_xfer && |mem_state && (mem_do_rinst || mem_do_rdata || mem_do_wdata)) || (&mem_state && mem_do_rinst)) &&
+			(!mem_la_firstword || (~&mem_rdata_latched[1:0] && mem_xfer));
+
+	assign mem_la_write = resetn && !mem_state && mem_do_wdata;
+	assign mem_la_read = resetn && ((!mem_la_use_prefetched_high_word && !mem_state && (mem_do_rinst || mem_do_prefetch || mem_do_rdata)) ||
+			(COMPRESSED_ISA && mem_xfer && (!last_mem_valid ? mem_la_firstword : mem_la_firstword_reg) && !mem_la_secondword && &mem_rdata_latched[1:0]));
+	assign mem_la_addr = (mem_do_prefetch || mem_do_rinst) ? {next_pc[31:2] + mem_la_firstword_xfer, 2'b00} : {reg_op1[31:2], 2'b00};
+
+	assign mem_rdata_latched_noshuffle = (mem_xfer || LATCHED_MEM_RDATA) ? mem_rdata : mem_rdata_q;
+
+	assign mem_rdata_latched = COMPRESSED_ISA && mem_la_use_prefetched_high_word ? {16'bx, mem_16bit_buffer} :
+			COMPRESSED_ISA && mem_la_secondword ? {mem_rdata_latched_noshuffle[15:0], mem_16bit_buffer} :
+			COMPRESSED_ISA && mem_la_firstword ? {16'bx, mem_rdata_latched_noshuffle[31:16]} : mem_rdata_latched_noshuffle;
+
+	always @(posedge clk) begin
+		if (!resetn) begin
+			mem_la_firstword_reg <= 0;
+			last_mem_valid <= 0;
+		end else begin
+			if (!last_mem_valid)
+				mem_la_firstword_reg <= mem_la_firstword;
+			last_mem_valid <= mem_valid && !mem_ready;
+		end
+	end
+
+	always @* begin
+		(* full_case *)
+		case (mem_wordsize)
+			0: begin
+				mem_la_wdata = reg_op2;
+				mem_la_wstrb = 4'b1111;
+				mem_rdata_word = mem_rdata;
+			end
+			1: begin
+				mem_la_wdata = {2{reg_op2[15:0]}};
+				mem_la_wstrb = reg_op1[1] ? 4'b1100 : 4'b0011;
+				case (reg_op1[1])
+					1'b0: mem_rdata_word = {16'b0, mem_rdata[15: 0]};
+					1'b1: mem_rdata_word = {16'b0, mem_rdata[31:16]};
+				endcase
+			end
+			2: begin
+				mem_la_wdata = {4{reg_op2[7:0]}};
+				mem_la_wstrb = 4'b0001 << reg_op1[1:0];
+				case (reg_op1[1:0])
+					2'b00: mem_rdata_word = {24'b0, mem_rdata[ 7: 0]};
+					2'b01: mem_rdata_word = {24'b0, mem_rdata[15: 8]};
+					2'b10: mem_rdata_word = {24'b0, mem_rdata[23:16]};
+					2'b11: mem_rdata_word = {24'b0, mem_rdata[31:24]};
+				endcase
+			end
+		endcase
+	end
+
+	always @(posedge clk) begin
+		if (mem_xfer) begin
+			mem_rdata_q <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata;
+			next_insn_opcode <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata;
+		end
+
+		if (COMPRESSED_ISA && mem_done && (mem_do_prefetch || mem_do_rinst)) begin
+			case (mem_rdata_latched[1:0])
+				2'b00: begin // Quadrant 0
+					case (mem_rdata_latched[15:13])
+						3'b000: begin // C.ADDI4SPN
+							mem_rdata_q[14:12] <= 3'b000;
+							mem_rdata_q[31:20] <= {2'b0, mem_rdata_latched[10:7], mem_rdata_latched[12:11], mem_rdata_latched[5], mem_rdata_latched[6], 2'b00};
+						end
+						3'b010: begin // C.LW
+							mem_rdata_q[31:20] <= {5'b0, mem_rdata_latched[5], mem_rdata_latched[12:10], mem_rdata_latched[6], 2'b00};
+							mem_rdata_q[14:12] <= 3'b 010;
+						end
+						3'b 110: begin // C.SW
+							{mem_rdata_q[31:25], mem_rdata_q[11:7]} <= {5'b0, mem_rdata_latched[5], mem_rdata_latched[12:10], mem_rdata_latched[6], 2'b00};
+							mem_rdata_q[14:12] <= 3'b 010;
+						end
+					endcase
+				end
+				2'b01: begin // Quadrant 1
+					case (mem_rdata_latched[15:13])
+						3'b 000: begin // C.ADDI
+							mem_rdata_q[14:12] <= 3'b000;
+							mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]});
+						end
+						3'b 010: begin // C.LI
+							mem_rdata_q[14:12] <= 3'b000;
+							mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]});
+						end
+						3'b 011: begin
+							if (mem_rdata_latched[11:7] == 2) begin // C.ADDI16SP
+								mem_rdata_q[14:12] <= 3'b000;
+								mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[4:3],
+										mem_rdata_latched[5], mem_rdata_latched[2], mem_rdata_latched[6], 4'b 0000});
+							end else begin // C.LUI
+								mem_rdata_q[31:12] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]});
+							end
+						end
+						3'b100: begin
+							if (mem_rdata_latched[11:10] == 2'b00) begin // C.SRLI
+								mem_rdata_q[31:25] <= 7'b0000000;
+								mem_rdata_q[14:12] <= 3'b 101;
+							end
+							if (mem_rdata_latched[11:10] == 2'b01) begin // C.SRAI
+								mem_rdata_q[31:25] <= 7'b0100000;
+								mem_rdata_q[14:12] <= 3'b 101;
+							end
+							if (mem_rdata_latched[11:10] == 2'b10) begin // C.ANDI
+								mem_rdata_q[14:12] <= 3'b111;
+								mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]});
+							end
+							if (mem_rdata_latched[12:10] == 3'b011) begin // C.SUB, C.XOR, C.OR, C.AND
+								if (mem_rdata_latched[6:5] == 2'b00) mem_rdata_q[14:12] <= 3'b000;
+								if (mem_rdata_latched[6:5] == 2'b01) mem_rdata_q[14:12] <= 3'b100;
+								if (mem_rdata_latched[6:5] == 2'b10) mem_rdata_q[14:12] <= 3'b110;
+								if (mem_rdata_latched[6:5] == 2'b11) mem_rdata_q[14:12] <= 3'b111;
+								mem_rdata_q[31:25] <= mem_rdata_latched[6:5] == 2'b00 ? 7'b0100000 : 7'b0000000;
+							end
+						end
+						3'b 110: begin // C.BEQZ
+							mem_rdata_q[14:12] <= 3'b000;
+							{ mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8] } <=
+									$signed({mem_rdata_latched[12], mem_rdata_latched[6:5], mem_rdata_latched[2],
+											mem_rdata_latched[11:10], mem_rdata_latched[4:3]});
+						end
+						3'b 111: begin // C.BNEZ
+							mem_rdata_q[14:12] <= 3'b001;
+							{ mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8] } <=
+									$signed({mem_rdata_latched[12], mem_rdata_latched[6:5], mem_rdata_latched[2],
+											mem_rdata_latched[11:10], mem_rdata_latched[4:3]});
+						end
+					endcase
+				end
+				2'b10: begin // Quadrant 2
+					case (mem_rdata_latched[15:13])
+						3'b000: begin // C.SLLI
+							mem_rdata_q[31:25] <= 7'b0000000;
+							mem_rdata_q[14:12] <= 3'b 001;
+						end
+						3'b010: begin // C.LWSP
+							mem_rdata_q[31:20] <= {4'b0, mem_rdata_latched[3:2], mem_rdata_latched[12], mem_rdata_latched[6:4], 2'b00};
+							mem_rdata_q[14:12] <= 3'b 010;
+						end
+						3'b100: begin
+							if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] == 0) begin // C.JR
+								mem_rdata_q[14:12] <= 3'b000;
+								mem_rdata_q[31:20] <= 12'b0;
+							end
+							if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] != 0) begin // C.MV
+								mem_rdata_q[14:12] <= 3'b000;
+								mem_rdata_q[31:25] <= 7'b0000000;
+							end
+							if (mem_rdata_latched[12] != 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JALR
+								mem_rdata_q[14:12] <= 3'b000;
+								mem_rdata_q[31:20] <= 12'b0;
+							end
+							if (mem_rdata_latched[12] != 0 && mem_rdata_latched[6:2] != 0) begin // C.ADD
+								mem_rdata_q[14:12] <= 3'b000;
+								mem_rdata_q[31:25] <= 7'b0000000;
+							end
+						end
+						3'b110: begin // C.SWSP
+							{mem_rdata_q[31:25], mem_rdata_q[11:7]} <= {4'b0, mem_rdata_latched[8:7], mem_rdata_latched[12:9], 2'b00};
+							mem_rdata_q[14:12] <= 3'b 010;
+						end
+					endcase
+				end
+			endcase
+		end
+	end
+
+	always @(posedge clk) begin
+		if (resetn && !trap) begin
+			if (mem_do_prefetch || mem_do_rinst || mem_do_rdata)
+				`assert(!mem_do_wdata);
+
+			if (mem_do_prefetch || mem_do_rinst)
+				`assert(!mem_do_rdata);
+
+			if (mem_do_rdata)
+				`assert(!mem_do_prefetch && !mem_do_rinst);
+
+			if (mem_do_wdata)
+				`assert(!(mem_do_prefetch || mem_do_rinst || mem_do_rdata));
+
+			if (mem_state == 2 || mem_state == 3)
+				`assert(mem_valid || mem_do_prefetch);
+		end
+	end
+
+	always @(posedge clk) begin
+		if (!resetn || trap) begin
+			if (!resetn)
+				mem_state <= 0;
+			if (!resetn || mem_ready)
+				mem_valid <= 0;
+			mem_la_secondword <= 0;
+			prefetched_high_word <= 0;
+		end else begin
+			if (mem_la_read || mem_la_write) begin
+				mem_addr <= mem_la_addr;
+				mem_wstrb <= mem_la_wstrb & {4{mem_la_write}};
+			end
+			if (mem_la_write) begin
+				mem_wdata <= mem_la_wdata;
+			end
+			case (mem_state)
+				0: begin
+					if (mem_do_prefetch || mem_do_rinst || mem_do_rdata) begin
+						mem_valid <= !mem_la_use_prefetched_high_word;
+						mem_instr <= mem_do_prefetch || mem_do_rinst;
+						mem_wstrb <= 0;
+						mem_state <= 1;
+					end
+					if (mem_do_wdata) begin
+						mem_valid <= 1;
+						mem_instr <= 0;
+						mem_state <= 2;
+					end
+				end
+				1: begin
+					`assert(mem_wstrb == 0);
+					`assert(mem_do_prefetch || mem_do_rinst || mem_do_rdata);
+					`assert(mem_valid == !mem_la_use_prefetched_high_word);
+					`assert(mem_instr == (mem_do_prefetch || mem_do_rinst));
+					if (mem_xfer) begin
+						if (COMPRESSED_ISA && mem_la_read) begin
+							mem_valid <= 1;
+							mem_la_secondword <= 1;
+							if (!mem_la_use_prefetched_high_word)
+								mem_16bit_buffer <= mem_rdata[31:16];
+						end else begin
+							mem_valid <= 0;
+							mem_la_secondword <= 0;
+							if (COMPRESSED_ISA && !mem_do_rdata) begin
+								if (~&mem_rdata[1:0] || mem_la_secondword) begin
+									mem_16bit_buffer <= mem_rdata[31:16];
+									prefetched_high_word <= 1;
+								end else begin
+									prefetched_high_word <= 0;
+								end
+							end
+							mem_state <= mem_do_rinst || mem_do_rdata ? 0 : 3;
+						end
+					end
+				end
+				2: begin
+					`assert(mem_wstrb != 0);
+					`assert(mem_do_wdata);
+					if (mem_xfer) begin
+						mem_valid <= 0;
+						mem_state <= 0;
+					end
+				end
+				3: begin
+					`assert(mem_wstrb == 0);
+					`assert(mem_do_prefetch);
+					if (mem_do_rinst) begin
+						mem_state <= 0;
+					end
+				end
+			endcase
+		end
+
+		if (clear_prefetched_high_word)
+			prefetched_high_word <= 0;
+	end
+
+
+	// Instruction Decoder
+
+	reg instr_lui, instr_auipc, instr_jal, instr_jalr;
+	reg instr_beq, instr_bne, instr_blt, instr_bge, instr_bltu, instr_bgeu;
+	reg instr_lb, instr_lh, instr_lw, instr_lbu, instr_lhu, instr_sb, instr_sh, instr_sw;
+	reg instr_addi, instr_slti, instr_sltiu, instr_xori, instr_ori, instr_andi, instr_slli, instr_srli, instr_srai;
+	reg instr_add, instr_sub, instr_sll, instr_slt, instr_sltu, instr_xor, instr_srl, instr_sra, instr_or, instr_and;
+	reg instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh, instr_ecall_ebreak;
+	reg instr_getq, instr_setq, instr_retirq, instr_maskirq, instr_waitirq, instr_timer;
+	wire instr_trap;
+
+	reg [regindex_bits-1:0] decoded_rd, decoded_rs1, decoded_rs2;
+	reg [31:0] decoded_imm, decoded_imm_j;
+	reg decoder_trigger;
+	reg decoder_trigger_q;
+	reg decoder_pseudo_trigger;
+	reg decoder_pseudo_trigger_q;
+	reg compressed_instr;
+
+	reg is_lui_auipc_jal;
+	reg is_lb_lh_lw_lbu_lhu;
+	reg is_slli_srli_srai;
+	reg is_jalr_addi_slti_sltiu_xori_ori_andi;
+	reg is_sb_sh_sw;
+	reg is_sll_srl_sra;
+	reg is_lui_auipc_jal_jalr_addi_add_sub;
+	reg is_slti_blt_slt;
+	reg is_sltiu_bltu_sltu;
+	reg is_beq_bne_blt_bge_bltu_bgeu;
+	reg is_lbu_lhu_lw;
+	reg is_alu_reg_imm;
+	reg is_alu_reg_reg;
+	reg is_compare;
+
+	assign instr_trap = (CATCH_ILLINSN || WITH_PCPI) && !{instr_lui, instr_auipc, instr_jal, instr_jalr,
+			instr_beq, instr_bne, instr_blt, instr_bge, instr_bltu, instr_bgeu,
+			instr_lb, instr_lh, instr_lw, instr_lbu, instr_lhu, instr_sb, instr_sh, instr_sw,
+			instr_addi, instr_slti, instr_sltiu, instr_xori, instr_ori, instr_andi, instr_slli, instr_srli, instr_srai,
+			instr_add, instr_sub, instr_sll, instr_slt, instr_sltu, instr_xor, instr_srl, instr_sra, instr_or, instr_and,
+			instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh,
+			instr_getq, instr_setq, instr_retirq, instr_maskirq, instr_waitirq, instr_timer};
+
+	wire is_rdcycle_rdcycleh_rdinstr_rdinstrh;
+	assign is_rdcycle_rdcycleh_rdinstr_rdinstrh = |{instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh};
+
+	reg [63:0] new_ascii_instr;
+	`FORMAL_KEEP reg [63:0] dbg_ascii_instr;
+	`FORMAL_KEEP reg [31:0] dbg_insn_imm;
+	`FORMAL_KEEP reg [4:0] dbg_insn_rs1;
+	`FORMAL_KEEP reg [4:0] dbg_insn_rs2;
+	`FORMAL_KEEP reg [4:0] dbg_insn_rd;
+	`FORMAL_KEEP reg [31:0] dbg_rs1val;
+	`FORMAL_KEEP reg [31:0] dbg_rs2val;
+	`FORMAL_KEEP reg dbg_rs1val_valid;
+	`FORMAL_KEEP reg dbg_rs2val_valid;
+
+	always @* begin
+		new_ascii_instr = "";
+
+		if (instr_lui)      new_ascii_instr = "lui";
+		if (instr_auipc)    new_ascii_instr = "auipc";
+		if (instr_jal)      new_ascii_instr = "jal";
+		if (instr_jalr)     new_ascii_instr = "jalr";
+
+		if (instr_beq)      new_ascii_instr = "beq";
+		if (instr_bne)      new_ascii_instr = "bne";
+		if (instr_blt)      new_ascii_instr = "blt";
+		if (instr_bge)      new_ascii_instr = "bge";
+		if (instr_bltu)     new_ascii_instr = "bltu";
+		if (instr_bgeu)     new_ascii_instr = "bgeu";
+
+		if (instr_lb)       new_ascii_instr = "lb";
+		if (instr_lh)       new_ascii_instr = "lh";
+		if (instr_lw)       new_ascii_instr = "lw";
+		if (instr_lbu)      new_ascii_instr = "lbu";
+		if (instr_lhu)      new_ascii_instr = "lhu";
+		if (instr_sb)       new_ascii_instr = "sb";
+		if (instr_sh)       new_ascii_instr = "sh";
+		if (instr_sw)       new_ascii_instr = "sw";
+
+		if (instr_addi)     new_ascii_instr = "addi";
+		if (instr_slti)     new_ascii_instr = "slti";
+		if (instr_sltiu)    new_ascii_instr = "sltiu";
+		if (instr_xori)     new_ascii_instr = "xori";
+		if (instr_ori)      new_ascii_instr = "ori";
+		if (instr_andi)     new_ascii_instr = "andi";
+		if (instr_slli)     new_ascii_instr = "slli";
+		if (instr_srli)     new_ascii_instr = "srli";
+		if (instr_srai)     new_ascii_instr = "srai";
+
+		if (instr_add)      new_ascii_instr = "add";
+		if (instr_sub)      new_ascii_instr = "sub";
+		if (instr_sll)      new_ascii_instr = "sll";
+		if (instr_slt)      new_ascii_instr = "slt";
+		if (instr_sltu)     new_ascii_instr = "sltu";
+		if (instr_xor)      new_ascii_instr = "xor";
+		if (instr_srl)      new_ascii_instr = "srl";
+		if (instr_sra)      new_ascii_instr = "sra";
+		if (instr_or)       new_ascii_instr = "or";
+		if (instr_and)      new_ascii_instr = "and";
+
+		if (instr_rdcycle)  new_ascii_instr = "rdcycle";
+		if (instr_rdcycleh) new_ascii_instr = "rdcycleh";
+		if (instr_rdinstr)  new_ascii_instr = "rdinstr";
+		if (instr_rdinstrh) new_ascii_instr = "rdinstrh";
+
+		if (instr_getq)     new_ascii_instr = "getq";
+		if (instr_setq)     new_ascii_instr = "setq";
+		if (instr_retirq)   new_ascii_instr = "retirq";
+		if (instr_maskirq)  new_ascii_instr = "maskirq";
+		if (instr_waitirq)  new_ascii_instr = "waitirq";
+		if (instr_timer)    new_ascii_instr = "timer";
+	end
+
+	reg [63:0] q_ascii_instr;
+	reg [31:0] q_insn_imm;
+	reg [31:0] q_insn_opcode;
+	reg [4:0] q_insn_rs1;
+	reg [4:0] q_insn_rs2;
+	reg [4:0] q_insn_rd;
+	reg dbg_next;
+
+	wire launch_next_insn;
+	reg dbg_valid_insn;
+
+	reg [63:0] cached_ascii_instr;
+	reg [31:0] cached_insn_imm;
+	reg [31:0] cached_insn_opcode;
+	reg [4:0] cached_insn_rs1;
+	reg [4:0] cached_insn_rs2;
+	reg [4:0] cached_insn_rd;
+
+	always @(posedge clk) begin
+		q_ascii_instr <= dbg_ascii_instr;
+		q_insn_imm <= dbg_insn_imm;
+		q_insn_opcode <= dbg_insn_opcode;
+		q_insn_rs1 <= dbg_insn_rs1;
+		q_insn_rs2 <= dbg_insn_rs2;
+		q_insn_rd <= dbg_insn_rd;
+		dbg_next <= launch_next_insn;
+
+		if (!resetn || trap)
+			dbg_valid_insn <= 0;
+		else if (launch_next_insn)
+			dbg_valid_insn <= 1;
+
+		if (decoder_trigger_q) begin
+			cached_ascii_instr <= new_ascii_instr;
+			cached_insn_imm <= decoded_imm;
+			if (&next_insn_opcode[1:0])
+				cached_insn_opcode <= next_insn_opcode;
+			else
+				cached_insn_opcode <= {16'b0, next_insn_opcode[15:0]};
+			cached_insn_rs1 <= decoded_rs1;
+			cached_insn_rs2 <= decoded_rs2;
+			cached_insn_rd <= decoded_rd;
+		end
+
+		if (launch_next_insn) begin
+			dbg_insn_addr <= next_pc;
+		end
+	end
+
+	always @* begin
+		dbg_ascii_instr = q_ascii_instr;
+		dbg_insn_imm = q_insn_imm;
+		dbg_insn_opcode = q_insn_opcode;
+		dbg_insn_rs1 = q_insn_rs1;
+		dbg_insn_rs2 = q_insn_rs2;
+		dbg_insn_rd = q_insn_rd;
+
+		if (dbg_next) begin
+			if (decoder_pseudo_trigger_q) begin
+				dbg_ascii_instr = cached_ascii_instr;
+				dbg_insn_imm = cached_insn_imm;
+				dbg_insn_opcode = cached_insn_opcode;
+				dbg_insn_rs1 = cached_insn_rs1;
+				dbg_insn_rs2 = cached_insn_rs2;
+				dbg_insn_rd = cached_insn_rd;
+			end else begin
+				dbg_ascii_instr = new_ascii_instr;
+				if (&next_insn_opcode[1:0])
+					dbg_insn_opcode = next_insn_opcode;
+				else
+					dbg_insn_opcode = {16'b0, next_insn_opcode[15:0]};
+				dbg_insn_imm = decoded_imm;
+				dbg_insn_rs1 = decoded_rs1;
+				dbg_insn_rs2 = decoded_rs2;
+				dbg_insn_rd = decoded_rd;
+			end
+		end
+	end
+
+`ifdef DEBUGASM
+	always @(posedge clk) begin
+		if (dbg_next) begin
+			$display("debugasm %x %x %s", dbg_insn_addr, dbg_insn_opcode, dbg_ascii_instr ? dbg_ascii_instr : "*");
+		end
+	end
+`endif
+
+`ifdef DEBUG
+	always @(posedge clk) begin
+		if (dbg_next) begin
+			if (&dbg_insn_opcode[1:0])
+				$display("DECODE: 0x%08x 0x%08x %-0s", dbg_insn_addr, dbg_insn_opcode, dbg_ascii_instr ? dbg_ascii_instr : "UNKNOWN");
+			else
+				$display("DECODE: 0x%08x     0x%04x %-0s", dbg_insn_addr, dbg_insn_opcode[15:0], dbg_ascii_instr ? dbg_ascii_instr : "UNKNOWN");
+		end
+	end
+`endif
+
+	always @(posedge clk) begin
+		is_lui_auipc_jal <= |{instr_lui, instr_auipc, instr_jal};
+		is_lui_auipc_jal_jalr_addi_add_sub <= |{instr_lui, instr_auipc, instr_jal, instr_jalr, instr_addi, instr_add, instr_sub};
+		is_slti_blt_slt <= |{instr_slti, instr_blt, instr_slt};
+		is_sltiu_bltu_sltu <= |{instr_sltiu, instr_bltu, instr_sltu};
+		is_lbu_lhu_lw <= |{instr_lbu, instr_lhu, instr_lw};
+		is_compare <= |{is_beq_bne_blt_bge_bltu_bgeu, instr_slti, instr_slt, instr_sltiu, instr_sltu};
+
+		if (mem_do_rinst && mem_done) begin
+			instr_lui     <= mem_rdata_latched[6:0] == 7'b0110111;
+			instr_auipc   <= mem_rdata_latched[6:0] == 7'b0010111;
+			instr_jal     <= mem_rdata_latched[6:0] == 7'b1101111;
+			instr_jalr    <= mem_rdata_latched[6:0] == 7'b1100111 && mem_rdata_latched[14:12] == 3'b000;
+			instr_retirq  <= mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000010 && ENABLE_IRQ;
+			instr_waitirq <= mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000100 && ENABLE_IRQ;
+
+			is_beq_bne_blt_bge_bltu_bgeu <= mem_rdata_latched[6:0] == 7'b1100011;
+			is_lb_lh_lw_lbu_lhu          <= mem_rdata_latched[6:0] == 7'b0000011;
+			is_sb_sh_sw                  <= mem_rdata_latched[6:0] == 7'b0100011;
+			is_alu_reg_imm               <= mem_rdata_latched[6:0] == 7'b0010011;
+			is_alu_reg_reg               <= mem_rdata_latched[6:0] == 7'b0110011;
+
+			{ decoded_imm_j[31:20], decoded_imm_j[10:1], decoded_imm_j[11], decoded_imm_j[19:12], decoded_imm_j[0] } <= $signed({mem_rdata_latched[31:12], 1'b0});
+
+			decoded_rd <= mem_rdata_latched[11:7];
+			decoded_rs1 <= mem_rdata_latched[19:15];
+			decoded_rs2 <= mem_rdata_latched[24:20];
+
+			if (mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000000 && ENABLE_IRQ && ENABLE_IRQ_QREGS)
+				decoded_rs1[regindex_bits-1] <= 1; // instr_getq
+
+			if (mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000010 && ENABLE_IRQ)
+				decoded_rs1 <= ENABLE_IRQ_QREGS ? irqregs_offset : 3; // instr_retirq
+
+			compressed_instr <= 0;
+			if (COMPRESSED_ISA && mem_rdata_latched[1:0] != 2'b11) begin
+				compressed_instr <= 1;
+				decoded_rd <= 0;
+				decoded_rs1 <= 0;
+				decoded_rs2 <= 0;
+
+				{ decoded_imm_j[31:11], decoded_imm_j[4], decoded_imm_j[9:8], decoded_imm_j[10], decoded_imm_j[6],
+				  decoded_imm_j[7], decoded_imm_j[3:1], decoded_imm_j[5], decoded_imm_j[0] } <= $signed({mem_rdata_latched[12:2], 1'b0});
+
+				case (mem_rdata_latched[1:0])
+					2'b00: begin // Quadrant 0
+						case (mem_rdata_latched[15:13])
+							3'b000: begin // C.ADDI4SPN
+								is_alu_reg_imm <= |mem_rdata_latched[12:5];
+								decoded_rs1 <= 2;
+								decoded_rd <= 8 + mem_rdata_latched[4:2];
+							end
+							3'b010: begin // C.LW
+								is_lb_lh_lw_lbu_lhu <= 1;
+								decoded_rs1 <= 8 + mem_rdata_latched[9:7];
+								decoded_rd <= 8 + mem_rdata_latched[4:2];
+							end
+							3'b110: begin // C.SW
+								is_sb_sh_sw <= 1;
+								decoded_rs1 <= 8 + mem_rdata_latched[9:7];
+								decoded_rs2 <= 8 + mem_rdata_latched[4:2];
+							end
+						endcase
+					end
+					2'b01: begin // Quadrant 1
+						case (mem_rdata_latched[15:13])
+							3'b000: begin // C.NOP / C.ADDI
+								is_alu_reg_imm <= 1;
+								decoded_rd <= mem_rdata_latched[11:7];
+								decoded_rs1 <= mem_rdata_latched[11:7];
+							end
+							3'b001: begin // C.JAL
+								instr_jal <= 1;
+								decoded_rd <= 1;
+							end
+							3'b 010: begin // C.LI
+								is_alu_reg_imm <= 1;
+								decoded_rd <= mem_rdata_latched[11:7];
+								decoded_rs1 <= 0;
+							end
+							3'b 011: begin
+								if (mem_rdata_latched[12] || mem_rdata_latched[6:2]) begin
+									if (mem_rdata_latched[11:7] == 2) begin // C.ADDI16SP
+										is_alu_reg_imm <= 1;
+										decoded_rd <= mem_rdata_latched[11:7];
+										decoded_rs1 <= mem_rdata_latched[11:7];
+									end else begin // C.LUI
+										instr_lui <= 1;
+										decoded_rd <= mem_rdata_latched[11:7];
+										decoded_rs1 <= 0;
+									end
+								end
+							end
+							3'b100: begin
+								if (!mem_rdata_latched[11] && !mem_rdata_latched[12]) begin // C.SRLI, C.SRAI
+									is_alu_reg_imm <= 1;
+									decoded_rd <= 8 + mem_rdata_latched[9:7];
+									decoded_rs1 <= 8 + mem_rdata_latched[9:7];
+									decoded_rs2 <= {mem_rdata_latched[12], mem_rdata_latched[6:2]};
+								end
+								if (mem_rdata_latched[11:10] == 2'b10) begin // C.ANDI
+									is_alu_reg_imm <= 1;
+									decoded_rd <= 8 + mem_rdata_latched[9:7];
+									decoded_rs1 <= 8 + mem_rdata_latched[9:7];
+								end
+								if (mem_rdata_latched[12:10] == 3'b011) begin // C.SUB, C.XOR, C.OR, C.AND
+									is_alu_reg_reg <= 1;
+									decoded_rd <= 8 + mem_rdata_latched[9:7];
+									decoded_rs1 <= 8 + mem_rdata_latched[9:7];
+									decoded_rs2 <= 8 + mem_rdata_latched[4:2];
+								end
+							end
+							3'b101: begin // C.J
+								instr_jal <= 1;
+							end
+							3'b110: begin // C.BEQZ
+								is_beq_bne_blt_bge_bltu_bgeu <= 1;
+								decoded_rs1 <= 8 + mem_rdata_latched[9:7];
+								decoded_rs2 <= 0;
+							end
+							3'b111: begin // C.BNEZ
+								is_beq_bne_blt_bge_bltu_bgeu <= 1;
+								decoded_rs1 <= 8 + mem_rdata_latched[9:7];
+								decoded_rs2 <= 0;
+							end
+						endcase
+					end
+					2'b10: begin // Quadrant 2
+						case (mem_rdata_latched[15:13])
+							3'b000: begin // C.SLLI
+								if (!mem_rdata_latched[12]) begin
+									is_alu_reg_imm <= 1;
+									decoded_rd <= mem_rdata_latched[11:7];
+									decoded_rs1 <= mem_rdata_latched[11:7];
+									decoded_rs2 <= {mem_rdata_latched[12], mem_rdata_latched[6:2]};
+								end
+							end
+							3'b010: begin // C.LWSP
+								if (mem_rdata_latched[11:7]) begin
+									is_lb_lh_lw_lbu_lhu <= 1;
+									decoded_rd <= mem_rdata_latched[11:7];
+									decoded_rs1 <= 2;
+								end
+							end
+							3'b100: begin
+								if (mem_rdata_latched[12] == 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JR
+									instr_jalr <= 1;
+									decoded_rd <= 0;
+									decoded_rs1 <= mem_rdata_latched[11:7];
+								end
+								if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] != 0) begin // C.MV
+									is_alu_reg_reg <= 1;
+									decoded_rd <= mem_rdata_latched[11:7];
+									decoded_rs1 <= 0;
+									decoded_rs2 <= mem_rdata_latched[6:2];
+								end
+								if (mem_rdata_latched[12] != 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JALR
+									instr_jalr <= 1;
+									decoded_rd <= 1;
+									decoded_rs1 <= mem_rdata_latched[11:7];
+								end
+								if (mem_rdata_latched[12] != 0 && mem_rdata_latched[6:2] != 0) begin // C.ADD
+									is_alu_reg_reg <= 1;
+									decoded_rd <= mem_rdata_latched[11:7];
+									decoded_rs1 <= mem_rdata_latched[11:7];
+									decoded_rs2 <= mem_rdata_latched[6:2];
+								end
+							end
+							3'b110: begin // C.SWSP
+								is_sb_sh_sw <= 1;
+								decoded_rs1 <= 2;
+								decoded_rs2 <= mem_rdata_latched[6:2];
+							end
+						endcase
+					end
+				endcase
+			end
+		end
+
+		if (decoder_trigger && !decoder_pseudo_trigger) begin
+			pcpi_insn <= WITH_PCPI ? mem_rdata_q : 'bx;
+
+			instr_beq   <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b000;
+			instr_bne   <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b001;
+			instr_blt   <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b100;
+			instr_bge   <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b101;
+			instr_bltu  <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b110;
+			instr_bgeu  <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b111;
+
+			instr_lb    <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b000;
+			instr_lh    <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b001;
+			instr_lw    <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b010;
+			instr_lbu   <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b100;
+			instr_lhu   <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b101;
+
+			instr_sb    <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b000;
+			instr_sh    <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b001;
+			instr_sw    <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b010;
+
+			instr_addi  <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b000;
+			instr_slti  <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b010;
+			instr_sltiu <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b011;
+			instr_xori  <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b100;
+			instr_ori   <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b110;
+			instr_andi  <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b111;
+
+			instr_slli  <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_srli  <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_srai  <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000;
+
+			instr_add   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b000 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_sub   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b000 && mem_rdata_q[31:25] == 7'b0100000;
+			instr_sll   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_slt   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b010 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_sltu  <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b011 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_xor   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b100 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_srl   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_sra   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000;
+			instr_or    <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b110 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_and   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b111 && mem_rdata_q[31:25] == 7'b0000000;
+
+			instr_rdcycle  <= ((mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000000000000010) ||
+			                   (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000000100000010)) && ENABLE_COUNTERS;
+			instr_rdcycleh <= ((mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000000000000010) ||
+			                   (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000000100000010)) && ENABLE_COUNTERS && ENABLE_COUNTERS64;
+			instr_rdinstr  <=  (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000001000000010) && ENABLE_COUNTERS;
+			instr_rdinstrh <=  (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000001000000010) && ENABLE_COUNTERS && ENABLE_COUNTERS64;
+
+			instr_ecall_ebreak <= ((mem_rdata_q[6:0] == 7'b1110011 && !mem_rdata_q[31:21] && !mem_rdata_q[19:7]) ||
+					(COMPRESSED_ISA && mem_rdata_q[15:0] == 16'h9002));
+
+			instr_getq    <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000000 && ENABLE_IRQ && ENABLE_IRQ_QREGS;
+			instr_setq    <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000001 && ENABLE_IRQ && ENABLE_IRQ_QREGS;
+			instr_maskirq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000011 && ENABLE_IRQ;
+			instr_timer   <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000101 && ENABLE_IRQ && ENABLE_IRQ_TIMER;
+
+			is_slli_srli_srai <= is_alu_reg_imm && |{
+				mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000,
+				mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000,
+				mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000
+			};
+
+			is_jalr_addi_slti_sltiu_xori_ori_andi <= instr_jalr || is_alu_reg_imm && |{
+				mem_rdata_q[14:12] == 3'b000,
+				mem_rdata_q[14:12] == 3'b010,
+				mem_rdata_q[14:12] == 3'b011,
+				mem_rdata_q[14:12] == 3'b100,
+				mem_rdata_q[14:12] == 3'b110,
+				mem_rdata_q[14:12] == 3'b111
+			};
+
+			is_sll_srl_sra <= is_alu_reg_reg && |{
+				mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000,
+				mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000,
+				mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000
+			};
+
+			is_lui_auipc_jal_jalr_addi_add_sub <= 0;
+			is_compare <= 0;
+
+			(* parallel_case *)
+			case (1'b1)
+				instr_jal:
+					decoded_imm <= decoded_imm_j;
+				|{instr_lui, instr_auipc}:
+					decoded_imm <= mem_rdata_q[31:12] << 12;
+				|{instr_jalr, is_lb_lh_lw_lbu_lhu, is_alu_reg_imm}:
+					decoded_imm <= $signed(mem_rdata_q[31:20]);
+				is_beq_bne_blt_bge_bltu_bgeu:
+					decoded_imm <= $signed({mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8], 1'b0});
+				is_sb_sh_sw:
+					decoded_imm <= $signed({mem_rdata_q[31:25], mem_rdata_q[11:7]});
+				default:
+					decoded_imm <= 1'bx;
+			endcase
+		end
+
+		if (!resetn) begin
+			is_beq_bne_blt_bge_bltu_bgeu <= 0;
+			is_compare <= 0;
+
+			instr_beq   <= 0;
+			instr_bne   <= 0;
+			instr_blt   <= 0;
+			instr_bge   <= 0;
+			instr_bltu  <= 0;
+			instr_bgeu  <= 0;
+
+			instr_addi  <= 0;
+			instr_slti  <= 0;
+			instr_sltiu <= 0;
+			instr_xori  <= 0;
+			instr_ori   <= 0;
+			instr_andi  <= 0;
+
+			instr_add   <= 0;
+			instr_sub   <= 0;
+			instr_sll   <= 0;
+			instr_slt   <= 0;
+			instr_sltu  <= 0;
+			instr_xor   <= 0;
+			instr_srl   <= 0;
+			instr_sra   <= 0;
+			instr_or    <= 0;
+			instr_and   <= 0;
+		end
+	end
+
+
+	// Main State Machine
+
+	localparam cpu_state_trap   = 8'b10000000;
+	localparam cpu_state_fetch  = 8'b01000000;
+	localparam cpu_state_ld_rs1 = 8'b00100000;
+	localparam cpu_state_ld_rs2 = 8'b00010000;
+	localparam cpu_state_exec   = 8'b00001000;
+	localparam cpu_state_shift  = 8'b00000100;
+	localparam cpu_state_stmem  = 8'b00000010;
+	localparam cpu_state_ldmem  = 8'b00000001;
+
+	reg [7:0] cpu_state;
+	reg [1:0] irq_state;
+
+	`FORMAL_KEEP reg [127:0] dbg_ascii_state;
+
+	always @* begin
+		dbg_ascii_state = "";
+		if (cpu_state == cpu_state_trap)   dbg_ascii_state = "trap";
+		if (cpu_state == cpu_state_fetch)  dbg_ascii_state = "fetch";
+		if (cpu_state == cpu_state_ld_rs1) dbg_ascii_state = "ld_rs1";
+		if (cpu_state == cpu_state_ld_rs2) dbg_ascii_state = "ld_rs2";
+		if (cpu_state == cpu_state_exec)   dbg_ascii_state = "exec";
+		if (cpu_state == cpu_state_shift)  dbg_ascii_state = "shift";
+		if (cpu_state == cpu_state_stmem)  dbg_ascii_state = "stmem";
+		if (cpu_state == cpu_state_ldmem)  dbg_ascii_state = "ldmem";
+	end
+
+	reg set_mem_do_rinst;
+	reg set_mem_do_rdata;
+	reg set_mem_do_wdata;
+
+	reg latched_store;
+	reg latched_stalu;
+	reg latched_branch;
+	reg latched_compr;
+	reg latched_trace;
+	reg latched_is_lu;
+	reg latched_is_lh;
+	reg latched_is_lb;
+	reg [regindex_bits-1:0] latched_rd;
+
+	reg [31:0] current_pc;
+	assign next_pc = latched_store && latched_branch ? reg_out & ~1 : reg_next_pc;
+
+	reg [3:0] pcpi_timeout_counter;
+	reg pcpi_timeout;
+
+	reg [31:0] next_irq_pending;
+	reg do_waitirq;
+
+	reg [31:0] alu_out, alu_out_q;
+	reg alu_out_0, alu_out_0_q;
+	reg alu_wait, alu_wait_2;
+
+	reg [31:0] alu_add_sub;
+	reg [31:0] alu_shl, alu_shr;
+	reg alu_eq, alu_ltu, alu_lts;
+
+	generate if (TWO_CYCLE_ALU) begin
+		always @(posedge clk) begin
+			alu_add_sub <= instr_sub ? reg_op1 - reg_op2 : reg_op1 + reg_op2;
+			alu_eq <= reg_op1 == reg_op2;
+			alu_lts <= $signed(reg_op1) < $signed(reg_op2);
+			alu_ltu <= reg_op1 < reg_op2;
+			alu_shl <= reg_op1 << reg_op2[4:0];
+			alu_shr <= $signed({instr_sra || instr_srai ? reg_op1[31] : 1'b0, reg_op1}) >>> reg_op2[4:0];
+		end
+	end else begin
+		always @* begin
+			alu_add_sub = instr_sub ? reg_op1 - reg_op2 : reg_op1 + reg_op2;
+			alu_eq = reg_op1 == reg_op2;
+			alu_lts = $signed(reg_op1) < $signed(reg_op2);
+			alu_ltu = reg_op1 < reg_op2;
+			alu_shl = reg_op1 << reg_op2[4:0];
+			alu_shr = $signed({instr_sra || instr_srai ? reg_op1[31] : 1'b0, reg_op1}) >>> reg_op2[4:0];
+		end
+	end endgenerate
+
+	always @* begin
+		alu_out_0 = 'bx;
+		(* parallel_case, full_case *)
+		case (1'b1)
+			instr_beq:
+				alu_out_0 = alu_eq;
+			instr_bne:
+				alu_out_0 = !alu_eq;
+			instr_bge:
+				alu_out_0 = !alu_lts;
+			instr_bgeu:
+				alu_out_0 = !alu_ltu;
+			is_slti_blt_slt && (!TWO_CYCLE_COMPARE || !{instr_beq,instr_bne,instr_bge,instr_bgeu}):
+				alu_out_0 = alu_lts;
+			is_sltiu_bltu_sltu && (!TWO_CYCLE_COMPARE || !{instr_beq,instr_bne,instr_bge,instr_bgeu}):
+				alu_out_0 = alu_ltu;
+		endcase
+
+		alu_out = 'bx;
+		(* parallel_case, full_case *)
+		case (1'b1)
+			is_lui_auipc_jal_jalr_addi_add_sub:
+				alu_out = alu_add_sub;
+			is_compare:
+				alu_out = alu_out_0;
+			instr_xori || instr_xor:
+				alu_out = reg_op1 ^ reg_op2;
+			instr_ori || instr_or:
+				alu_out = reg_op1 | reg_op2;
+			instr_andi || instr_and:
+				alu_out = reg_op1 & reg_op2;
+			BARREL_SHIFTER && (instr_sll || instr_slli):
+				alu_out = alu_shl;
+			BARREL_SHIFTER && (instr_srl || instr_srli || instr_sra || instr_srai):
+				alu_out = alu_shr;
+		endcase
+
+`ifdef RISCV_FORMAL_BLACKBOX_ALU
+		alu_out_0 = $anyseq;
+		alu_out = $anyseq;
+`endif
+	end
+
+	reg clear_prefetched_high_word_q;
+	always @(posedge clk) clear_prefetched_high_word_q <= clear_prefetched_high_word;
+
+	always @* begin
+		clear_prefetched_high_word = clear_prefetched_high_word_q;
+		if (!prefetched_high_word)
+			clear_prefetched_high_word = 0;
+		if (latched_branch || irq_state || !resetn)
+			clear_prefetched_high_word = COMPRESSED_ISA;
+	end
+
+	reg cpuregs_write;
+	reg [31:0] cpuregs_wrdata;
+	reg [31:0] cpuregs_rs1;
+	reg [31:0] cpuregs_rs2;
+	reg [regindex_bits-1:0] decoded_rs;
+
+	always @* begin
+		cpuregs_write = 0;
+		cpuregs_wrdata = 'bx;
+
+		if (cpu_state == cpu_state_fetch) begin
+			(* parallel_case *)
+			case (1'b1)
+				latched_branch: begin
+					cpuregs_wrdata = reg_pc + (latched_compr ? 2 : 4);
+					cpuregs_write = 1;
+				end
+				latched_store && !latched_branch: begin
+					cpuregs_wrdata = latched_stalu ? alu_out_q : reg_out;
+					cpuregs_write = 1;
+				end
+				ENABLE_IRQ && irq_state[0]: begin
+					cpuregs_wrdata = reg_next_pc | latched_compr;
+					cpuregs_write = 1;
+				end
+				ENABLE_IRQ && irq_state[1]: begin
+					cpuregs_wrdata = irq_pending & ~irq_mask;
+					cpuregs_write = 1;
+				end
+			endcase
+		end
+	end
+
+`ifndef PICORV32_REGS
+	always @(posedge clk) begin
+		if (resetn && cpuregs_write && latched_rd)
+`ifdef PICORV32_TESTBUG_001
+			cpuregs[latched_rd ^ 1] <= cpuregs_wrdata;
+`elsif PICORV32_TESTBUG_002
+			cpuregs[latched_rd] <= cpuregs_wrdata ^ 1;
+`else
+			cpuregs[latched_rd] <= cpuregs_wrdata;
+`endif
+	end
+
+	always @* begin
+		decoded_rs = 'bx;
+		if (ENABLE_REGS_DUALPORT) begin
+`ifndef RISCV_FORMAL_BLACKBOX_REGS
+			cpuregs_rs1 = decoded_rs1 ? cpuregs[decoded_rs1] : 0;
+			cpuregs_rs2 = decoded_rs2 ? cpuregs[decoded_rs2] : 0;
+`else
+			cpuregs_rs1 = decoded_rs1 ? $anyseq : 0;
+			cpuregs_rs2 = decoded_rs2 ? $anyseq : 0;
+`endif
+		end else begin
+			decoded_rs = (cpu_state == cpu_state_ld_rs2) ? decoded_rs2 : decoded_rs1;
+`ifndef RISCV_FORMAL_BLACKBOX_REGS
+			cpuregs_rs1 = decoded_rs ? cpuregs[decoded_rs] : 0;
+`else
+			cpuregs_rs1 = decoded_rs ? $anyseq : 0;
+`endif
+			cpuregs_rs2 = cpuregs_rs1;
+		end
+	end
+`else
+	wire[31:0] cpuregs_rdata1;
+	wire[31:0] cpuregs_rdata2;
+
+	wire [5:0] cpuregs_waddr = latched_rd;
+	wire [5:0] cpuregs_raddr1 = ENABLE_REGS_DUALPORT ? decoded_rs1 : decoded_rs;
+	wire [5:0] cpuregs_raddr2 = ENABLE_REGS_DUALPORT ? decoded_rs2 : 0;
+
+	`PICORV32_REGS cpuregs (
+		.clk(clk),
+		.wen(resetn && cpuregs_write && latched_rd),
+		.waddr(cpuregs_waddr),
+		.raddr1(cpuregs_raddr1),
+		.raddr2(cpuregs_raddr2),
+		.wdata(cpuregs_wrdata),
+		.rdata1(cpuregs_rdata1),
+		.rdata2(cpuregs_rdata2)
+	);
+
+	always @* begin
+		decoded_rs = 'bx;
+		if (ENABLE_REGS_DUALPORT) begin
+			cpuregs_rs1 = decoded_rs1 ? cpuregs_rdata1 : 0;
+			cpuregs_rs2 = decoded_rs2 ? cpuregs_rdata2 : 0;
+		end else begin
+			decoded_rs = (cpu_state == cpu_state_ld_rs2) ? decoded_rs2 : decoded_rs1;
+			cpuregs_rs1 = decoded_rs ? cpuregs_rdata1 : 0;
+			cpuregs_rs2 = cpuregs_rs1;
+		end
+	end
+`endif
+
+	assign launch_next_insn = cpu_state == cpu_state_fetch && decoder_trigger && (!ENABLE_IRQ || irq_delay || irq_active || !(irq_pending & ~irq_mask));
+
+	always @(posedge clk) begin
+		trap <= 0;
+		reg_sh <= 'bx;
+		reg_out <= 'bx;
+		set_mem_do_rinst = 0;
+		set_mem_do_rdata = 0;
+		set_mem_do_wdata = 0;
+
+		alu_out_0_q <= alu_out_0;
+		alu_out_q <= alu_out;
+
+		alu_wait <= 0;
+		alu_wait_2 <= 0;
+
+		if (launch_next_insn) begin
+			dbg_rs1val <= 'bx;
+			dbg_rs2val <= 'bx;
+			dbg_rs1val_valid <= 0;
+			dbg_rs2val_valid <= 0;
+		end
+
+		if (WITH_PCPI && CATCH_ILLINSN) begin
+			if (resetn && pcpi_valid && !pcpi_int_wait) begin
+				if (pcpi_timeout_counter)
+					pcpi_timeout_counter <= pcpi_timeout_counter - 1;
+			end else
+				pcpi_timeout_counter <= ~0;
+			pcpi_timeout <= !pcpi_timeout_counter;
+		end
+
+		if (ENABLE_COUNTERS) begin
+			count_cycle <= resetn ? count_cycle + 1 : 0;
+			if (!ENABLE_COUNTERS64) count_cycle[63:32] <= 0;
+		end else begin
+			count_cycle <= 'bx;
+			count_instr <= 'bx;
+		end
+
+		next_irq_pending = ENABLE_IRQ ? irq_pending & LATCHED_IRQ : 'bx;
+
+		if (ENABLE_IRQ && ENABLE_IRQ_TIMER && timer) begin
+			timer <= timer - 1;
+		end
+
+		decoder_trigger <= mem_do_rinst && mem_done;
+		decoder_trigger_q <= decoder_trigger;
+		decoder_pseudo_trigger <= 0;
+		decoder_pseudo_trigger_q <= decoder_pseudo_trigger;
+		do_waitirq <= 0;
+
+		trace_valid <= 0;
+
+		if (!ENABLE_TRACE)
+			trace_data <= 'bx;
+
+		if (!resetn) begin
+			reg_pc <= PROGADDR_RESET;
+			reg_next_pc <= PROGADDR_RESET;
+			if (ENABLE_COUNTERS)
+				count_instr <= 0;
+			latched_store <= 0;
+			latched_stalu <= 0;
+			latched_branch <= 0;
+			latched_trace <= 0;
+			latched_is_lu <= 0;
+			latched_is_lh <= 0;
+			latched_is_lb <= 0;
+			pcpi_valid <= 0;
+			pcpi_timeout <= 0;
+			irq_active <= 0;
+			irq_delay <= 0;
+			irq_mask <= ~0;
+			next_irq_pending = 0;
+			irq_state <= 0;
+			eoi <= 0;
+			timer <= 0;
+			if (~STACKADDR) begin
+				latched_store <= 1;
+				latched_rd <= 2;
+				reg_out <= STACKADDR;
+			end
+			cpu_state <= cpu_state_fetch;
+		end else
+		(* parallel_case, full_case *)
+		case (cpu_state)
+			cpu_state_trap: begin
+				trap <= 1;
+			end
+
+			cpu_state_fetch: begin
+				mem_do_rinst <= !decoder_trigger && !do_waitirq;
+				mem_wordsize <= 0;
+
+				current_pc = reg_next_pc;
+
+				(* parallel_case *)
+				case (1'b1)
+					latched_branch: begin
+						current_pc = latched_store ? (latched_stalu ? alu_out_q : reg_out) & ~1 : reg_next_pc;
+						`debug($display("ST_RD:  %2d 0x%08x, BRANCH 0x%08x", latched_rd, reg_pc + (latched_compr ? 2 : 4), current_pc);)
+					end
+					latched_store && !latched_branch: begin
+						`debug($display("ST_RD:  %2d 0x%08x", latched_rd, latched_stalu ? alu_out_q : reg_out);)
+					end
+					ENABLE_IRQ && irq_state[0]: begin
+						current_pc = PROGADDR_IRQ;
+						irq_active <= 1;
+						mem_do_rinst <= 1;
+					end
+					ENABLE_IRQ && irq_state[1]: begin
+						eoi <= irq_pending & ~irq_mask;
+						next_irq_pending = next_irq_pending & irq_mask;
+					end
+				endcase
+
+				if (ENABLE_TRACE && latched_trace) begin
+					latched_trace <= 0;
+					trace_valid <= 1;
+					if (latched_branch)
+						trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_BRANCH | (current_pc & 32'hfffffffe);
+					else
+						trace_data <= (irq_active ? TRACE_IRQ : 0) | (latched_stalu ? alu_out_q : reg_out);
+				end
+
+				reg_pc <= current_pc;
+				reg_next_pc <= current_pc;
+
+				latched_store <= 0;
+				latched_stalu <= 0;
+				latched_branch <= 0;
+				latched_is_lu <= 0;
+				latched_is_lh <= 0;
+				latched_is_lb <= 0;
+				latched_rd <= decoded_rd;
+				latched_compr <= compressed_instr;
+
+				if (ENABLE_IRQ && ((decoder_trigger && !irq_active && !irq_delay && |(irq_pending & ~irq_mask)) || irq_state)) begin
+					irq_state <=
+						irq_state == 2'b00 ? 2'b01 :
+						irq_state == 2'b01 ? 2'b10 : 2'b00;
+					latched_compr <= latched_compr;
+					if (ENABLE_IRQ_QREGS)
+						latched_rd <= irqregs_offset | irq_state[0];
+					else
+						latched_rd <= irq_state[0] ? 4 : 3;
+				end else
+				if (ENABLE_IRQ && (decoder_trigger || do_waitirq) && instr_waitirq) begin
+					if (irq_pending) begin
+						latched_store <= 1;
+						reg_out <= irq_pending;
+						reg_next_pc <= current_pc + (compressed_instr ? 2 : 4);
+						mem_do_rinst <= 1;
+					end else
+						do_waitirq <= 1;
+				end else
+				if (decoder_trigger) begin
+					`debug($display("-- %-0t", $time);)
+					irq_delay <= irq_active;
+					reg_next_pc <= current_pc + (compressed_instr ? 2 : 4);
+					if (ENABLE_TRACE)
+						latched_trace <= 1;
+					if (ENABLE_COUNTERS) begin
+						count_instr <= count_instr + 1;
+						if (!ENABLE_COUNTERS64) count_instr[63:32] <= 0;
+					end
+					if (instr_jal) begin
+						mem_do_rinst <= 1;
+						reg_next_pc <= current_pc + decoded_imm_j;
+						latched_branch <= 1;
+					end else begin
+						mem_do_rinst <= 0;
+						mem_do_prefetch <= !instr_jalr && !instr_retirq;
+						cpu_state <= cpu_state_ld_rs1;
+					end
+				end
+			end
+
+			cpu_state_ld_rs1: begin
+				reg_op1 <= 'bx;
+				reg_op2 <= 'bx;
+
+				(* parallel_case *)
+				case (1'b1)
+					(CATCH_ILLINSN || WITH_PCPI) && instr_trap: begin
+						if (WITH_PCPI) begin
+							`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+							reg_op1 <= cpuregs_rs1;
+							dbg_rs1val <= cpuregs_rs1;
+							dbg_rs1val_valid <= 1;
+							if (ENABLE_REGS_DUALPORT) begin
+								pcpi_valid <= 1;
+								`debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);)
+								reg_sh <= cpuregs_rs2;
+								reg_op2 <= cpuregs_rs2;
+								dbg_rs2val <= cpuregs_rs2;
+								dbg_rs2val_valid <= 1;
+								if (pcpi_int_ready) begin
+									mem_do_rinst <= 1;
+									pcpi_valid <= 0;
+									reg_out <= pcpi_int_rd;
+									latched_store <= pcpi_int_wr;
+									cpu_state <= cpu_state_fetch;
+								end else
+								if (CATCH_ILLINSN && (pcpi_timeout || instr_ecall_ebreak)) begin
+									pcpi_valid <= 0;
+									`debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);)
+									if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin
+										next_irq_pending[irq_ebreak] = 1;
+										cpu_state <= cpu_state_fetch;
+									end else
+										cpu_state <= cpu_state_trap;
+								end
+							end else begin
+								cpu_state <= cpu_state_ld_rs2;
+							end
+						end else begin
+							`debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);)
+							if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin
+								next_irq_pending[irq_ebreak] = 1;
+								cpu_state <= cpu_state_fetch;
+							end else
+								cpu_state <= cpu_state_trap;
+						end
+					end
+					ENABLE_COUNTERS && is_rdcycle_rdcycleh_rdinstr_rdinstrh: begin
+						(* parallel_case, full_case *)
+						case (1'b1)
+							instr_rdcycle:
+								reg_out <= count_cycle[31:0];
+							instr_rdcycleh && ENABLE_COUNTERS64:
+								reg_out <= count_cycle[63:32];
+							instr_rdinstr:
+								reg_out <= count_instr[31:0];
+							instr_rdinstrh && ENABLE_COUNTERS64:
+								reg_out <= count_instr[63:32];
+						endcase
+						latched_store <= 1;
+						cpu_state <= cpu_state_fetch;
+					end
+					is_lui_auipc_jal: begin
+						reg_op1 <= instr_lui ? 0 : reg_pc;
+						reg_op2 <= decoded_imm;
+						if (TWO_CYCLE_ALU)
+							alu_wait <= 1;
+						else
+							mem_do_rinst <= mem_do_prefetch;
+						cpu_state <= cpu_state_exec;
+					end
+					ENABLE_IRQ && ENABLE_IRQ_QREGS && instr_getq: begin
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						reg_out <= cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						latched_store <= 1;
+						cpu_state <= cpu_state_fetch;
+					end
+					ENABLE_IRQ && ENABLE_IRQ_QREGS && instr_setq: begin
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						reg_out <= cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						latched_rd <= latched_rd | irqregs_offset;
+						latched_store <= 1;
+						cpu_state <= cpu_state_fetch;
+					end
+					ENABLE_IRQ && instr_retirq: begin
+						eoi <= 0;
+						irq_active <= 0;
+						latched_branch <= 1;
+						latched_store <= 1;
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						reg_out <= CATCH_MISALIGN ? (cpuregs_rs1 & 32'h fffffffe) : cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						cpu_state <= cpu_state_fetch;
+					end
+					ENABLE_IRQ && instr_maskirq: begin
+						latched_store <= 1;
+						reg_out <= irq_mask;
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						irq_mask <= cpuregs_rs1 | MASKED_IRQ;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						cpu_state <= cpu_state_fetch;
+					end
+					ENABLE_IRQ && ENABLE_IRQ_TIMER && instr_timer: begin
+						latched_store <= 1;
+						reg_out <= timer;
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						timer <= cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						cpu_state <= cpu_state_fetch;
+					end
+					is_lb_lh_lw_lbu_lhu && !instr_trap: begin
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						reg_op1 <= cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						cpu_state <= cpu_state_ldmem;
+						mem_do_rinst <= 1;
+					end
+					is_slli_srli_srai && !BARREL_SHIFTER: begin
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						reg_op1 <= cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						reg_sh <= decoded_rs2;
+						cpu_state <= cpu_state_shift;
+					end
+					is_jalr_addi_slti_sltiu_xori_ori_andi, is_slli_srli_srai && BARREL_SHIFTER: begin
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						reg_op1 <= cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						reg_op2 <= is_slli_srli_srai && BARREL_SHIFTER ? decoded_rs2 : decoded_imm;
+						if (TWO_CYCLE_ALU)
+							alu_wait <= 1;
+						else
+							mem_do_rinst <= mem_do_prefetch;
+						cpu_state <= cpu_state_exec;
+					end
+					default: begin
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						reg_op1 <= cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						if (ENABLE_REGS_DUALPORT) begin
+							`debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);)
+							reg_sh <= cpuregs_rs2;
+							reg_op2 <= cpuregs_rs2;
+							dbg_rs2val <= cpuregs_rs2;
+							dbg_rs2val_valid <= 1;
+							(* parallel_case *)
+							case (1'b1)
+								is_sb_sh_sw: begin
+									cpu_state <= cpu_state_stmem;
+									mem_do_rinst <= 1;
+								end
+								is_sll_srl_sra && !BARREL_SHIFTER: begin
+									cpu_state <= cpu_state_shift;
+								end
+								default: begin
+									if (TWO_CYCLE_ALU || (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu)) begin
+										alu_wait_2 <= TWO_CYCLE_ALU && (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu);
+										alu_wait <= 1;
+									end else
+										mem_do_rinst <= mem_do_prefetch;
+									cpu_state <= cpu_state_exec;
+								end
+							endcase
+						end else
+							cpu_state <= cpu_state_ld_rs2;
+					end
+				endcase
+			end
+
+			cpu_state_ld_rs2: begin
+				`debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);)
+				reg_sh <= cpuregs_rs2;
+				reg_op2 <= cpuregs_rs2;
+				dbg_rs2val <= cpuregs_rs2;
+				dbg_rs2val_valid <= 1;
+
+				(* parallel_case *)
+				case (1'b1)
+					WITH_PCPI && instr_trap: begin
+						pcpi_valid <= 1;
+						if (pcpi_int_ready) begin
+							mem_do_rinst <= 1;
+							pcpi_valid <= 0;
+							reg_out <= pcpi_int_rd;
+							latched_store <= pcpi_int_wr;
+							cpu_state <= cpu_state_fetch;
+						end else
+						if (CATCH_ILLINSN && (pcpi_timeout || instr_ecall_ebreak)) begin
+							pcpi_valid <= 0;
+							`debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);)
+							if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin
+								next_irq_pending[irq_ebreak] = 1;
+								cpu_state <= cpu_state_fetch;
+							end else
+								cpu_state <= cpu_state_trap;
+						end
+					end
+					is_sb_sh_sw: begin
+						cpu_state <= cpu_state_stmem;
+						mem_do_rinst <= 1;
+					end
+					is_sll_srl_sra && !BARREL_SHIFTER: begin
+						cpu_state <= cpu_state_shift;
+					end
+					default: begin
+						if (TWO_CYCLE_ALU || (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu)) begin
+							alu_wait_2 <= TWO_CYCLE_ALU && (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu);
+							alu_wait <= 1;
+						end else
+							mem_do_rinst <= mem_do_prefetch;
+						cpu_state <= cpu_state_exec;
+					end
+				endcase
+			end
+
+			cpu_state_exec: begin
+				reg_out <= reg_pc + decoded_imm;
+				if ((TWO_CYCLE_ALU || TWO_CYCLE_COMPARE) && (alu_wait || alu_wait_2)) begin
+					mem_do_rinst <= mem_do_prefetch && !alu_wait_2;
+					alu_wait <= alu_wait_2;
+				end else
+				if (is_beq_bne_blt_bge_bltu_bgeu) begin
+					latched_rd <= 0;
+					latched_store <= TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0;
+					latched_branch <= TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0;
+					if (mem_done)
+						cpu_state <= cpu_state_fetch;
+					if (TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0) begin
+						decoder_trigger <= 0;
+						set_mem_do_rinst = 1;
+					end
+				end else begin
+					latched_branch <= instr_jalr;
+					latched_store <= 1;
+					latched_stalu <= 1;
+					cpu_state <= cpu_state_fetch;
+				end
+			end
+
+			cpu_state_shift: begin
+				latched_store <= 1;
+				if (reg_sh == 0) begin
+					reg_out <= reg_op1;
+					mem_do_rinst <= mem_do_prefetch;
+					cpu_state <= cpu_state_fetch;
+				end else if (TWO_STAGE_SHIFT && reg_sh >= 4) begin
+					(* parallel_case, full_case *)
+					case (1'b1)
+						instr_slli || instr_sll: reg_op1 <= reg_op1 << 4;
+						instr_srli || instr_srl: reg_op1 <= reg_op1 >> 4;
+						instr_srai || instr_sra: reg_op1 <= $signed(reg_op1) >>> 4;
+					endcase
+					reg_sh <= reg_sh - 4;
+				end else begin
+					(* parallel_case, full_case *)
+					case (1'b1)
+						instr_slli || instr_sll: reg_op1 <= reg_op1 << 1;
+						instr_srli || instr_srl: reg_op1 <= reg_op1 >> 1;
+						instr_srai || instr_sra: reg_op1 <= $signed(reg_op1) >>> 1;
+					endcase
+					reg_sh <= reg_sh - 1;
+				end
+			end
+
+			cpu_state_stmem: begin
+				if (ENABLE_TRACE)
+					reg_out <= reg_op2;
+				if (!mem_do_prefetch || mem_done) begin
+					if (!mem_do_wdata) begin
+						(* parallel_case, full_case *)
+						case (1'b1)
+							instr_sb: mem_wordsize <= 2;
+							instr_sh: mem_wordsize <= 1;
+							instr_sw: mem_wordsize <= 0;
+						endcase
+						if (ENABLE_TRACE) begin
+							trace_valid <= 1;
+							trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_ADDR | ((reg_op1 + decoded_imm) & 32'hffffffff);
+						end
+						reg_op1 <= reg_op1 + decoded_imm;
+						set_mem_do_wdata = 1;
+					end
+					if (!mem_do_prefetch && mem_done) begin
+						cpu_state <= cpu_state_fetch;
+						decoder_trigger <= 1;
+						decoder_pseudo_trigger <= 1;
+					end
+				end
+			end
+
+			cpu_state_ldmem: begin
+				latched_store <= 1;
+				if (!mem_do_prefetch || mem_done) begin
+					if (!mem_do_rdata) begin
+						(* parallel_case, full_case *)
+						case (1'b1)
+							instr_lb || instr_lbu: mem_wordsize <= 2;
+							instr_lh || instr_lhu: mem_wordsize <= 1;
+							instr_lw: mem_wordsize <= 0;
+						endcase
+						latched_is_lu <= is_lbu_lhu_lw;
+						latched_is_lh <= instr_lh;
+						latched_is_lb <= instr_lb;
+						if (ENABLE_TRACE) begin
+							trace_valid <= 1;
+							trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_ADDR | ((reg_op1 + decoded_imm) & 32'hffffffff);
+						end
+						reg_op1 <= reg_op1 + decoded_imm;
+						set_mem_do_rdata = 1;
+					end
+					if (!mem_do_prefetch && mem_done) begin
+						(* parallel_case, full_case *)
+						case (1'b1)
+							latched_is_lu: reg_out <= mem_rdata_word;
+							latched_is_lh: reg_out <= $signed(mem_rdata_word[15:0]);
+							latched_is_lb: reg_out <= $signed(mem_rdata_word[7:0]);
+						endcase
+						decoder_trigger <= 1;
+						decoder_pseudo_trigger <= 1;
+						cpu_state <= cpu_state_fetch;
+					end
+				end
+			end
+		endcase
+
+		if (ENABLE_IRQ) begin
+			next_irq_pending = next_irq_pending | irq;
+			if(ENABLE_IRQ_TIMER && timer)
+				if (timer - 1 == 0)
+					next_irq_pending[irq_timer] = 1;
+		end
+
+		if (CATCH_MISALIGN && resetn && (mem_do_rdata || mem_do_wdata)) begin
+			if (mem_wordsize == 0 && reg_op1[1:0] != 0) begin
+				`debug($display("MISALIGNED WORD: 0x%08x", reg_op1);)
+				if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin
+					next_irq_pending[irq_buserror] = 1;
+				end else
+					cpu_state <= cpu_state_trap;
+			end
+			if (mem_wordsize == 1 && reg_op1[0] != 0) begin
+				`debug($display("MISALIGNED HALFWORD: 0x%08x", reg_op1);)
+				if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin
+					next_irq_pending[irq_buserror] = 1;
+				end else
+					cpu_state <= cpu_state_trap;
+			end
+		end
+		if (CATCH_MISALIGN && resetn && mem_do_rinst && (COMPRESSED_ISA ? reg_pc[0] : |reg_pc[1:0])) begin
+			`debug($display("MISALIGNED INSTRUCTION: 0x%08x", reg_pc);)
+			if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin
+				next_irq_pending[irq_buserror] = 1;
+			end else
+				cpu_state <= cpu_state_trap;
+		end
+		if (!CATCH_ILLINSN && decoder_trigger_q && !decoder_pseudo_trigger_q && instr_ecall_ebreak) begin
+			cpu_state <= cpu_state_trap;
+		end
+
+		if (!resetn || mem_done) begin
+			mem_do_prefetch <= 0;
+			mem_do_rinst <= 0;
+			mem_do_rdata <= 0;
+			mem_do_wdata <= 0;
+		end
+
+		if (set_mem_do_rinst)
+			mem_do_rinst <= 1;
+		if (set_mem_do_rdata)
+			mem_do_rdata <= 1;
+		if (set_mem_do_wdata)
+			mem_do_wdata <= 1;
+
+		irq_pending <= next_irq_pending & ~MASKED_IRQ;
+
+		if (!CATCH_MISALIGN) begin
+			if (COMPRESSED_ISA) begin
+				reg_pc[0] <= 0;
+				reg_next_pc[0] <= 0;
+			end else begin
+				reg_pc[1:0] <= 0;
+				reg_next_pc[1:0] <= 0;
+			end
+		end
+		current_pc = 'bx;
+	end
+
+`ifdef RISCV_FORMAL
+	reg dbg_irq_call;
+	reg dbg_irq_enter;
+	reg [31:0] dbg_irq_ret;
+	always @(posedge clk) begin
+		rvfi_valid <= resetn && (launch_next_insn || trap) && dbg_valid_insn;
+		rvfi_order <= resetn ? rvfi_order + rvfi_valid : 0;
+
+		rvfi_insn <= dbg_insn_opcode;
+		rvfi_rs1_addr <= dbg_rs1val_valid ? dbg_insn_rs1 : 0;
+		rvfi_rs2_addr <= dbg_rs2val_valid ? dbg_insn_rs2 : 0;
+		rvfi_pc_rdata <= dbg_insn_addr;
+		rvfi_rs1_rdata <= dbg_rs1val_valid ? dbg_rs1val : 0;
+		rvfi_rs2_rdata <= dbg_rs2val_valid ? dbg_rs2val : 0;
+		rvfi_trap <= trap;
+		rvfi_halt <= trap;
+		rvfi_intr <= dbg_irq_enter;
+		rvfi_mode <= 3;
+		rvfi_ixl <= 1;
+
+		if (!resetn) begin
+			dbg_irq_call <= 0;
+			dbg_irq_enter <= 0;
+		end else
+		if (rvfi_valid) begin
+			dbg_irq_call <= 0;
+			dbg_irq_enter <= dbg_irq_call;
+		end else
+		if (irq_state == 1) begin
+			dbg_irq_call <= 1;
+			dbg_irq_ret <= next_pc;
+		end
+
+		if (!resetn) begin
+			rvfi_rd_addr <= 0;
+			rvfi_rd_wdata <= 0;
+		end else
+		if (cpuregs_write && !irq_state) begin
+`ifdef PICORV32_TESTBUG_003
+			rvfi_rd_addr <= latched_rd ^ 1;
+`else
+			rvfi_rd_addr <= latched_rd;
+`endif
+`ifdef PICORV32_TESTBUG_004
+			rvfi_rd_wdata <= latched_rd ? cpuregs_wrdata ^ 1 : 0;
+`else
+			rvfi_rd_wdata <= latched_rd ? cpuregs_wrdata : 0;
+`endif
+		end else
+		if (rvfi_valid) begin
+			rvfi_rd_addr <= 0;
+			rvfi_rd_wdata <= 0;
+		end
+
+		casez (dbg_insn_opcode)
+			32'b 0000000_?????_000??_???_?????_0001011: begin // getq
+				rvfi_rs1_addr <= 0;
+				rvfi_rs1_rdata <= 0;
+			end
+			32'b 0000001_?????_?????_???_000??_0001011: begin // setq
+				rvfi_rd_addr <= 0;
+				rvfi_rd_wdata <= 0;
+			end
+			32'b 0000010_?????_00000_???_00000_0001011: begin // retirq
+				rvfi_rs1_addr <= 0;
+				rvfi_rs1_rdata <= 0;
+			end
+		endcase
+
+		if (!dbg_irq_call) begin
+			if (dbg_mem_instr) begin
+				rvfi_mem_addr <= 0;
+				rvfi_mem_rmask <= 0;
+				rvfi_mem_wmask <= 0;
+				rvfi_mem_rdata <= 0;
+				rvfi_mem_wdata <= 0;
+			end else
+			if (dbg_mem_valid && dbg_mem_ready) begin
+				rvfi_mem_addr <= dbg_mem_addr;
+				rvfi_mem_rmask <= dbg_mem_wstrb ? 0 : ~0;
+				rvfi_mem_wmask <= dbg_mem_wstrb;
+				rvfi_mem_rdata <= dbg_mem_rdata;
+				rvfi_mem_wdata <= dbg_mem_wdata;
+			end
+		end
+	end
+
+	always @* begin
+`ifdef PICORV32_TESTBUG_005
+		rvfi_pc_wdata = (dbg_irq_call ? dbg_irq_ret : dbg_insn_addr) ^ 4;
+`else
+		rvfi_pc_wdata = dbg_irq_call ? dbg_irq_ret : dbg_insn_addr;
+`endif
+
+		rvfi_csr_mcycle_rmask = 0;
+		rvfi_csr_mcycle_wmask = 0;
+		rvfi_csr_mcycle_rdata = 0;
+		rvfi_csr_mcycle_wdata = 0;
+
+		rvfi_csr_minstret_rmask = 0;
+		rvfi_csr_minstret_wmask = 0;
+		rvfi_csr_minstret_rdata = 0;
+		rvfi_csr_minstret_wdata = 0;
+
+		if (rvfi_valid && rvfi_insn[6:0] == 7'b 1110011 && rvfi_insn[13:12] == 3'b010) begin
+			if (rvfi_insn[31:20] == 12'h C00) begin
+				rvfi_csr_mcycle_rmask = 64'h 0000_0000_FFFF_FFFF;
+				rvfi_csr_mcycle_rdata = {32'h 0000_0000, rvfi_rd_wdata};
+			end
+			if (rvfi_insn[31:20] == 12'h C80) begin
+				rvfi_csr_mcycle_rmask = 64'h FFFF_FFFF_0000_0000;
+				rvfi_csr_mcycle_rdata = {rvfi_rd_wdata, 32'h 0000_0000};
+			end
+			if (rvfi_insn[31:20] == 12'h C02) begin
+				rvfi_csr_minstret_rmask = 64'h 0000_0000_FFFF_FFFF;
+				rvfi_csr_minstret_rdata = {32'h 0000_0000, rvfi_rd_wdata};
+			end
+			if (rvfi_insn[31:20] == 12'h C82) begin
+				rvfi_csr_minstret_rmask = 64'h FFFF_FFFF_0000_0000;
+				rvfi_csr_minstret_rdata = {rvfi_rd_wdata, 32'h 0000_0000};
+			end
+		end
+	end
+`endif
+
+	// Formal Verification
+`ifdef FORMAL
+	reg [3:0] last_mem_nowait;
+	always @(posedge clk)
+		last_mem_nowait <= {last_mem_nowait, mem_ready || !mem_valid};
+
+	// stall the memory interface for max 4 cycles
+	restrict property (|last_mem_nowait || mem_ready || !mem_valid);
+
+	// resetn low in first cycle, after that resetn high
+	restrict property (resetn != $initstate);
+
+	// this just makes it much easier to read traces. uncomment as needed.
+	// assume property (mem_valid || !mem_ready);
+
+	reg ok;
+	always @* begin
+		if (resetn) begin
+			// instruction fetches are read-only
+			if (mem_valid && mem_instr)
+				assert (mem_wstrb == 0);
+
+			// cpu_state must be valid
+			ok = 0;
+			if (cpu_state == cpu_state_trap)   ok = 1;
+			if (cpu_state == cpu_state_fetch)  ok = 1;
+			if (cpu_state == cpu_state_ld_rs1) ok = 1;
+			if (cpu_state == cpu_state_ld_rs2) ok = !ENABLE_REGS_DUALPORT;
+			if (cpu_state == cpu_state_exec)   ok = 1;
+			if (cpu_state == cpu_state_shift)  ok = 1;
+			if (cpu_state == cpu_state_stmem)  ok = 1;
+			if (cpu_state == cpu_state_ldmem)  ok = 1;
+			assert (ok);
+		end
+	end
+
+	reg last_mem_la_read = 0;
+	reg last_mem_la_write = 0;
+	reg [31:0] last_mem_la_addr;
+	reg [31:0] last_mem_la_wdata;
+	reg [3:0] last_mem_la_wstrb = 0;
+
+	always @(posedge clk) begin
+		last_mem_la_read <= mem_la_read;
+		last_mem_la_write <= mem_la_write;
+		last_mem_la_addr <= mem_la_addr;
+		last_mem_la_wdata <= mem_la_wdata;
+		last_mem_la_wstrb <= mem_la_wstrb;
+
+		if (last_mem_la_read) begin
+			assert(mem_valid);
+			assert(mem_addr == last_mem_la_addr);
+			assert(mem_wstrb == 0);
+		end
+		if (last_mem_la_write) begin
+			assert(mem_valid);
+			assert(mem_addr == last_mem_la_addr);
+			assert(mem_wdata == last_mem_la_wdata);
+			assert(mem_wstrb == last_mem_la_wstrb);
+		end
+		if (mem_la_read || mem_la_write) begin
+			assert(!mem_valid || mem_ready);
+		end
+	end
+`endif
+endmodule
+
+// This is a simple example implementation of PICORV32_REGS.
+// Use the PICORV32_REGS mechanism if you want to use custom
+// memory resources to implement the processor register file.
+// Note that your implementation must match the requirements of
+// the PicoRV32 configuration. (e.g. QREGS, etc)
+module picorv32_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:30];
+
+	always @(posedge clk)
+		if (wen) regs[~waddr[4:0]] <= wdata;
+
+	assign rdata1 = regs[~raddr1[4:0]];
+	assign rdata2 = regs[~raddr2[4:0]];
+endmodule
+
+
+/***************************************************************
+ * picorv32_pcpi_mul
+ ***************************************************************/
+
+module picorv32_pcpi_mul #(
+	parameter STEPS_AT_ONCE = 1,
+	parameter CARRY_CHAIN = 4
+) (
+	input clk, resetn,
+
+	input             pcpi_valid,
+	input      [31:0] pcpi_insn,
+	input      [31:0] pcpi_rs1,
+	input      [31:0] pcpi_rs2,
+	output reg        pcpi_wr,
+	output reg [31:0] pcpi_rd,
+	output reg        pcpi_wait,
+	output reg        pcpi_ready
+);
+	reg instr_mul, instr_mulh, instr_mulhsu, instr_mulhu;
+	wire instr_any_mul = |{instr_mul, instr_mulh, instr_mulhsu, instr_mulhu};
+	wire instr_any_mulh = |{instr_mulh, instr_mulhsu, instr_mulhu};
+	wire instr_rs1_signed = |{instr_mulh, instr_mulhsu};
+	wire instr_rs2_signed = |{instr_mulh};
+
+	reg pcpi_wait_q;
+	wire mul_start = pcpi_wait && !pcpi_wait_q;
+
+	always @(posedge clk) begin
+		instr_mul <= 0;
+		instr_mulh <= 0;
+		instr_mulhsu <= 0;
+		instr_mulhu <= 0;
+
+		if (resetn && pcpi_valid && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001) begin
+			case (pcpi_insn[14:12])
+				3'b000: instr_mul <= 1;
+				3'b001: instr_mulh <= 1;
+				3'b010: instr_mulhsu <= 1;
+				3'b011: instr_mulhu <= 1;
+			endcase
+		end
+
+		pcpi_wait <= instr_any_mul;
+		pcpi_wait_q <= pcpi_wait;
+	end
+
+	reg [63:0] rs1, rs2, rd, rdx;
+	reg [63:0] next_rs1, next_rs2, this_rs2;
+	reg [63:0] next_rd, next_rdx, next_rdt;
+	reg [6:0] mul_counter;
+	reg mul_waiting;
+	reg mul_finish;
+	integer i, j;
+
+	// carry save accumulator
+	always @* begin
+		next_rd = rd;
+		next_rdx = rdx;
+		next_rs1 = rs1;
+		next_rs2 = rs2;
+
+		for (i = 0; i < STEPS_AT_ONCE; i=i+1) begin
+			this_rs2 = next_rs1[0] ? next_rs2 : 0;
+			if (CARRY_CHAIN == 0) begin
+				next_rdt = next_rd ^ next_rdx ^ this_rs2;
+				next_rdx = ((next_rd & next_rdx) | (next_rd & this_rs2) | (next_rdx & this_rs2)) << 1;
+				next_rd = next_rdt;
+			end else begin
+				next_rdt = 0;
+				for (j = 0; j < 64; j = j + CARRY_CHAIN)
+					{next_rdt[j+CARRY_CHAIN-1], next_rd[j +: CARRY_CHAIN]} =
+							next_rd[j +: CARRY_CHAIN] + next_rdx[j +: CARRY_CHAIN] + this_rs2[j +: CARRY_CHAIN];
+				next_rdx = next_rdt << 1;
+			end
+			next_rs1 = next_rs1 >> 1;
+			next_rs2 = next_rs2 << 1;
+		end
+	end
+
+	always @(posedge clk) begin
+		mul_finish <= 0;
+		if (!resetn) begin
+			mul_waiting <= 1;
+		end else
+		if (mul_waiting) begin
+			if (instr_rs1_signed)
+				rs1 <= $signed(pcpi_rs1);
+			else
+				rs1 <= $unsigned(pcpi_rs1);
+
+			if (instr_rs2_signed)
+				rs2 <= $signed(pcpi_rs2);
+			else
+				rs2 <= $unsigned(pcpi_rs2);
+
+			rd <= 0;
+			rdx <= 0;
+			mul_counter <= (instr_any_mulh ? 63 - STEPS_AT_ONCE : 31 - STEPS_AT_ONCE);
+			mul_waiting <= !mul_start;
+		end else begin
+			rd <= next_rd;
+			rdx <= next_rdx;
+			rs1 <= next_rs1;
+			rs2 <= next_rs2;
+
+			mul_counter <= mul_counter - STEPS_AT_ONCE;
+			if (mul_counter[6]) begin
+				mul_finish <= 1;
+				mul_waiting <= 1;
+			end
+		end
+	end
+
+	always @(posedge clk) begin
+		pcpi_wr <= 0;
+		pcpi_ready <= 0;
+		if (mul_finish && resetn) begin
+			pcpi_wr <= 1;
+			pcpi_ready <= 1;
+			pcpi_rd <= instr_any_mulh ? rd >> 32 : rd;
+		end
+	end
+endmodule
+
+module picorv32_pcpi_fast_mul #(
+	parameter EXTRA_MUL_FFS = 0,
+	parameter EXTRA_INSN_FFS = 0,
+	parameter MUL_CLKGATE = 0
+) (
+	input clk, resetn,
+
+	input             pcpi_valid,
+	input      [31:0] pcpi_insn,
+	input      [31:0] pcpi_rs1,
+	input      [31:0] pcpi_rs2,
+	output            pcpi_wr,
+	output     [31:0] pcpi_rd,
+	output            pcpi_wait,
+	output            pcpi_ready
+);
+	reg instr_mul, instr_mulh, instr_mulhsu, instr_mulhu;
+	wire instr_any_mul = |{instr_mul, instr_mulh, instr_mulhsu, instr_mulhu};
+	wire instr_any_mulh = |{instr_mulh, instr_mulhsu, instr_mulhu};
+	wire instr_rs1_signed = |{instr_mulh, instr_mulhsu};
+	wire instr_rs2_signed = |{instr_mulh};
+
+	reg shift_out;
+	reg [3:0] active;
+	reg [32:0] rs1, rs2, rs1_q, rs2_q;
+	reg [63:0] rd, rd_q;
+
+	wire pcpi_insn_valid = pcpi_valid && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001;
+	reg pcpi_insn_valid_q;
+
+	always @* begin
+		instr_mul = 0;
+		instr_mulh = 0;
+		instr_mulhsu = 0;
+		instr_mulhu = 0;
+
+		if (resetn && (EXTRA_INSN_FFS ? pcpi_insn_valid_q : pcpi_insn_valid)) begin
+			case (pcpi_insn[14:12])
+				3'b000: instr_mul = 1;
+				3'b001: instr_mulh = 1;
+				3'b010: instr_mulhsu = 1;
+				3'b011: instr_mulhu = 1;
+			endcase
+		end
+	end
+
+	always @(posedge clk) begin
+		pcpi_insn_valid_q <= pcpi_insn_valid;
+		if (!MUL_CLKGATE || active[0]) begin
+			rs1_q <= rs1;
+			rs2_q <= rs2;
+		end
+		if (!MUL_CLKGATE || active[1]) begin
+			rd <= $signed(EXTRA_MUL_FFS ? rs1_q : rs1) * $signed(EXTRA_MUL_FFS ? rs2_q : rs2);
+		end
+		if (!MUL_CLKGATE || active[2]) begin
+			rd_q <= rd;
+		end
+	end
+
+	always @(posedge clk) begin
+		if (instr_any_mul && !(EXTRA_MUL_FFS ? active[3:0] : active[1:0])) begin
+			if (instr_rs1_signed)
+				rs1 <= $signed(pcpi_rs1);
+			else
+				rs1 <= $unsigned(pcpi_rs1);
+
+			if (instr_rs2_signed)
+				rs2 <= $signed(pcpi_rs2);
+			else
+				rs2 <= $unsigned(pcpi_rs2);
+			active[0] <= 1;
+		end else begin
+			active[0] <= 0;
+		end
+
+		active[3:1] <= active;
+		shift_out <= instr_any_mulh;
+
+		if (!resetn)
+			active <= 0;
+	end
+
+	assign pcpi_wr = active[EXTRA_MUL_FFS ? 3 : 1];
+	assign pcpi_wait = 0;
+	assign pcpi_ready = active[EXTRA_MUL_FFS ? 3 : 1];
+`ifdef RISCV_FORMAL_ALTOPS
+	assign pcpi_rd =
+			instr_mul    ? (pcpi_rs1 + pcpi_rs2) ^ 32'h5876063e :
+			instr_mulh   ? (pcpi_rs1 + pcpi_rs2) ^ 32'hf6583fb7 :
+			instr_mulhsu ? (pcpi_rs1 - pcpi_rs2) ^ 32'hecfbe137 :
+			instr_mulhu  ? (pcpi_rs1 + pcpi_rs2) ^ 32'h949ce5e8 : 1'bx;
+`else
+	assign pcpi_rd = shift_out ? (EXTRA_MUL_FFS ? rd_q : rd) >> 32 : (EXTRA_MUL_FFS ? rd_q : rd);
+`endif
+endmodule
+
+
+/***************************************************************
+ * picorv32_pcpi_div
+ ***************************************************************/
+
+module picorv32_pcpi_div (
+	input clk, resetn,
+
+	input             pcpi_valid,
+	input      [31:0] pcpi_insn,
+	input      [31:0] pcpi_rs1,
+	input      [31:0] pcpi_rs2,
+	output reg        pcpi_wr,
+	output reg [31:0] pcpi_rd,
+	output reg        pcpi_wait,
+	output reg        pcpi_ready
+);
+	reg instr_div, instr_divu, instr_rem, instr_remu;
+	wire instr_any_div_rem = |{instr_div, instr_divu, instr_rem, instr_remu};
+
+	reg pcpi_wait_q;
+	wire start = pcpi_wait && !pcpi_wait_q;
+
+	always @(posedge clk) begin
+		instr_div <= 0;
+		instr_divu <= 0;
+		instr_rem <= 0;
+		instr_remu <= 0;
+
+		if (resetn && pcpi_valid && !pcpi_ready && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001) begin
+			case (pcpi_insn[14:12])
+				3'b100: instr_div <= 1;
+				3'b101: instr_divu <= 1;
+				3'b110: instr_rem <= 1;
+				3'b111: instr_remu <= 1;
+			endcase
+		end
+
+		pcpi_wait <= instr_any_div_rem && resetn;
+		pcpi_wait_q <= pcpi_wait && resetn;
+	end
+
+	reg [31:0] dividend;
+	reg [62:0] divisor;
+	reg [31:0] quotient;
+	reg [31:0] quotient_msk;
+	reg running;
+	reg outsign;
+
+	always @(posedge clk) begin
+		pcpi_ready <= 0;
+		pcpi_wr <= 0;
+		pcpi_rd <= 'bx;
+
+		if (!resetn) begin
+			running <= 0;
+		end else
+		if (start) begin
+			running <= 1;
+			dividend <= (instr_div || instr_rem) && pcpi_rs1[31] ? -pcpi_rs1 : pcpi_rs1;
+			divisor <= ((instr_div || instr_rem) && pcpi_rs2[31] ? -pcpi_rs2 : pcpi_rs2) << 31;
+			outsign <= (instr_div && (pcpi_rs1[31] != pcpi_rs2[31]) && |pcpi_rs2) || (instr_rem && pcpi_rs1[31]);
+			quotient <= 0;
+			quotient_msk <= 1 << 31;
+		end else
+		if (!quotient_msk && running) begin
+			running <= 0;
+			pcpi_ready <= 1;
+			pcpi_wr <= 1;
+`ifdef RISCV_FORMAL_ALTOPS
+			case (1)
+				instr_div:  pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h7f8529ec;
+				instr_divu: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h10e8fd70;
+				instr_rem:  pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h8da68fa5;
+				instr_remu: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h3138d0e1;
+			endcase
+`else
+			if (instr_div || instr_divu)
+				pcpi_rd <= outsign ? -quotient : quotient;
+			else
+				pcpi_rd <= outsign ? -dividend : dividend;
+`endif
+		end else begin
+			if (divisor <= dividend) begin
+				dividend <= dividend - divisor;
+				quotient <= quotient | quotient_msk;
+			end
+			divisor <= divisor >> 1;
+`ifdef RISCV_FORMAL_ALTOPS
+			quotient_msk <= quotient_msk >> 5;
+`else
+			quotient_msk <= quotient_msk >> 1;
+`endif
+		end
+	end
+endmodule
+
+
+/***************************************************************
+ * picorv32_axi
+ ***************************************************************/
+
+module picorv32_axi #(
+	parameter [ 0:0] ENABLE_COUNTERS = 1,
+	parameter [ 0:0] ENABLE_COUNTERS64 = 1,
+	parameter [ 0:0] ENABLE_REGS_16_31 = 1,
+	parameter [ 0:0] ENABLE_REGS_DUALPORT = 1,
+	parameter [ 0:0] TWO_STAGE_SHIFT = 1,
+	parameter [ 0:0] BARREL_SHIFTER = 0,
+	parameter [ 0:0] TWO_CYCLE_COMPARE = 0,
+	parameter [ 0:0] TWO_CYCLE_ALU = 0,
+	parameter [ 0:0] COMPRESSED_ISA = 0,
+	parameter [ 0:0] CATCH_MISALIGN = 1,
+	parameter [ 0:0] CATCH_ILLINSN = 1,
+	parameter [ 0:0] ENABLE_PCPI = 0,
+	parameter [ 0:0] ENABLE_MUL = 0,
+	parameter [ 0:0] ENABLE_FAST_MUL = 0,
+	parameter [ 0:0] ENABLE_DIV = 0,
+	parameter [ 0:0] ENABLE_IRQ = 0,
+	parameter [ 0:0] ENABLE_IRQ_QREGS = 1,
+	parameter [ 0:0] ENABLE_IRQ_TIMER = 1,
+	parameter [ 0:0] ENABLE_TRACE = 0,
+	parameter [ 0:0] REGS_INIT_ZERO = 0,
+	parameter [31:0] MASKED_IRQ = 32'h 0000_0000,
+	parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff,
+	parameter [31:0] PROGADDR_RESET = 32'h 0000_0000,
+	parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010,
+	parameter [31:0] STACKADDR = 32'h ffff_ffff
+) (
+	input clk, resetn,
+	output trap,
+
+	// AXI4-lite master memory interface
+
+	output        mem_axi_awvalid,
+	input         mem_axi_awready,
+	output [31:0] mem_axi_awaddr,
+	output [ 2:0] mem_axi_awprot,
+
+	output        mem_axi_wvalid,
+	input         mem_axi_wready,
+	output [31:0] mem_axi_wdata,
+	output [ 3:0] mem_axi_wstrb,
+
+	input         mem_axi_bvalid,
+	output        mem_axi_bready,
+
+	output        mem_axi_arvalid,
+	input         mem_axi_arready,
+	output [31:0] mem_axi_araddr,
+	output [ 2:0] mem_axi_arprot,
+
+	input         mem_axi_rvalid,
+	output        mem_axi_rready,
+	input  [31:0] mem_axi_rdata,
+
+	// Pico Co-Processor Interface (PCPI)
+	output        pcpi_valid,
+	output [31:0] pcpi_insn,
+	output [31:0] pcpi_rs1,
+	output [31:0] pcpi_rs2,
+	input         pcpi_wr,
+	input  [31:0] pcpi_rd,
+	input         pcpi_wait,
+	input         pcpi_ready,
+
+	// IRQ interface
+	input  [31:0] irq,
+	output [31:0] eoi,
+
+`ifdef RISCV_FORMAL
+	output        rvfi_valid,
+	output [63:0] rvfi_order,
+	output [31:0] rvfi_insn,
+	output        rvfi_trap,
+	output        rvfi_halt,
+	output        rvfi_intr,
+	output [ 4:0] rvfi_rs1_addr,
+	output [ 4:0] rvfi_rs2_addr,
+	output [31:0] rvfi_rs1_rdata,
+	output [31:0] rvfi_rs2_rdata,
+	output [ 4:0] rvfi_rd_addr,
+	output [31:0] rvfi_rd_wdata,
+	output [31:0] rvfi_pc_rdata,
+	output [31:0] rvfi_pc_wdata,
+	output [31:0] rvfi_mem_addr,
+	output [ 3:0] rvfi_mem_rmask,
+	output [ 3:0] rvfi_mem_wmask,
+	output [31:0] rvfi_mem_rdata,
+	output [31:0] rvfi_mem_wdata,
+`endif
+
+	// Trace Interface
+	output        trace_valid,
+	output [35:0] trace_data
+);
+	wire        mem_valid;
+	wire [31:0] mem_addr;
+	wire [31:0] mem_wdata;
+	wire [ 3:0] mem_wstrb;
+	wire        mem_instr;
+	wire        mem_ready;
+	wire [31:0] mem_rdata;
+
+	picorv32_axi_adapter axi_adapter (
+		.clk            (clk            ),
+		.resetn         (resetn         ),
+		.mem_axi_awvalid(mem_axi_awvalid),
+		.mem_axi_awready(mem_axi_awready),
+		.mem_axi_awaddr (mem_axi_awaddr ),
+		.mem_axi_awprot (mem_axi_awprot ),
+		.mem_axi_wvalid (mem_axi_wvalid ),
+		.mem_axi_wready (mem_axi_wready ),
+		.mem_axi_wdata  (mem_axi_wdata  ),
+		.mem_axi_wstrb  (mem_axi_wstrb  ),
+		.mem_axi_bvalid (mem_axi_bvalid ),
+		.mem_axi_bready (mem_axi_bready ),
+		.mem_axi_arvalid(mem_axi_arvalid),
+		.mem_axi_arready(mem_axi_arready),
+		.mem_axi_araddr (mem_axi_araddr ),
+		.mem_axi_arprot (mem_axi_arprot ),
+		.mem_axi_rvalid (mem_axi_rvalid ),
+		.mem_axi_rready (mem_axi_rready ),
+		.mem_axi_rdata  (mem_axi_rdata  ),
+		.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      )
+	);
+
+	picorv32 #(
+		.ENABLE_COUNTERS     (ENABLE_COUNTERS     ),
+		.ENABLE_COUNTERS64   (ENABLE_COUNTERS64   ),
+		.ENABLE_REGS_16_31   (ENABLE_REGS_16_31   ),
+		.ENABLE_REGS_DUALPORT(ENABLE_REGS_DUALPORT),
+		.TWO_STAGE_SHIFT     (TWO_STAGE_SHIFT     ),
+		.BARREL_SHIFTER      (BARREL_SHIFTER      ),
+		.TWO_CYCLE_COMPARE   (TWO_CYCLE_COMPARE   ),
+		.TWO_CYCLE_ALU       (TWO_CYCLE_ALU       ),
+		.COMPRESSED_ISA      (COMPRESSED_ISA      ),
+		.CATCH_MISALIGN      (CATCH_MISALIGN      ),
+		.CATCH_ILLINSN       (CATCH_ILLINSN       ),
+		.ENABLE_PCPI         (ENABLE_PCPI         ),
+		.ENABLE_MUL          (ENABLE_MUL          ),
+		.ENABLE_FAST_MUL     (ENABLE_FAST_MUL     ),
+		.ENABLE_DIV          (ENABLE_DIV          ),
+		.ENABLE_IRQ          (ENABLE_IRQ          ),
+		.ENABLE_IRQ_QREGS    (ENABLE_IRQ_QREGS    ),
+		.ENABLE_IRQ_TIMER    (ENABLE_IRQ_TIMER    ),
+		.ENABLE_TRACE        (ENABLE_TRACE        ),
+		.REGS_INIT_ZERO      (REGS_INIT_ZERO      ),
+		.MASKED_IRQ          (MASKED_IRQ          ),
+		.LATCHED_IRQ         (LATCHED_IRQ         ),
+		.PROGADDR_RESET      (PROGADDR_RESET      ),
+		.PROGADDR_IRQ        (PROGADDR_IRQ        ),
+		.STACKADDR           (STACKADDR           )
+	) picorv32_core (
+		.clk      (clk   ),
+		.resetn   (resetn),
+		.trap     (trap  ),
+
+		.mem_valid(mem_valid),
+		.mem_addr (mem_addr ),
+		.mem_wdata(mem_wdata),
+		.mem_wstrb(mem_wstrb),
+		.mem_instr(mem_instr),
+		.mem_ready(mem_ready),
+		.mem_rdata(mem_rdata),
+
+		.pcpi_valid(pcpi_valid),
+		.pcpi_insn (pcpi_insn ),
+		.pcpi_rs1  (pcpi_rs1  ),
+		.pcpi_rs2  (pcpi_rs2  ),
+		.pcpi_wr   (pcpi_wr   ),
+		.pcpi_rd   (pcpi_rd   ),
+		.pcpi_wait (pcpi_wait ),
+		.pcpi_ready(pcpi_ready),
+
+		.irq(irq),
+		.eoi(eoi),
+
+`ifdef RISCV_FORMAL
+		.rvfi_valid    (rvfi_valid    ),
+		.rvfi_order    (rvfi_order    ),
+		.rvfi_insn     (rvfi_insn     ),
+		.rvfi_trap     (rvfi_trap     ),
+		.rvfi_halt     (rvfi_halt     ),
+		.rvfi_intr     (rvfi_intr     ),
+		.rvfi_rs1_addr (rvfi_rs1_addr ),
+		.rvfi_rs2_addr (rvfi_rs2_addr ),
+		.rvfi_rs1_rdata(rvfi_rs1_rdata),
+		.rvfi_rs2_rdata(rvfi_rs2_rdata),
+		.rvfi_rd_addr  (rvfi_rd_addr  ),
+		.rvfi_rd_wdata (rvfi_rd_wdata ),
+		.rvfi_pc_rdata (rvfi_pc_rdata ),
+		.rvfi_pc_wdata (rvfi_pc_wdata ),
+		.rvfi_mem_addr (rvfi_mem_addr ),
+		.rvfi_mem_rmask(rvfi_mem_rmask),
+		.rvfi_mem_wmask(rvfi_mem_wmask),
+		.rvfi_mem_rdata(rvfi_mem_rdata),
+		.rvfi_mem_wdata(rvfi_mem_wdata),
+`endif
+
+		.trace_valid(trace_valid),
+		.trace_data (trace_data)
+	);
+endmodule
+
+
+/***************************************************************
+ * picorv32_axi_adapter
+ ***************************************************************/
+
+module picorv32_axi_adapter (
+	input clk, resetn,
+
+	// AXI4-lite master memory interface
+
+	output        mem_axi_awvalid,
+	input         mem_axi_awready,
+	output [31:0] mem_axi_awaddr,
+	output [ 2:0] mem_axi_awprot,
+
+	output        mem_axi_wvalid,
+	input         mem_axi_wready,
+	output [31:0] mem_axi_wdata,
+	output [ 3:0] mem_axi_wstrb,
+
+	input         mem_axi_bvalid,
+	output        mem_axi_bready,
+
+	output        mem_axi_arvalid,
+	input         mem_axi_arready,
+	output [31:0] mem_axi_araddr,
+	output [ 2:0] mem_axi_arprot,
+
+	input         mem_axi_rvalid,
+	output        mem_axi_rready,
+	input  [31:0] mem_axi_rdata,
+
+	// Native PicoRV32 memory interface
+
+	input         mem_valid,
+	input         mem_instr,
+	output        mem_ready,
+	input  [31:0] mem_addr,
+	input  [31:0] mem_wdata,
+	input  [ 3:0] mem_wstrb,
+	output [31:0] mem_rdata
+);
+	reg ack_awvalid;
+	reg ack_arvalid;
+	reg ack_wvalid;
+	reg xfer_done;
+
+	assign mem_axi_awvalid = mem_valid && |mem_wstrb && !ack_awvalid;
+	assign mem_axi_awaddr = mem_addr;
+	assign mem_axi_awprot = 0;
+
+	assign mem_axi_arvalid = mem_valid && !mem_wstrb && !ack_arvalid;
+	assign mem_axi_araddr = mem_addr;
+	assign mem_axi_arprot = mem_instr ? 3'b100 : 3'b000;
+
+	assign mem_axi_wvalid = mem_valid && |mem_wstrb && !ack_wvalid;
+	assign mem_axi_wdata = mem_wdata;
+	assign mem_axi_wstrb = mem_wstrb;
+
+	assign mem_ready = mem_axi_bvalid || mem_axi_rvalid;
+	assign mem_axi_bready = mem_valid && |mem_wstrb;
+	assign mem_axi_rready = mem_valid && !mem_wstrb;
+	assign mem_rdata = mem_axi_rdata;
+
+	always @(posedge clk) begin
+		if (!resetn) begin
+			ack_awvalid <= 0;
+		end else begin
+			xfer_done <= mem_valid && mem_ready;
+			if (mem_axi_awready && mem_axi_awvalid)
+				ack_awvalid <= 1;
+			if (mem_axi_arready && mem_axi_arvalid)
+				ack_arvalid <= 1;
+			if (mem_axi_wready && mem_axi_wvalid)
+				ack_wvalid <= 1;
+			if (xfer_done || !mem_valid) begin
+				ack_awvalid <= 0;
+				ack_arvalid <= 0;
+				ack_wvalid <= 0;
+			end
+		end
+	end
+endmodule
+
+
+/***************************************************************
+ * picorv32_wb
+ ***************************************************************/
+
+module picorv32_wb #(
+	parameter [ 0:0] ENABLE_COUNTERS = 1,
+	parameter [ 0:0] ENABLE_COUNTERS64 = 1,
+	parameter [ 0:0] ENABLE_REGS_16_31 = 1,
+	parameter [ 0:0] ENABLE_REGS_DUALPORT = 1,
+	parameter [ 0:0] TWO_STAGE_SHIFT = 1,
+	parameter [ 0:0] BARREL_SHIFTER = 0,
+	parameter [ 0:0] TWO_CYCLE_COMPARE = 0,
+	parameter [ 0:0] TWO_CYCLE_ALU = 0,
+	parameter [ 0:0] COMPRESSED_ISA = 0,
+	parameter [ 0:0] CATCH_MISALIGN = 1,
+	parameter [ 0:0] CATCH_ILLINSN = 1,
+	parameter [ 0:0] ENABLE_PCPI = 0,
+	parameter [ 0:0] ENABLE_MUL = 0,
+	parameter [ 0:0] ENABLE_FAST_MUL = 0,
+	parameter [ 0:0] ENABLE_DIV = 0,
+	parameter [ 0:0] ENABLE_IRQ = 0,
+	parameter [ 0:0] ENABLE_IRQ_QREGS = 1,
+	parameter [ 0:0] ENABLE_IRQ_TIMER = 1,
+	parameter [ 0:0] ENABLE_TRACE = 0,
+	parameter [ 0:0] REGS_INIT_ZERO = 0,
+	parameter [31:0] MASKED_IRQ = 32'h 0000_0000,
+	parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff,
+	parameter [31:0] PROGADDR_RESET = 32'h 0000_0000,
+	parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010,
+	parameter [31:0] STACKADDR = 32'h ffff_ffff
+) (
+	output trap,
+
+	// Wishbone interfaces
+	input wb_rst_i,
+	input wb_clk_i,
+
+	output reg [31:0] wbm_adr_o,
+	output reg [31:0] wbm_dat_o,
+	input [31:0] wbm_dat_i,
+	output reg wbm_we_o,
+	output reg [3:0] wbm_sel_o,
+	output reg wbm_stb_o,
+	input wbm_ack_i,
+	output reg wbm_cyc_o,
+
+	// Pico Co-Processor Interface (PCPI)
+	output        pcpi_valid,
+	output [31:0] pcpi_insn,
+	output [31:0] pcpi_rs1,
+	output [31:0] pcpi_rs2,
+	input         pcpi_wr,
+	input  [31:0] pcpi_rd,
+	input         pcpi_wait,
+	input         pcpi_ready,
+
+	// IRQ interface
+	input  [31:0] irq,
+	output [31:0] eoi,
+
+`ifdef RISCV_FORMAL
+	output        rvfi_valid,
+	output [63:0] rvfi_order,
+	output [31:0] rvfi_insn,
+	output        rvfi_trap,
+	output        rvfi_halt,
+	output        rvfi_intr,
+	output [ 4:0] rvfi_rs1_addr,
+	output [ 4:0] rvfi_rs2_addr,
+	output [31:0] rvfi_rs1_rdata,
+	output [31:0] rvfi_rs2_rdata,
+	output [ 4:0] rvfi_rd_addr,
+	output [31:0] rvfi_rd_wdata,
+	output [31:0] rvfi_pc_rdata,
+	output [31:0] rvfi_pc_wdata,
+	output [31:0] rvfi_mem_addr,
+	output [ 3:0] rvfi_mem_rmask,
+	output [ 3:0] rvfi_mem_wmask,
+	output [31:0] rvfi_mem_rdata,
+	output [31:0] rvfi_mem_wdata,
+`endif
+
+	// Trace Interface
+	output        trace_valid,
+	output [35:0] trace_data,
+
+	output mem_instr
+);
+	wire        mem_valid;
+	wire [31:0] mem_addr;
+	wire [31:0] mem_wdata;
+	wire [ 3:0] mem_wstrb;
+	reg         mem_ready;
+	reg [31:0] mem_rdata;
+
+	wire clk;
+	wire resetn;
+
+	assign clk = wb_clk_i;
+	assign resetn = ~wb_rst_i;
+
+	picorv32 #(
+		.ENABLE_COUNTERS     (ENABLE_COUNTERS     ),
+		.ENABLE_COUNTERS64   (ENABLE_COUNTERS64   ),
+		.ENABLE_REGS_16_31   (ENABLE_REGS_16_31   ),
+		.ENABLE_REGS_DUALPORT(ENABLE_REGS_DUALPORT),
+		.TWO_STAGE_SHIFT     (TWO_STAGE_SHIFT     ),
+		.BARREL_SHIFTER      (BARREL_SHIFTER      ),
+		.TWO_CYCLE_COMPARE   (TWO_CYCLE_COMPARE   ),
+		.TWO_CYCLE_ALU       (TWO_CYCLE_ALU       ),
+		.COMPRESSED_ISA      (COMPRESSED_ISA      ),
+		.CATCH_MISALIGN      (CATCH_MISALIGN      ),
+		.CATCH_ILLINSN       (CATCH_ILLINSN       ),
+		.ENABLE_PCPI         (ENABLE_PCPI         ),
+		.ENABLE_MUL          (ENABLE_MUL          ),
+		.ENABLE_FAST_MUL     (ENABLE_FAST_MUL     ),
+		.ENABLE_DIV          (ENABLE_DIV          ),
+		.ENABLE_IRQ          (ENABLE_IRQ          ),
+		.ENABLE_IRQ_QREGS    (ENABLE_IRQ_QREGS    ),
+		.ENABLE_IRQ_TIMER    (ENABLE_IRQ_TIMER    ),
+		.ENABLE_TRACE        (ENABLE_TRACE        ),
+		.REGS_INIT_ZERO      (REGS_INIT_ZERO      ),
+		.MASKED_IRQ          (MASKED_IRQ          ),
+		.LATCHED_IRQ         (LATCHED_IRQ         ),
+		.PROGADDR_RESET      (PROGADDR_RESET      ),
+		.PROGADDR_IRQ        (PROGADDR_IRQ        ),
+		.STACKADDR           (STACKADDR           )
+	) picorv32_core (
+		.clk      (clk   ),
+		.resetn   (resetn),
+		.trap     (trap  ),
+
+		.mem_valid(mem_valid),
+		.mem_addr (mem_addr ),
+		.mem_wdata(mem_wdata),
+		.mem_wstrb(mem_wstrb),
+		.mem_instr(mem_instr),
+		.mem_ready(mem_ready),
+		.mem_rdata(mem_rdata),
+
+		.pcpi_valid(pcpi_valid),
+		.pcpi_insn (pcpi_insn ),
+		.pcpi_rs1  (pcpi_rs1  ),
+		.pcpi_rs2  (pcpi_rs2  ),
+		.pcpi_wr   (pcpi_wr   ),
+		.pcpi_rd   (pcpi_rd   ),
+		.pcpi_wait (pcpi_wait ),
+		.pcpi_ready(pcpi_ready),
+
+		.irq(irq),
+		.eoi(eoi),
+
+`ifdef RISCV_FORMAL
+		.rvfi_valid    (rvfi_valid    ),
+		.rvfi_order    (rvfi_order    ),
+		.rvfi_insn     (rvfi_insn     ),
+		.rvfi_trap     (rvfi_trap     ),
+		.rvfi_halt     (rvfi_halt     ),
+		.rvfi_intr     (rvfi_intr     ),
+		.rvfi_rs1_addr (rvfi_rs1_addr ),
+		.rvfi_rs2_addr (rvfi_rs2_addr ),
+		.rvfi_rs1_rdata(rvfi_rs1_rdata),
+		.rvfi_rs2_rdata(rvfi_rs2_rdata),
+		.rvfi_rd_addr  (rvfi_rd_addr  ),
+		.rvfi_rd_wdata (rvfi_rd_wdata ),
+		.rvfi_pc_rdata (rvfi_pc_rdata ),
+		.rvfi_pc_wdata (rvfi_pc_wdata ),
+		.rvfi_mem_addr (rvfi_mem_addr ),
+		.rvfi_mem_rmask(rvfi_mem_rmask),
+		.rvfi_mem_wmask(rvfi_mem_wmask),
+		.rvfi_mem_rdata(rvfi_mem_rdata),
+		.rvfi_mem_wdata(rvfi_mem_wdata),
+`endif
+
+		.trace_valid(trace_valid),
+		.trace_data (trace_data)
+	);
+
+	localparam IDLE = 2'b00;
+	localparam WBSTART = 2'b01;
+	localparam WBEND = 2'b10;
+
+	reg [1:0] state;
+
+	wire we;
+	assign we = (mem_wstrb[0] | mem_wstrb[1] | mem_wstrb[2] | mem_wstrb[3]);
+
+	always @(posedge wb_clk_i) begin
+		if (wb_rst_i) begin
+			wbm_adr_o <= 0;
+			wbm_dat_o <= 0;
+			wbm_we_o <= 0;
+			wbm_sel_o <= 0;
+			wbm_stb_o <= 0;
+			wbm_cyc_o <= 0;
+			state <= IDLE;
+		end else begin
+			case (state)
+				IDLE: begin
+					if (mem_valid) begin
+						wbm_adr_o <= mem_addr;
+						wbm_dat_o <= mem_wdata;
+						wbm_we_o <= we;
+						wbm_sel_o <= mem_wstrb;
+
+						wbm_stb_o <= 1'b1;
+						wbm_cyc_o <= 1'b1;
+						state <= WBSTART;
+					end else begin
+						mem_ready <= 1'b0;
+
+						wbm_stb_o <= 1'b0;
+						wbm_cyc_o <= 1'b0;
+						wbm_we_o <= 1'b0;
+					end
+				end
+				WBSTART:begin
+					if (wbm_ack_i) begin
+						mem_rdata <= wbm_dat_i;
+						mem_ready <= 1'b1;
+
+						state <= WBEND;
+
+						wbm_stb_o <= 1'b0;
+						wbm_cyc_o <= 1'b0;
+						wbm_we_o <= 1'b0;
+					end
+				end
+				WBEND: begin
+					mem_ready <= 1'b0;
+
+					state <= IDLE;
+				end
+				default:
+					state <= IDLE;
+			endcase
+		end
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/picosoc/.gitignore b/verilog/rtl/softshell/third_party/picorv32/picosoc/.gitignore
new file mode 100644
index 0000000..08067d3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/picosoc/.gitignore
@@ -0,0 +1,29 @@
+/spiflash_tb.vcd
+/spiflash_tb.vvp
+/hx8kdemo.asc
+/hx8kdemo.bin
+/hx8kdemo.blif
+/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/verilog/rtl/softshell/third_party/picorv32/picosoc/Makefile b/verilog/rtl/softshell/third_party/picorv32/picosoc/Makefile
new file mode 100644
index 0000000..f600062
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/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.blif: hx8kdemo.v spimemio.v simpleuart.v picosoc.v ../picorv32.v
+	yosys -ql hx8kdemo.log -p 'synth_ice40 -top hx8kdemo -blif hx8kdemo.blif' $^
+
+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`
+
+hx8kdemo_syn_tb.vvp: hx8kdemo_tb.v hx8kdemo_syn.v spiflash.v
+	iverilog -s testbench -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v`
+
+hx8kdemo_syn.v: hx8kdemo.blif
+	yosys -p 'read_blif -wideports hx8kdemo.blif; write_verilog hx8kdemo_syn.v'
+
+hx8kdemo.asc: hx8kdemo.pcf hx8kdemo.blif
+	arachne-pnr -d 8k -o hx8kdemo.asc -p hx8kdemo.pcf hx8kdemo.blif
+
+hx8kdemo.bin: hx8kdemo.asc
+	icetime -d hx8k -c 12 -mtr hx8kdemo.rpt hx8kdemo.asc
+	icepack hx8kdemo.asc hx8kdemo.bin
+
+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 -march=rv32imc -Wl,-Bstatic,-T,hx8kdemo_sections.lds,--strip-debug -ffreestanding -nostdlib -o hx8kdemo_fw.elf start.s firmware.c
+
+hx8kdemo_fw.hex: hx8kdemo_fw.elf
+	$(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 -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`
+
+icebreaker_syn_tb.vvp: icebreaker_tb.v icebreaker_syn.v spiflash.v
+	iverilog -s testbench -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v`
+
+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 --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 -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 firmware.hex
+	vvp -N $<
+
+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/verilog/rtl/softshell/third_party/picorv32/picosoc/README.md b/verilog/rtl/softshell/third_party/picorv32/picosoc/README.md
new file mode 100644
index 0000000..1708709
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/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/verilog/rtl/softshell/third_party/picorv32/picosoc/firmware.c b/verilog/rtl/softshell/third_party/picorv32/picosoc/firmware.c
new file mode 100644
index 0000000..425e036
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/picosoc/firmware.c
@@ -0,0 +1,770 @@
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#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/verilog/rtl/softshell/third_party/picorv32/picosoc/hx8kdemo.core b/verilog/rtl/softshell/third_party/picorv32/picosoc/hx8kdemo.core
new file mode 100644
index 0000000..97a1989
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/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/verilog/rtl/softshell/third_party/picorv32/picosoc/hx8kdemo.pcf b/verilog/rtl/softshell/third_party/picorv32/picosoc/hx8kdemo.pcf
new file mode 100644
index 0000000..418bae8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/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/verilog/rtl/softshell/third_party/picorv32/picosoc/hx8kdemo.v b/verilog/rtl/softshell/third_party/picorv32/picosoc/hx8kdemo.v
new file mode 100644
index 0000000..9b784f8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/picosoc/hx8kdemo.v
@@ -0,0 +1,139 @@
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+module hx8kdemo (
+	input clk,
+
+	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/verilog/rtl/softshell/third_party/picorv32/picosoc/hx8kdemo_tb.v b/verilog/rtl/softshell/third_party/picorv32/picosoc/hx8kdemo_tb.v
new file mode 100644
index 0000000..734f483
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/picosoc/hx8kdemo_tb.v
@@ -0,0 +1,108 @@
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`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/verilog/rtl/softshell/third_party/picorv32/picosoc/ice40up5k_spram.v b/verilog/rtl/softshell/third_party/picorv32/picosoc/ice40up5k_spram.v
new file mode 100644
index 0000000..6edb23b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/picosoc/ice40up5k_spram.v
@@ -0,0 +1,91 @@
+
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+module ice40up5k_spram #(
+	// We current always use the whole SPRAM (128 kB)
+	parameter integer WORDS = 32768
+) (
+	input clk,
+	input [3:0] wen,
+	input [21:0] addr,
+	input [31:0] wdata,
+	output [31:0] rdata
+);
+
+	wire cs_0, cs_1;
+	wire [31:0] rdata_0, rdata_1;
+
+	assign cs_0 = !addr[14];
+	assign cs_1 = addr[14];
+	assign rdata = addr[14] ? rdata_1 : rdata_0;
+
+	SB_SPRAM256KA ram00 (
+		.ADDRESS(addr[13:0]),
+		.DATAIN(wdata[15:0]),
+		.MASKWREN({wen[1], wen[1], wen[0], wen[0]}),
+		.WREN(wen[1]|wen[0]),
+		.CHIPSELECT(cs_0),
+		.CLOCK(clk),
+		.STANDBY(1'b0),
+		.SLEEP(1'b0),
+		.POWEROFF(1'b1),
+		.DATAOUT(rdata_0[15:0])
+	);
+
+	SB_SPRAM256KA ram01 (
+		.ADDRESS(addr[13:0]),
+		.DATAIN(wdata[31:16]),
+		.MASKWREN({wen[3], wen[3], wen[2], wen[2]}),
+		.WREN(wen[3]|wen[2]),
+		.CHIPSELECT(cs_0),
+		.CLOCK(clk),
+		.STANDBY(1'b0),
+		.SLEEP(1'b0),
+		.POWEROFF(1'b1),
+		.DATAOUT(rdata_0[31:16])
+	);
+
+	SB_SPRAM256KA ram10 (
+		.ADDRESS(addr[13:0]),
+		.DATAIN(wdata[15:0]),
+		.MASKWREN({wen[1], wen[1], wen[0], wen[0]}),
+		.WREN(wen[1]|wen[0]),
+		.CHIPSELECT(cs_1),
+		.CLOCK(clk),
+		.STANDBY(1'b0),
+		.SLEEP(1'b0),
+		.POWEROFF(1'b1),
+		.DATAOUT(rdata_1[15:0])
+	);
+
+	SB_SPRAM256KA ram11 (
+		.ADDRESS(addr[13:0]),
+		.DATAIN(wdata[31:16]),
+		.MASKWREN({wen[3], wen[3], wen[2], wen[2]}),
+		.WREN(wen[3]|wen[2]),
+		.CHIPSELECT(cs_1),
+		.CLOCK(clk),
+		.STANDBY(1'b0),
+		.SLEEP(1'b0),
+		.POWEROFF(1'b1),
+		.DATAOUT(rdata_1[31:16])
+	);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/picosoc/icebreaker.core b/verilog/rtl/softshell/third_party/picorv32/picosoc/icebreaker.core
new file mode 100644
index 0000000..5af5fd6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/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/verilog/rtl/softshell/third_party/picorv32/picosoc/icebreaker.pcf b/verilog/rtl/softshell/third_party/picorv32/picosoc/icebreaker.pcf
new file mode 100644
index 0000000..86cf78e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/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/verilog/rtl/softshell/third_party/picorv32/picosoc/icebreaker.v b/verilog/rtl/softshell/third_party/picorv32/picosoc/icebreaker.v
new file mode 100644
index 0000000..0b401db
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/picosoc/icebreaker.v
@@ -0,0 +1,149 @@
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`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_MULDIV(0),
+		.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/verilog/rtl/softshell/third_party/picorv32/picosoc/icebreaker_tb.v b/verilog/rtl/softshell/third_party/picorv32/picosoc/icebreaker_tb.v
new file mode 100644
index 0000000..209d165
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/picosoc/icebreaker_tb.v
@@ -0,0 +1,122 @@
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`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/verilog/rtl/softshell/third_party/picorv32/picosoc/overview.svg b/verilog/rtl/softshell/third_party/picorv32/picosoc/overview.svg
new file mode 100644
index 0000000..2335f76
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/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/verilog/rtl/softshell/third_party/picorv32/picosoc/performance.png b/verilog/rtl/softshell/third_party/picorv32/picosoc/performance.png
new file mode 100644
index 0000000..aac75b2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/picosoc/performance.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/picorv32/picosoc/performance.py b/verilog/rtl/softshell/third_party/picorv32/picosoc/performance.py
new file mode 100644
index 0000000..92c50c5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/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/verilog/rtl/softshell/third_party/picorv32/picosoc/picosoc.core b/verilog/rtl/softshell/third_party/picorv32/picosoc/picosoc.core
new file mode 100644
index 0000000..eb0988a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/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/verilog/rtl/softshell/third_party/picorv32/picosoc/picosoc.v b/verilog/rtl/softshell/third_party/picorv32/picosoc/picosoc.v
new file mode 100644
index 0000000..9c5981e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/picosoc/picosoc.v
@@ -0,0 +1,259 @@
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`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_MULDIV = 1;
+	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_MULDIV),
+		.ENABLE_DIV(ENABLE_MULDIV),
+		.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/verilog/rtl/softshell/third_party/picorv32/picosoc/sections.lds b/verilog/rtl/softshell/third_party/picorv32/picosoc/sections.lds
new file mode 100644
index 0000000..f38d813
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/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/verilog/rtl/softshell/third_party/picorv32/picosoc/simpleuart.v b/verilog/rtl/softshell/third_party/picorv32/picosoc/simpleuart.v
new file mode 100644
index 0000000..1efddef
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/picosoc/simpleuart.v
@@ -0,0 +1,137 @@
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+module 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/verilog/rtl/softshell/third_party/picorv32/picosoc/spiflash.core b/verilog/rtl/softshell/third_party/picorv32/picosoc/spiflash.core
new file mode 100644
index 0000000..1b7d153
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/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/verilog/rtl/softshell/third_party/picorv32/picosoc/spiflash.v b/verilog/rtl/softshell/third_party/picorv32/picosoc/spiflash.v
new file mode 100644
index 0000000..298219d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/picosoc/spiflash.v
@@ -0,0 +1,409 @@
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`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/verilog/rtl/softshell/third_party/picorv32/picosoc/spiflash_tb.v b/verilog/rtl/softshell/third_party/picorv32/picosoc/spiflash_tb.v
new file mode 100644
index 0000000..f300373
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/picosoc/spiflash_tb.v
@@ -0,0 +1,366 @@
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`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/verilog/rtl/softshell/third_party/picorv32/picosoc/spimemio.v b/verilog/rtl/softshell/third_party/picorv32/picosoc/spimemio.v
new file mode 100644
index 0000000..0bbf532
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/picosoc/spimemio.v
@@ -0,0 +1,579 @@
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+module 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/verilog/rtl/softshell/third_party/picorv32/picosoc/start.s b/verilog/rtl/softshell/third_party/picorv32/picosoc/start.s
new file mode 100644
index 0000000..e9e18db
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/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:
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/.gitignore b/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/.gitignore
new file mode 100644
index 0000000..efd00f7
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/.gitignore
@@ -0,0 +1,13 @@
+obj_dir
+riscv-fesvr
+riscv-isa-sim
+output_ref.txt
+output_sim.txt
+platform.info
+test.c
+test.ld
+test.elf
+test_ref
+test.hex
+testbench.vvp
+testbench.vcd
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/Makefile b/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/Makefile
new file mode 100644
index 0000000..fd5107f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/Makefile
@@ -0,0 +1,85 @@
+RISCV_TOOLS_DIR = /opt/riscv32imc
+RISCV_TOOLS_PREFIX = $(RISCV_TOOLS_DIR)/bin/riscv32-unknown-elf-
+CSMITH_INCDIR = $(shell ls -d /usr/local/include/csmith-* | head -n1)
+CC = $(RISCV_TOOLS_PREFIX)gcc
+SHELL = /bin/bash
+
+help:
+	@echo "Usage: make { loop | verilator | iverilog | spike }"
+
+loop: riscv-fesvr/build.ok riscv-isa-sim/build.ok obj_dir/Vtestbench
+	+set -e; x() { echo "$$*" >&2; "$$@"; }; i=1; j=1; while true; do echo; echo; \
+		echo "---------------- $$((i++)) ($$j) ----------------"; \
+		x rm -f test.hex test.elf test.c test_ref test.ld output_ref.txt output_sim.txt; \
+		x make spike test.hex || { echo SKIP; continue; }; x rm -f output_sim.txt; \
+		x obj_dir/Vtestbench | grep -v '$$finish' > output_sim.txt; \
+		x diff -u output_ref.txt output_sim.txt; echo OK; ! ((j++)); \
+	done
+
+verilator: test_ref test.hex obj_dir/Vtestbench
+	timeout 2 ./test_ref > output_ref.txt && cat output_ref.txt
+	obj_dir/Vtestbench | grep -v '$$finish' > output_sim.txt
+	diff -u output_ref.txt output_sim.txt
+
+iverilog: test_ref test.hex testbench.vvp
+	timeout 2 ./test_ref > output_ref.txt && cat output_ref.txt
+	vvp -N testbench.vvp > output_sim.txt
+	diff -u output_ref.txt output_sim.txt
+
+spike: riscv-fesvr/build.ok riscv-isa-sim/build.ok test_ref test.elf
+	timeout 2 ./test_ref > output_ref.txt && cat output_ref.txt
+	LD_LIBRARY_PATH="./riscv-isa-sim:./riscv-fesvr" ./riscv-isa-sim/spike test.elf > output_sim.txt
+	diff -u output_ref.txt output_sim.txt
+
+riscv-fesvr/build.ok:
+	rm -rf riscv-fesvr
+	git clone https://github.com/riscv/riscv-fesvr.git riscv-fesvr
+	+cd riscv-fesvr && git checkout 1c02bd6 && ./configure && make && touch build.ok
+
+riscv-isa-sim/build.ok: riscv-fesvr/build.ok
+	rm -rf riscv-isa-sim
+	git clone https://github.com/riscv/riscv-isa-sim.git riscv-isa-sim
+	cd riscv-isa-sim && git checkout 10ae74e
+	cd riscv-isa-sim && patch -p1 < ../riscv-isa-sim.diff
+	cd riscv-isa-sim && LDFLAGS="-L../riscv-fesvr" ./configure --with-isa=RV32IMC
+	+cd riscv-isa-sim && ln -s ../riscv-fesvr/fesvr . && make && touch build.ok
+
+testbench.vvp: testbench.v ../../picorv32.v
+	iverilog -o testbench.vvp testbench.v ../../picorv32.v
+	chmod -x testbench.vvp
+
+obj_dir/Vtestbench: testbench.v testbench.cc ../../picorv32.v
+	verilator --exe -Wno-fatal --cc --top-module testbench testbench.v ../../picorv32.v testbench.cc
+	$(MAKE) -C obj_dir -f Vtestbench.mk
+
+test.hex: test.elf
+	$(RISCV_TOOLS_PREFIX)objcopy -O verilog test.elf test.hex
+
+start.elf: start.S start.ld
+	$(CC) -nostdlib -o start.elf start.S -T start.ld
+	chmod -x start.elf
+
+test_ref: test.c
+	gcc -m32 -o test_ref -w -Os -I $(CSMITH_INCDIR) test.c
+
+test.elf: test.c syscalls.c start.S
+	sed -e '/SECTIONS/,+1 s/{/{ . = 0x00000000; .start : { *(.text.start) } application_entry_point = 0x00010000;/;' \
+		$(RISCV_TOOLS_DIR)/riscv32-unknown-elf/lib/riscv.ld > test.ld
+	$(CC) -o test.elf -w -Os -I $(CSMITH_INCDIR) -T test.ld test.c syscalls.c start.S
+	chmod -x test.elf
+
+test.c:
+	echo "integer size = 4" > platform.info
+	echo "pointer size = 4" >> platform.info
+	csmith --no-packed-struct -o test.c
+	gawk '/Seed:/ {print$$2,$$3;}' test.c
+
+clean:
+	rm -rf platform.info test.c test.ld test.elf test.hex test_ref obj_dir
+	rm -rf testbench.vvp testbench.vcd output_ref.txt output_sim.txt
+
+mrproper: clean
+	rm -rf riscv-fesvr riscv-isa-sim
+
+.PHONY: help loop verilator iverilog spike clean mrproper
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/riscv-isa-sim.diff b/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/riscv-isa-sim.diff
new file mode 100644
index 0000000..fd22280
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/riscv-isa-sim.diff
@@ -0,0 +1,62 @@
+diff --git a/riscv/execute.cc b/riscv/execute.cc
+index 5c3fdf7..4d914b3 100644
+--- a/riscv/execute.cc
++++ b/riscv/execute.cc
+@@ -124,6 +124,10 @@ miss:
+     }
+ 
+     state.minstret += instret;
++    if (state.minstret > 1000000) {
++        printf("Reached limit of 1000000 instructions.\n");
++	exit(0);
++    }
+     n -= instret;
+   }
+ }
+diff --git a/riscv/insns/c_ebreak.h b/riscv/insns/c_ebreak.h
+index a17200f..f06d8d9 100644
+--- a/riscv/insns/c_ebreak.h
++++ b/riscv/insns/c_ebreak.h
+@@ -1,2 +1,4 @@
+ require_extension('C');
++
++exit(0);
+ throw trap_breakpoint();
+diff --git a/riscv/insns/sbreak.h b/riscv/insns/sbreak.h
+index c22776c..d38bd22 100644
+--- a/riscv/insns/sbreak.h
++++ b/riscv/insns/sbreak.h
+@@ -1 +1,2 @@
++exit(0);
+ throw trap_breakpoint();
+diff --git a/riscv/mmu.h b/riscv/mmu.h
+index b9948c5..bee1f8b 100644
+--- a/riscv/mmu.h
++++ b/riscv/mmu.h
+@@ -67,7 +67,8 @@ public:
+       if (addr & (sizeof(type##_t)-1)) \
+         throw trap_store_address_misaligned(addr); \
+       reg_t vpn = addr >> PGSHIFT; \
+-      if (likely(tlb_store_tag[vpn % TLB_ENTRIES] == vpn)) \
++      if (addr == 0x10000000) putchar(val), fflush(stdout); \
++      else if (likely(tlb_store_tag[vpn % TLB_ENTRIES] == vpn)) \
+         *(type##_t*)(tlb_data[vpn % TLB_ENTRIES] + addr) = val; \
+       else \
+         store_slow_path(addr, sizeof(type##_t), (const uint8_t*)&val); \
+diff --git a/riscv/processor.cc b/riscv/processor.cc
+index 3b834c5..f407543 100644
+--- a/riscv/processor.cc
++++ b/riscv/processor.cc
+@@ -201,9 +201,9 @@ void processor_t::set_privilege(reg_t prv)
+ 
+ void processor_t::take_trap(trap_t& t, reg_t epc)
+ {
+-  if (debug)
+-    fprintf(stderr, "core %3d: exception %s, epc 0x%016" PRIx64 "\n",
+-            id, t.name(), epc);
++  printf("core %3d: exception %s, epc 0x%016" PRIx64 "\n",
++         id, t.name(), epc);
++  exit(0);
+ 
+   // by default, trap to M-mode, unless delegated to S-mode
+   reg_t bit = t.cause();
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/start.S b/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/start.S
new file mode 100644
index 0000000..d8f110e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/start.S
@@ -0,0 +1,51 @@
+.section .text.start
+.global application_entry_point
+
+/* zero-initialize all registers */
+addi x1, zero, 0
+addi x2, zero, 0
+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
+
+/* set stack pointer */
+lui sp, %hi(4*1024*1024)
+addi sp, sp, %lo(4*1024*1024)
+
+/* push zeros on the stack for argc and argv */
+/* (stack is aligned to 16 bytes in riscv calling convention) */
+addi sp,sp,-16
+sw zero,0(sp)
+sw zero,4(sp)
+sw zero,8(sp)
+sw zero,12(sp)
+
+/* jump to libc init */
+j application_entry_point
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/syscalls.c b/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/syscalls.c
new file mode 100644
index 0000000..8ea84ca
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/syscalls.c
@@ -0,0 +1,95 @@
+// An extremely minimalist syscalls.c for newlib
+// Based on riscv newlib libgloss/riscv/sys_*.c
+// Written by Clifford Wolf.
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define UNIMPL_FUNC(_f) ".globl " #_f "\n.type " #_f ", @function\n" #_f ":\n"
+
+asm (
+	".text\n"
+	".align 2\n"
+	UNIMPL_FUNC(_open)
+	UNIMPL_FUNC(_openat)
+	UNIMPL_FUNC(_lseek)
+	UNIMPL_FUNC(_stat)
+	UNIMPL_FUNC(_lstat)
+	UNIMPL_FUNC(_fstatat)
+	UNIMPL_FUNC(_isatty)
+	UNIMPL_FUNC(_access)
+	UNIMPL_FUNC(_faccessat)
+	UNIMPL_FUNC(_link)
+	UNIMPL_FUNC(_unlink)
+	UNIMPL_FUNC(_execve)
+	UNIMPL_FUNC(_getpid)
+	UNIMPL_FUNC(_fork)
+	UNIMPL_FUNC(_kill)
+	UNIMPL_FUNC(_wait)
+	UNIMPL_FUNC(_times)
+	UNIMPL_FUNC(_gettimeofday)
+	UNIMPL_FUNC(_ftime)
+	UNIMPL_FUNC(_utime)
+	UNIMPL_FUNC(_chown)
+	UNIMPL_FUNC(_chmod)
+	UNIMPL_FUNC(_chdir)
+	UNIMPL_FUNC(_getcwd)
+	UNIMPL_FUNC(_sysconf)
+	"j unimplemented_syscall\n"
+);
+
+void unimplemented_syscall()
+{
+	const char *p = "Unimplemented system call called!\n";
+	while (*p)
+		*(volatile int*)0x10000000 = *(p++);
+	asm volatile ("ebreak");
+	__builtin_unreachable();
+}
+
+ssize_t _read(int file, void *ptr, size_t len)
+{
+	// always EOF
+	return 0;
+}
+
+ssize_t _write(int file, const void *ptr, size_t len)
+{
+	const void *eptr = ptr + len;
+	while (ptr != eptr)
+		*(volatile int*)0x10000000 = *(char*)(ptr++);
+	return len;
+}
+
+int _close(int file)
+{
+	// close is called before _exit()
+	return 0;
+}
+
+int _fstat(int file, struct stat *st)
+{
+	// fstat is called during libc startup
+	errno = ENOENT;
+	return -1;
+}
+
+void *_sbrk(ptrdiff_t incr)
+{
+	extern unsigned char _end[];   // Defined by linker
+	static unsigned long heap_end;
+
+	if (heap_end == 0)
+		heap_end = (long)_end;
+
+	heap_end += incr;
+	return (void *)(heap_end - incr);
+}
+
+void _exit(int exit_status)
+{
+	asm volatile ("ebreak");
+	__builtin_unreachable();
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/testbench.cc b/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/testbench.cc
new file mode 100644
index 0000000..2925d0b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/testbench.cc
@@ -0,0 +1,18 @@
+#include "Vtestbench.h"
+#include "verilated.h"
+
+int main(int argc, char **argv, char **env)
+{
+	Verilated::commandArgs(argc, argv);
+	Vtestbench* top = new Vtestbench;
+
+	top->clk = 0;
+	while (!Verilated::gotFinish()) {
+		top->clk = !top->clk;
+		top->eval();
+	}
+
+	delete top;
+	exit(0);
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/testbench.v b/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/testbench.v
new file mode 100644
index 0000000..9d9d8f6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/csmith/testbench.v
@@ -0,0 +1,100 @@
+`timescale 1 ns / 1 ps
+
+module testbench (
+`ifdef VERILATOR
+	input clk
+`endif
+);
+`ifndef VERILATOR
+	reg clk = 1;
+	always #5 clk = ~clk;
+`endif
+
+	reg resetn = 0;
+	integer resetn_cnt = 0;
+	wire trap;
+
+	initial begin
+		// $dumpfile("testbench.vcd");
+		// $dumpvars(0, testbench);
+	end
+
+	always @(posedge clk) begin
+		if (resetn_cnt < 100)
+			resetn_cnt <= resetn_cnt + 1;
+		else
+			resetn <= 1;
+	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;
+
+	reg [31:0] x32 = 314159265;
+	reg [31:0] next_x32;
+
+	always @(posedge clk) begin
+		if (resetn) begin
+			next_x32 = x32;
+			next_x32 = next_x32 ^ (next_x32 << 13);
+			next_x32 = next_x32 ^ (next_x32 >> 17);
+			next_x32 = next_x32 ^ (next_x32 << 5);
+			x32 <= next_x32;
+		end
+	end
+
+	picorv32 #(
+		.COMPRESSED_ISA(1),
+		.ENABLE_MUL(1),
+		.ENABLE_DIV(1)
+	) uut (
+		.clk         (clk        ),
+		.resetn      (resetn     ),
+		.trap        (trap       ),
+		.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  )
+	);
+
+	reg [7:0] memory [0:4*1024*1024-1];
+	initial $readmemh("test.hex", memory);
+
+	assign mem_ready = x32[0] && mem_valid;
+
+	assign mem_rdata[ 7: 0] = memory[mem_addr + 0];
+	assign mem_rdata[15: 8] = memory[mem_addr + 1];
+	assign mem_rdata[23:16] = memory[mem_addr + 2];
+	assign mem_rdata[31:24] = memory[mem_addr + 3];
+
+	always @(posedge clk) begin
+		if (mem_valid && mem_ready) begin
+			if (mem_wstrb && mem_addr == 'h10000000) begin
+				$write("%c", mem_wdata[ 7: 0]);
+`ifndef VERILATOR
+				$fflush;
+`endif
+			end else begin
+				if (mem_wstrb[0]) memory[mem_addr + 0] <= mem_wdata[ 7: 0];
+				if (mem_wstrb[1]) memory[mem_addr + 1] <= mem_wdata[15: 8];
+				if (mem_wstrb[2]) memory[mem_addr + 2] <= mem_wdata[23:16];
+				if (mem_wstrb[3]) memory[mem_addr + 3] <= mem_wdata[31:24];
+			end
+		end
+	end
+
+	always @(posedge clk) begin
+		if (resetn && trap) begin
+			// repeat (10) @(posedge clk);
+			// $display("TRAP");
+			$finish;
+		end
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/.gitignore b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/.gitignore
new file mode 100644
index 0000000..47e6b5c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/.gitignore
@@ -0,0 +1,9 @@
+firmware.d
+firmware.elf
+firmware.hex
+firmware32.hex
+firmware.o
+syscalls.o
+testbench.vvp
+testbench.vcd
+start.elf
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/Makefile b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/Makefile
new file mode 100644
index 0000000..2d95019
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/Makefile
@@ -0,0 +1,38 @@
+RISCV_TOOLS_PREFIX = /opt/riscv32ic/bin/riscv32-unknown-elf-
+CXX = $(RISCV_TOOLS_PREFIX)g++
+CC = $(RISCV_TOOLS_PREFIX)gcc
+AS = $(RISCV_TOOLS_PREFIX)gcc
+CXXFLAGS = -MD -Os -Wall -std=c++11
+CCFLAGS = -MD -Os -Wall -std=c++11
+LDFLAGS = -Wl,--gc-sections
+LDLIBS = -lstdc++
+
+test: testbench.vvp firmware32.hex
+	vvp -N testbench.vvp
+
+testbench.vvp: testbench.v ../../picorv32.v
+	iverilog -o testbench.vvp testbench.v ../../picorv32.v
+	chmod -x testbench.vvp
+
+firmware32.hex: firmware.elf start.elf hex8tohex32.py
+	$(RISCV_TOOLS_PREFIX)objcopy -O verilog start.elf start.tmp
+	$(RISCV_TOOLS_PREFIX)objcopy -O verilog firmware.elf firmware.tmp
+	cat start.tmp firmware.tmp > firmware.hex
+	python3 hex8tohex32.py firmware.hex > firmware32.hex
+	rm -f start.tmp firmware.tmp
+
+firmware.elf: firmware.o syscalls.o
+	$(CC) $(LDFLAGS) -o $@ $^ -T ../../firmware/riscv.ld $(LDLIBS)
+	chmod -x firmware.elf
+
+start.elf: start.S start.ld
+	$(CC) -nostdlib -o start.elf start.S -T start.ld $(LDLIBS)
+	chmod -x start.elf
+
+clean:
+	rm -f *.o *.d *.tmp start.elf
+	rm -f firmware.elf firmware.hex firmware32.hex
+	rm -f testbench.vvp testbench.vcd
+
+-include *.d
+.PHONY: test clean
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/firmware.cc b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/firmware.cc
new file mode 100644
index 0000000..638c0dd
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/firmware.cc
@@ -0,0 +1,87 @@
+#include <stdio.h>
+#include <iostream>
+#include <vector>
+#include <algorithm>
+
+class ExampleBaseClass
+{
+public:
+	ExampleBaseClass() {
+		std::cout << "ExampleBaseClass()" << std::endl;
+	}
+
+	virtual ~ExampleBaseClass() {
+		std::cout << "~ExampleBaseClass()" << std::endl;
+	}
+
+	virtual void print_something_virt() {
+		std::cout << "ExampleBaseClass::print_something_virt()" << std::endl;
+	}
+
+	void print_something_novirt() {
+		std::cout << "ExampleBaseClass::print_something_novirt()" << std::endl;
+	}
+};
+
+class ExampleSubClass : public ExampleBaseClass
+{
+public:
+	ExampleSubClass() {
+		std::cout << "ExampleSubClass()" << std::endl;
+	}
+
+	virtual ~ExampleSubClass() {
+		std::cout << "~ExampleSubClass()" << std::endl;
+	}
+
+	virtual void print_something_virt() {
+		std::cout << "ExampleSubClass::print_something_virt()" << std::endl;
+	}
+
+	void print_something_novirt() {
+		std::cout << "ExampleSubClass::print_something_novirt()" << std::endl;
+	}
+};
+
+int main()
+{
+	printf("Hello World, C!\n");
+
+	std::cout << "Hello World, C++!" << std::endl;
+
+	ExampleBaseClass *obj = new ExampleBaseClass;
+	obj->print_something_virt();
+	obj->print_something_novirt();
+	delete obj;
+
+	obj = new ExampleSubClass;
+	obj->print_something_virt();
+	obj->print_something_novirt();
+	delete obj;
+
+	std::vector<unsigned int> some_ints;
+	some_ints.push_back(0x48c9b3e4);
+	some_ints.push_back(0x79109b6a);
+	some_ints.push_back(0x16155039);
+	some_ints.push_back(0xa3635c9a);
+	some_ints.push_back(0x8d2f4702);
+	some_ints.push_back(0x38d232ae);
+	some_ints.push_back(0x93924a17);
+	some_ints.push_back(0x62b895cc);
+	some_ints.push_back(0x6130d459);
+	some_ints.push_back(0x837c8b44);
+	some_ints.push_back(0x3d59b4fe);
+	some_ints.push_back(0x444914d8);
+	some_ints.push_back(0x3a3dc660);
+	some_ints.push_back(0xe5a121ef);
+	some_ints.push_back(0xff00866d);
+	some_ints.push_back(0xb843b879);
+
+	std::sort(some_ints.begin(), some_ints.end());
+
+	for (auto n : some_ints)
+		std::cout << std::hex << n << std::endl;
+
+	std::cout << "All done." << std::endl;
+	return 0;
+}
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/hex8tohex32.py b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/hex8tohex32.py
new file mode 100644
index 0000000..ae44101
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/hex8tohex32.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+
+import fileinput
+import itertools
+
+ptr = 0
+data = []
+
+def write_data():
+    if len(data) != 0:
+        print("@%08x" % (ptr >> 2))
+        while len(data) % 4 != 0:
+            data.append(0)
+        for word_bytes in zip(*([iter(data)]*4)):
+            print("".join(["%02x" % b for b in reversed(word_bytes)]))
+
+for line in fileinput.input():
+    if line.startswith("@"):
+        addr = int(line[1:], 16)
+        if addr > ptr+4:
+            write_data()
+            ptr = addr
+            data = []
+            while ptr % 4 != 0:
+                data.append(0)
+                ptr -= 1
+        else:
+            while ptr + len(data) < addr:
+                data.append(0)
+    else:
+        data += [int(tok, 16) for tok in line.split()]
+
+write_data()
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/start.S b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/start.S
new file mode 100644
index 0000000..f872a14
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/start.S
@@ -0,0 +1,52 @@
+.section .text
+.global _ftext
+.global _pvstart
+
+_pvstart:
+/* zero-initialize all registers */
+addi x1, zero, 0
+addi x2, zero, 0
+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
+
+/* set stack pointer */
+lui sp, %hi(4*1024*1024)
+addi sp, sp, %lo(4*1024*1024)
+
+/* push zeros on the stack for argc and argv */
+/* (stack is aligned to 16 bytes in riscv calling convention) */
+addi sp,sp,-16
+sw zero,0(sp)
+sw zero,4(sp)
+sw zero,8(sp)
+sw zero,12(sp)
+
+/* jump to libc init */
+j _ftext
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/start.ld b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/start.ld
new file mode 100644
index 0000000..773eee2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/start.ld
@@ -0,0 +1,5 @@
+SECTIONS {
+. = 0x00000000;
+.text : { *(.text) }
+_ftext = 0x00010000;
+}
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/syscalls.c b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/syscalls.c
new file mode 100644
index 0000000..8ea84ca
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/syscalls.c
@@ -0,0 +1,95 @@
+// An extremely minimalist syscalls.c for newlib
+// Based on riscv newlib libgloss/riscv/sys_*.c
+// Written by Clifford Wolf.
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define UNIMPL_FUNC(_f) ".globl " #_f "\n.type " #_f ", @function\n" #_f ":\n"
+
+asm (
+	".text\n"
+	".align 2\n"
+	UNIMPL_FUNC(_open)
+	UNIMPL_FUNC(_openat)
+	UNIMPL_FUNC(_lseek)
+	UNIMPL_FUNC(_stat)
+	UNIMPL_FUNC(_lstat)
+	UNIMPL_FUNC(_fstatat)
+	UNIMPL_FUNC(_isatty)
+	UNIMPL_FUNC(_access)
+	UNIMPL_FUNC(_faccessat)
+	UNIMPL_FUNC(_link)
+	UNIMPL_FUNC(_unlink)
+	UNIMPL_FUNC(_execve)
+	UNIMPL_FUNC(_getpid)
+	UNIMPL_FUNC(_fork)
+	UNIMPL_FUNC(_kill)
+	UNIMPL_FUNC(_wait)
+	UNIMPL_FUNC(_times)
+	UNIMPL_FUNC(_gettimeofday)
+	UNIMPL_FUNC(_ftime)
+	UNIMPL_FUNC(_utime)
+	UNIMPL_FUNC(_chown)
+	UNIMPL_FUNC(_chmod)
+	UNIMPL_FUNC(_chdir)
+	UNIMPL_FUNC(_getcwd)
+	UNIMPL_FUNC(_sysconf)
+	"j unimplemented_syscall\n"
+);
+
+void unimplemented_syscall()
+{
+	const char *p = "Unimplemented system call called!\n";
+	while (*p)
+		*(volatile int*)0x10000000 = *(p++);
+	asm volatile ("ebreak");
+	__builtin_unreachable();
+}
+
+ssize_t _read(int file, void *ptr, size_t len)
+{
+	// always EOF
+	return 0;
+}
+
+ssize_t _write(int file, const void *ptr, size_t len)
+{
+	const void *eptr = ptr + len;
+	while (ptr != eptr)
+		*(volatile int*)0x10000000 = *(char*)(ptr++);
+	return len;
+}
+
+int _close(int file)
+{
+	// close is called before _exit()
+	return 0;
+}
+
+int _fstat(int file, struct stat *st)
+{
+	// fstat is called during libc startup
+	errno = ENOENT;
+	return -1;
+}
+
+void *_sbrk(ptrdiff_t incr)
+{
+	extern unsigned char _end[];   // Defined by linker
+	static unsigned long heap_end;
+
+	if (heap_end == 0)
+		heap_end = (long)_end;
+
+	heap_end += incr;
+	return (void *)(heap_end - incr);
+}
+
+void _exit(int exit_status)
+{
+	asm volatile ("ebreak");
+	__builtin_unreachable();
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/testbench.v b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/testbench.v
new file mode 100644
index 0000000..ac9af70
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/cxxdemo/testbench.v
@@ -0,0 +1,114 @@
+`timescale 1 ns / 1 ps
+`undef VERBOSE_MEM
+`undef WRITE_VCD
+`undef MEM8BIT
+
+module testbench;
+	reg clk = 1;
+	reg resetn = 0;
+	wire trap;
+
+	always #5 clk = ~clk;
+
+	initial begin
+		repeat (100) @(posedge clk);
+		resetn <= 1;
+	end
+
+	wire mem_valid;
+	wire mem_instr;
+	reg mem_ready;
+	wire [31:0] mem_addr;
+	wire [31:0] mem_wdata;
+	wire [3:0] mem_wstrb;
+	reg  [31:0] mem_rdata;
+
+	picorv32 #(
+		.COMPRESSED_ISA(1)
+	) uut (
+		.clk         (clk        ),
+		.resetn      (resetn     ),
+		.trap        (trap       ),
+		.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  )
+	);
+
+	localparam MEM_SIZE = 4*1024*1024;
+`ifdef MEM8BIT
+	reg [7:0] memory [0:MEM_SIZE-1];
+	initial $readmemh("firmware.hex", memory);
+`else
+	reg [31:0] memory [0:MEM_SIZE/4-1];
+	initial $readmemh("firmware32.hex", memory);
+`endif
+
+	always @(posedge clk) begin
+		mem_ready <= 0;
+		if (mem_valid && !mem_ready) begin
+			mem_ready <= 1;
+			mem_rdata <= 'bx;
+			case (1)
+				mem_addr < MEM_SIZE: begin
+`ifdef MEM8BIT
+					if (|mem_wstrb) begin
+						if (mem_wstrb[0]) memory[mem_addr + 0] <= mem_wdata[ 7: 0];
+						if (mem_wstrb[1]) memory[mem_addr + 1] <= mem_wdata[15: 8];
+						if (mem_wstrb[2]) memory[mem_addr + 2] <= mem_wdata[23:16];
+						if (mem_wstrb[3]) memory[mem_addr + 3] <= mem_wdata[31:24];
+					end else begin
+						mem_rdata <= {memory[mem_addr+3], memory[mem_addr+2], memory[mem_addr+1], memory[mem_addr]};
+					end
+`else
+					if (|mem_wstrb) begin
+						if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
+						if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
+						if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16];
+						if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24];
+					end else begin
+						mem_rdata <= memory[mem_addr >> 2];
+					end
+`endif
+				end
+				mem_addr == 32'h 1000_0000: begin
+					$write("%c", mem_wdata[7:0]);
+				end
+			endcase
+		end
+		if (mem_valid && mem_ready) begin
+`ifdef VERBOSE_MEM
+			if (|mem_wstrb)
+				$display("WR: ADDR=%x DATA=%x MASK=%b", mem_addr, mem_wdata, mem_wstrb);
+			else
+				$display("RD: ADDR=%x DATA=%x%s", mem_addr, mem_rdata, mem_instr ? " INSN" : "");
+`endif
+			if (^mem_addr === 1'bx ||
+					(mem_wstrb[0] && ^mem_wdata[ 7: 0] == 1'bx) ||
+					(mem_wstrb[1] && ^mem_wdata[15: 8] == 1'bx) ||
+					(mem_wstrb[2] && ^mem_wdata[23:16] == 1'bx) ||
+					(mem_wstrb[3] && ^mem_wdata[31:24] == 1'bx)) begin
+				$display("CRITICAL UNDEF MEM TRANSACTION");
+				$finish;
+			end
+		end
+	end
+
+`ifdef WRITE_VCD
+	initial begin
+		$dumpfile("testbench.vcd");
+		$dumpvars(0, testbench);
+	end
+`endif
+
+	always @(posedge clk) begin
+		if (resetn && trap) begin
+			repeat (10) @(posedge clk);
+			$display("TRAP");
+			$finish;
+		end
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/.gitignore b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/.gitignore
new file mode 100644
index 0000000..9502e6b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/.gitignore
@@ -0,0 +1,5 @@
+synth.blif
+synth.log
+synth.bin
+synth.txt
+firmware.hex
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/Makefile b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/Makefile
new file mode 100644
index 0000000..7672b41
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/Makefile
@@ -0,0 +1,104 @@
+TOOLCHAIN_PREFIX = riscv32-unknown-elf-
+
+ICE40_SIM_CELLS=$(shell yosys-config --datdir/ice40/cells_sim.v)
+
+# set to 4 for simulation
+FIRMWARE_COUNTER_BITS=18
+
+all: example.bin
+
+## -------------------
+## firmware generation
+
+firmware.elf: firmware.S firmware.c firmware.lds
+	$(TOOLCHAIN_PREFIX)gcc \
+		-DSHIFT_COUNTER_BITS=$(FIRMWARE_COUNTER_BITS) \
+		-march=rv32i -Os -ffreestanding -nostdlib \
+		-o $@ firmware.S firmware.c \
+		--std=gnu99 -Wl,-Bstatic,-T,firmware.lds,-Map,firmware.map,--strip-debug
+	chmod -x $@
+
+firmware.bin: firmware.elf
+	$(TOOLCHAIN_PREFIX)objcopy -O binary $< $@
+	chmod -x $@
+
+firmware.hex: firmware.bin
+	python3 ../../firmware/makehex.py $< 128 > $@
+
+## ------------------------------
+## main flow: synth/p&r/bitstream
+
+synth.json: example.v ../../picorv32.v firmware.hex
+	yosys -v3 -l synth.log -p 'synth_ice40 -top top -json $@; write_verilog -attr2comment synth.v' $(filter %.v, $^)
+
+example.asc: synth.json example.pcf
+	nextpnr-ice40 --hx8k --package ct256 --json $< --pcf example.pcf --asc $@
+
+example.bin: example.asc
+	icepack $< $@
+
+## -----------------
+## icarus simulation
+
+example_tb.vvp: example.v example_tb.v ../../picorv32.v firmware.hex
+	iverilog -o $@ -s testbench $(filter %.v, $^)
+	chmod -x $@
+
+example_sim: example_tb.vvp
+	vvp -N $<
+
+example_sim_vcd: example_tb.vvp
+	vvp -N $< +vcd
+
+## ---------------------
+## post-synth simulation
+
+synth_tb.vvp: example_tb.v synth.json
+	iverilog -o $@ -s testbench synth.v example_tb.v $(ICE40_SIM_CELLS)
+	chmod -x $@
+
+synth_sim: synth_tb.vvp
+	vvp -N $<
+
+synth_sim_vcd: synth_tb.vvp
+	vvp -N $< +vcd
+
+## ---------------------
+## post-route simulation
+
+route.v: example.asc example.pcf
+	icebox_vlog -L -n top -sp example.pcf $< > $@
+
+route_tb.vvp: route.v example_tb.v
+	iverilog -o $@ -s testbench $^ $(ICE40_SIM_CELLS)
+	chmod -x $@
+
+route_sim: route_tb.vvp
+	vvp -N $<
+
+route_sim_vcd: route_tb.vvp
+	vvp -N $< +vcd
+
+## ---------------------
+## miscellaneous targets
+
+prog_sram: example.bin
+	iceprog -S $<
+
+timing: example.asc example.pcf
+	icetime -c 62 -tmd hx8k -P ct256 -p example.pcf -t $<
+
+view: example.vcd
+	gtkwave $< example.gtkw
+
+## ------
+## el fin
+
+clean:
+	rm -f firmware.elf firmware.map firmware.bin firmware.hex
+	rm -f synth.log synth.v synth.json route.v example.asc example.bin
+	rm -f example_tb.vvp synth_tb.vvp route_tb.vvp example.vcd
+
+.PHONY: all prog_sram view clean
+.PHONY: example_sim synth_sim route_sim timing
+.PHONY: example_sim_vcd synth_sim_vcd route_sim_vcd
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/example.pcf b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/example.pcf
new file mode 100644
index 0000000..a5c7398
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/example.pcf
@@ -0,0 +1,9 @@
+set_io clk J3
+set_io LED0 B5
+set_io LED1 B4
+set_io LED2 A2
+set_io LED3 A1
+set_io LED4 C5
+set_io LED5 C4
+set_io LED6 B3
+set_io LED7 C3
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/example.v b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/example.v
new file mode 100644
index 0000000..e1c64b4
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/example.v
@@ -0,0 +1,80 @@
+`timescale 1 ns / 1 ps
+
+module top (
+	input clk,
+	output reg LED0, LED1, LED2, LED3, LED4, LED5, LED6, LED7
+);
+	// -------------------------------
+	// Reset Generator
+
+	reg [7:0] resetn_counter = 0;
+	wire resetn = &resetn_counter;
+
+	always @(posedge clk) begin
+		if (!resetn)
+			resetn_counter <= resetn_counter + 1;
+	end
+
+
+	// -------------------------------
+	// PicoRV32 Core
+
+	wire mem_valid;
+	wire [31:0] mem_addr;
+	wire [31:0] mem_wdata;
+	wire [3:0] mem_wstrb;
+
+	reg mem_ready;
+	reg [31:0] mem_rdata;
+
+	picorv32 #(
+		.ENABLE_COUNTERS(0),
+		.LATCHED_MEM_RDATA(1),
+		.TWO_STAGE_SHIFT(0),
+		.TWO_CYCLE_ALU(1),
+		.CATCH_MISALIGN(0),
+		.CATCH_ILLINSN(0)
+	) cpu (
+		.clk      (clk      ),
+		.resetn   (resetn   ),
+		.mem_valid(mem_valid),
+		.mem_ready(mem_ready),
+		.mem_addr (mem_addr ),
+		.mem_wdata(mem_wdata),
+		.mem_wstrb(mem_wstrb),
+		.mem_rdata(mem_rdata)
+	);
+
+
+	// -------------------------------
+	// Memory/IO Interface
+
+	// 128 32bit words = 512 bytes memory
+	localparam MEM_SIZE = 128;
+	reg [31:0] memory [0:MEM_SIZE-1];
+	initial $readmemh("firmware.hex", memory);
+
+	always @(posedge clk) begin
+		mem_ready <= 0;
+		if (resetn && mem_valid && !mem_ready) begin
+			(* parallel_case *)
+			case (1)
+				!mem_wstrb && (mem_addr >> 2) < MEM_SIZE: begin
+					mem_rdata <= memory[mem_addr >> 2];
+					mem_ready <= 1;
+				end
+				|mem_wstrb && (mem_addr >> 2) < MEM_SIZE: begin
+					if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
+					if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
+					if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16];
+					if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24];
+					mem_ready <= 1;
+				end
+				|mem_wstrb && mem_addr == 32'h1000_0000: begin
+					{LED7, LED6, LED5, LED4, LED3, LED2, LED1, LED0} <= mem_wdata;
+					mem_ready <= 1;
+				end
+			endcase
+		end
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/example_tb.v b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/example_tb.v
new file mode 100644
index 0000000..f04f8f8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/example_tb.v
@@ -0,0 +1,30 @@
+`timescale 1 ns / 1 ps
+
+module testbench;
+	reg clk = 1;
+	always #5 clk = ~clk;
+	wire LED0, LED1, LED2, LED3, LED4, LED5, LED6, LED7;
+
+	top uut (
+		.clk(clk),
+		.LED0(LED0),
+		.LED1(LED1),
+		.LED2(LED2),
+		.LED3(LED3),
+		.LED4(LED4),
+		.LED5(LED5),
+		.LED6(LED6),
+		.LED7(LED7)
+	);
+
+	initial begin
+		if ($test$plusargs("vcd")) begin
+			$dumpfile("example.vcd");
+			$dumpvars(0, testbench);
+		end
+
+		$monitor(LED7, LED6, LED5, LED4, LED3, LED2, LED1, LED0);
+		repeat (10000) @(posedge clk);
+		$finish;
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/firmware.S b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/firmware.S
new file mode 100644
index 0000000..d19783d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/firmware.S
@@ -0,0 +1,12 @@
+.section .init
+.global main
+
+/* set stack pointer */
+lui sp, %hi(512)
+addi sp, sp, %lo(512)
+
+/* call main */
+jal ra, main
+
+/* break */
+ebreak
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/firmware.c b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/firmware.c
new file mode 100644
index 0000000..80a4661
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/firmware.c
@@ -0,0 +1,58 @@
+#include <stdint.h>
+
+#ifndef SHIFT_COUNTER_BITS
+#error SHIFT_COUNTER_BITS must be defined as 4 (for simulation) or 18 (for hardware bitstreams)!
+#endif
+
+void output(uint8_t c)
+{
+	*(volatile char*)0x10000000 = c;
+}
+
+uint8_t gray_encode_simple(uint8_t c)
+{
+	return c ^ (c >> 1);
+}
+
+uint8_t gray_encode_bitwise(uint8_t c)
+{
+	unsigned int in_buf = c, out_buf = 0, bit = 1;
+	for (int i = 0; i < 8; i++) {
+		if ((in_buf & 1) ^ ((in_buf >> 1) & 1))
+			out_buf |= bit;
+		in_buf = in_buf >> 1;
+		bit = bit << 1;
+	}
+	return out_buf;
+}
+
+uint8_t gray_decode(uint8_t c)
+{
+	uint8_t t = c >> 1;
+	while (t) {
+		c = c ^ t;
+		t = t >> 1;
+	}
+	return c;
+}
+
+void gray(uint8_t c)
+{
+	uint8_t gray_simple = gray_encode_simple(c);
+	uint8_t gray_bitwise = gray_encode_bitwise(c);
+	uint8_t gray_decoded = gray_decode(gray_simple);
+
+	if (gray_simple != gray_bitwise || gray_decoded != c)
+		while (1) asm volatile ("ebreak");
+
+	output(gray_simple);
+}
+
+void main()
+{
+	for (uint32_t counter = (2+4+32+64) << SHIFT_COUNTER_BITS;; counter++) {
+		asm volatile ("" : : "r"(counter));
+		if ((counter & ~(~0 << SHIFT_COUNTER_BITS)) == 0)
+			gray(counter >> SHIFT_COUNTER_BITS);
+	}
+}
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/firmware.lds b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/firmware.lds
new file mode 100644
index 0000000..970000a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/firmware.lds
@@ -0,0 +1,11 @@
+SECTIONS {
+	.memory : {
+		. = 0x000000;
+		*(.init);
+		*(.text);
+		*(*);
+		. = ALIGN(4);
+		end = .;
+	}
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/readme.md b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/readme.md
new file mode 100644
index 0000000..101391f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/icestorm/readme.md
@@ -0,0 +1,12 @@
+To build the example LED-blinking firmware for an HX8K Breakout Board and get
+a timing report (checked against the default 12MHz oscillator):
+
+    $ make clean example.bin timing
+
+To run all the simulation tests:
+
+    $ make clean example_sim synth_sim route_sim FIRMWARE_COUNTER_BITS=4
+
+(You must run the `clean` target to rebuild the firmware with the updated
+`FIRMWARE_COUNTER_BITS` parameter; the firmware source must be recompiled for
+simulation vs hardware, but this is not tracked as a Makefile dependency.)
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/.gitignore b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/.gitignore
new file mode 100644
index 0000000..4281b17
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/.gitignore
@@ -0,0 +1,7 @@
+firmware.bin
+firmware.elf
+firmware.hex
+firmware.map
+picorv32_presyn.v
+testbench.vcd
+testbench.vvp
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/Makefile b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/Makefile
new file mode 100644
index 0000000..d1c367e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/Makefile
@@ -0,0 +1,22 @@
+
+TOOLCHAIN_PREFIX = /opt/riscv32ic/bin/riscv32-unknown-elf-
+
+run: testbench.vvp firmware.hex
+	vvp -N testbench.vvp
+
+firmware.hex: firmware.S firmware.c firmware.lds
+	$(TOOLCHAIN_PREFIX)gcc -Os -ffreestanding -nostdlib -o firmware.elf firmware.S firmware.c \
+		 --std=gnu99 -Wl,-Bstatic,-T,firmware.lds,-Map,firmware.map,--strip-debug -lgcc
+	$(TOOLCHAIN_PREFIX)objcopy -O binary firmware.elf firmware.bin
+	python3 ../../firmware/makehex.py firmware.bin 4096 > firmware.hex
+
+picorv32_presyn.v: picorv32_presyn.ys picorv32_regs.txt ../../picorv32.v
+	yosys -v0 picorv32_presyn.ys
+
+testbench.vvp: testbench.v picorv32_presyn.v
+	iverilog -o testbench.vvp testbench.v picorv32_presyn.v
+
+clean:
+	rm -f firmware.bin firmware.elf firmware.hex firmware.map
+	rm -f picorv32_presyn.v testbench.vvp testbench.vcd
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/README b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/README
new file mode 100644
index 0000000..14aea33
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/README
@@ -0,0 +1,5 @@
+A simple example for how to use Yosys to "pre-synthesize" PicoRV32 in
+a way that can utilize an external memory module for the register file.
+
+See also:
+https://github.com/cliffordwolf/picorv32/issues/30
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/firmware.S b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/firmware.S
new file mode 100644
index 0000000..ec5caaa
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/firmware.S
@@ -0,0 +1,47 @@
+.section .init
+.global main
+
+entry:
+
+/* zero-initialize all registers */
+addi x1, zero, 0
+addi x2, zero, 0
+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
+
+/* set stack pointer */
+lui sp, %hi(16*1024)
+addi sp, sp, %lo(16*1024)
+
+/* call main */
+jal ra, main
+
+/* break */
+ebreak
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/firmware.c b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/firmware.c
new file mode 100644
index 0000000..6c62169
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/firmware.c
@@ -0,0 +1,43 @@
+void putc(char c)
+{
+	*(volatile char*)0x10000000 = c;
+}
+
+void puts(const char *s)
+{
+	while (*s) putc(*s++);
+}
+
+void *memcpy(void *dest, const void *src, int n)
+{
+	while (n) {
+		n--;
+		((char*)dest)[n] = ((char*)src)[n];
+	}
+	return dest;
+}
+
+void main()
+{
+	char message[] = "$Uryyb+Jbeyq!+Vs+lbh+pna+ernq+guvf+zrffntr+gura$gur+CvpbEI32+PCH"
+			"+frrzf+gb+or+jbexvat+whfg+svar.$$++++++++++++++++GRFG+CNFFRQ!$$";
+	for (int i = 0; message[i]; i++)
+		switch (message[i])
+		{
+		case 'a' ... 'm':
+		case 'A' ... 'M':
+			message[i] += 13;
+			break;
+		case 'n' ... 'z':
+		case 'N' ... 'Z':
+			message[i] -= 13;
+			break;
+		case '$':
+			message[i] = '\n';
+			break;
+		case '+':
+			message[i] = ' ';
+			break;
+		}
+	puts(message);
+}
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/firmware.lds b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/firmware.lds
new file mode 100644
index 0000000..970000a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/firmware.lds
@@ -0,0 +1,11 @@
+SECTIONS {
+	.memory : {
+		. = 0x000000;
+		*(.init);
+		*(.text);
+		*(*);
+		. = ALIGN(4);
+		end = .;
+	}
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/picorv32_presyn.ys b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/picorv32_presyn.ys
new file mode 100644
index 0000000..5855a21
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/picorv32_presyn.ys
@@ -0,0 +1,5 @@
+read_verilog ../../picorv32.v
+chparam -set COMPRESSED_ISA 1 picorv32
+prep -top picorv32
+memory_bram -rules picorv32_regs.txt
+write_verilog -noattr picorv32_presyn.v
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/picorv32_regs.txt b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/picorv32_regs.txt
new file mode 100644
index 0000000..1cfbbeb
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/picorv32_regs.txt
@@ -0,0 +1,16 @@
+bram picorv32_regs
+  init 0
+  abits 5
+  dbits 32
+  groups 2
+  ports  2 1
+  wrmode 0 1
+  enable 0 1
+  transp 0 0
+  clocks 1 1
+  clkpol 1 1
+endbram
+
+match picorv32_regs
+  make_transp
+endmatch
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/testbench.v b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/testbench.v
new file mode 100644
index 0000000..59ff66b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/presyn/testbench.v
@@ -0,0 +1,81 @@
+module testbench;
+	reg clk = 1;
+	always #5 clk = ~clk;
+
+	reg resetn = 0;
+	always @(posedge clk) resetn <= 1;
+
+	wire        trap;
+	wire        mem_valid;
+	wire        mem_instr;
+	reg         mem_ready;
+	wire [31:0] mem_addr;
+	wire [31:0] mem_wdata;
+	wire [3:0]  mem_wstrb;
+	reg  [31:0] mem_rdata;
+
+	picorv32 UUT (
+		.clk      (clk      ),
+		.resetn   (resetn   ),
+		.trap     (trap     ),
+		.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)
+	);
+
+	// 4096 32bit words = 16kB memory
+	localparam MEM_SIZE = 4096;
+
+	reg [31:0] memory [0:MEM_SIZE-1];
+	initial $readmemh("firmware.hex", memory);
+
+	always @(posedge clk) begin
+		mem_ready <= 0;
+		mem_rdata <= 'bx;
+
+		if (resetn && mem_valid && !mem_ready) begin
+			mem_ready <= 1;
+			if (mem_wstrb) begin
+				if (mem_addr == 32'h1000_0000) begin
+					$write("%c", mem_wdata[7:0]);
+					$fflush;
+				end else begin
+					if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
+					if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
+					if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16];
+					if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24];
+				end
+			end else begin
+				mem_rdata <= memory[mem_addr >> 2];
+			end
+		end
+
+		if (resetn && trap) begin
+			$display("TRAP.");
+			$finish;
+		end
+	end
+
+	initial begin
+		$dumpfile("testbench.vcd");
+		$dumpvars(0, testbench);
+	end
+endmodule
+
+module picorv32_regs (
+	input [4:0] A1ADDR, A2ADDR, B1ADDR,
+	output reg [31:0] A1DATA, A2DATA,
+	input [31:0] B1DATA,
+	input B1EN, CLK1
+);
+	reg [31:0] memory [0:31];
+	always @(posedge CLK1) begin
+		A1DATA <= memory[A1ADDR];
+		A2DATA <= memory[A2ADDR];
+		if (B1EN) memory[B1ADDR] <= B1DATA;
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/.gitignore b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/.gitignore
new file mode 100644
index 0000000..d37ca0a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/.gitignore
@@ -0,0 +1,11 @@
+firmware.bin
+firmware.elf
+firmware.hex
+firmware.map
+synth_*.log
+synth_*.mmi
+synth_*.bit
+synth_system.v
+table.txt
+tab_*/
+system_tb
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/Makefile b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/Makefile
new file mode 100644
index 0000000..c644609
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/Makefile
@@ -0,0 +1,62 @@
+
+export QUARTUS_ROOTDIR = /opt/altera_lite/16.0
+export QUARTUS_BIN = $(QUARTUS_ROOTDIR)/quartus/bin
+
+VLOG = iverilog
+TOOLCHAIN_PREFIX = /opt/riscv32i/bin/riscv32-unknown-elf-
+
+help:
+	@echo ""
+	@echo "Simple synthesis tests:"
+	@echo "  make synth_area_{small|regular|large}"
+	@echo "  make synth_speed"
+	@echo ""
+	@echo "Example system:"
+	@echo "  make synth_system"
+	@echo "  make sim_system"
+	@echo ""
+	@echo "Timing and Utilization Evaluation:"
+	@echo "  make table.txt"
+	@echo "  make area"
+	@echo ""
+
+synth_%:
+	rm -f $@.log
+	mkdir -p $@_build
+	cp $@.qsf $@_build
+	cd $@_build && $(QUARTUS_BIN)/quartus_map $@.qsf
+	cd $@_build && $(QUARTUS_BIN)/quartus_fit --read_settings_files=off -write_settings_files=off $@ -c $@
+	cd $@_build && $(QUARTUS_BIN)/quartus_sta $@ -c $@
+	-cd $@_build && grep -A3 "Total logic elements" output_files/$@.fit.summary
+	-cd $@_build && grep -B1 "Slack" output_files/$@.sta.summary
+
+synth_system: firmware.hex
+
+sim_system: firmware.hex system_tb.v system.v ../../picorv32.v
+	$(VLOG) -o system_tb system_tb.v system.v ../../picorv32.v
+	./system_tb
+
+firmware.hex: firmware.S firmware.c firmware.lds
+	$(TOOLCHAIN_PREFIX)gcc -Os -ffreestanding -nostdlib -o firmware.elf firmware.S firmware.c \
+		 --std=gnu99 -Wl,-Bstatic,-T,firmware.lds,-Map,firmware.map,--strip-debug -lgcc
+	$(TOOLCHAIN_PREFIX)objcopy -O binary firmware.elf firmware.bin
+	python3 ../../firmware/makehex.py firmware.bin 4096 > firmware.hex
+
+tab_%/results.txt:
+	bash tabtest.sh $@
+
+area: synth_area_small synth_area_regular synth_area_large
+	-grep -A3 "Total logic elements" synth_area_*_build/output_files/synth_area_*.fit.summary
+
+table.txt: tab_small_ep4ce_c7/results.txt
+table.txt: tab_small_ep4cgx_c7/results.txt
+table.txt: tab_small_5cgx_c7/results.txt
+
+table.txt:
+	bash table.sh > table.txt
+
+clean:
+	rm -rf firmware.bin firmware.elf firmware.hex firmware.map synth_*.log
+	rm -rf table.txt tab_*/
+	rm -rf synth_*_build
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/firmware.S b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/firmware.S
new file mode 100644
index 0000000..c55a3ba
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/firmware.S
@@ -0,0 +1,12 @@
+.section .init
+.global main
+
+/* set stack pointer */
+lui sp, %hi(16*1024)
+addi sp, sp, %lo(16*1024)
+
+/* call main */
+jal ra, main
+
+/* break */
+ebreak
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/firmware.c b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/firmware.c
new file mode 100644
index 0000000..6c62169
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/firmware.c
@@ -0,0 +1,43 @@
+void putc(char c)
+{
+	*(volatile char*)0x10000000 = c;
+}
+
+void puts(const char *s)
+{
+	while (*s) putc(*s++);
+}
+
+void *memcpy(void *dest, const void *src, int n)
+{
+	while (n) {
+		n--;
+		((char*)dest)[n] = ((char*)src)[n];
+	}
+	return dest;
+}
+
+void main()
+{
+	char message[] = "$Uryyb+Jbeyq!+Vs+lbh+pna+ernq+guvf+zrffntr+gura$gur+CvpbEI32+PCH"
+			"+frrzf+gb+or+jbexvat+whfg+svar.$$++++++++++++++++GRFG+CNFFRQ!$$";
+	for (int i = 0; message[i]; i++)
+		switch (message[i])
+		{
+		case 'a' ... 'm':
+		case 'A' ... 'M':
+			message[i] += 13;
+			break;
+		case 'n' ... 'z':
+		case 'N' ... 'Z':
+			message[i] -= 13;
+			break;
+		case '$':
+			message[i] = '\n';
+			break;
+		case '+':
+			message[i] = ' ';
+			break;
+		}
+	puts(message);
+}
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/firmware.lds b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/firmware.lds
new file mode 100644
index 0000000..970000a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/firmware.lds
@@ -0,0 +1,11 @@
+SECTIONS {
+	.memory : {
+		. = 0x000000;
+		*(.init);
+		*(.text);
+		*(*);
+		. = ALIGN(4);
+		end = .;
+	}
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_area.sdc b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_area.sdc
new file mode 100644
index 0000000..3c3d5a1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_area.sdc
@@ -0,0 +1 @@
+create_clock -period 20.00 [get_ports clk]
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_area_large.qsf b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_area_large.qsf
new file mode 100644
index 0000000..c09700b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_area_large.qsf
@@ -0,0 +1,6 @@
+set_global_assignment -name DEVICE ep4ce40f29c7
+set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
+set_global_assignment -name TOP_LEVEL_ENTITY top_large
+set_global_assignment -name VERILOG_FILE ../synth_area_top.v
+set_global_assignment -name VERILOG_FILE ../../../picorv32.v
+set_global_assignment -name SDC_FILE ../synth_area.sdc
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_area_regular.qsf b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_area_regular.qsf
new file mode 100644
index 0000000..8507413
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_area_regular.qsf
@@ -0,0 +1,6 @@
+set_global_assignment -name DEVICE ep4ce40f29c7
+set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
+set_global_assignment -name TOP_LEVEL_ENTITY top_regular
+set_global_assignment -name VERILOG_FILE ../synth_area_top.v
+set_global_assignment -name VERILOG_FILE ../../../picorv32.v
+set_global_assignment -name SDC_FILE ../synth_area.sdc
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_area_small.qsf b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_area_small.qsf
new file mode 100644
index 0000000..048ff96
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_area_small.qsf
@@ -0,0 +1,6 @@
+set_global_assignment -name DEVICE ep4ce40f29c7
+set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
+set_global_assignment -name TOP_LEVEL_ENTITY top_small
+set_global_assignment -name VERILOG_FILE ../synth_area_top.v
+set_global_assignment -name VERILOG_FILE ../../../picorv32.v
+set_global_assignment -name SDC_FILE ../synth_area.sdc
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_area_top.v b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_area_top.v
new file mode 100644
index 0000000..6298a86
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_area_top.v
@@ -0,0 +1,140 @@
+
+module top_small (
+	input clk, resetn,
+
+	output        mem_valid,
+	output        mem_instr,
+	input         mem_ready,
+
+	output [31:0] mem_addr,
+	output [31:0] mem_wdata,
+	output [ 3:0] mem_wstrb,
+	input  [31:0] mem_rdata
+);
+	picorv32 #(
+		.ENABLE_COUNTERS(0),
+		.LATCHED_MEM_RDATA(1),
+		.TWO_STAGE_SHIFT(0),
+		.CATCH_MISALIGN(0),
+		.CATCH_ILLINSN(0)
+	) picorv32 (
+		.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)
+	);
+endmodule
+
+module top_regular (
+	input clk, resetn,
+	output trap,
+
+	output        mem_valid,
+	output        mem_instr,
+	input         mem_ready,
+
+	output [31:0] mem_addr,
+	output [31:0] mem_wdata,
+	output [ 3:0] mem_wstrb,
+	input  [31:0] mem_rdata,
+
+	// Look-Ahead Interface
+	output        mem_la_read,
+	output        mem_la_write,
+	output [31:0] mem_la_addr,
+	output [31:0] mem_la_wdata,
+	output [ 3:0] mem_la_wstrb
+);
+	picorv32 picorv32 (
+		.clk         (clk         ),
+		.resetn      (resetn      ),
+		.trap        (trap        ),
+		.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   ),
+		.mem_la_read (mem_la_read ),
+		.mem_la_write(mem_la_write),
+		.mem_la_addr (mem_la_addr ),
+		.mem_la_wdata(mem_la_wdata),
+		.mem_la_wstrb(mem_la_wstrb)
+	);
+endmodule
+
+module top_large (
+	input clk, resetn,
+	output trap,
+
+	output        mem_valid,
+	output        mem_instr,
+	input         mem_ready,
+
+	output [31:0] mem_addr,
+	output [31:0] mem_wdata,
+	output [ 3:0] mem_wstrb,
+	input  [31:0] mem_rdata,
+
+	// Look-Ahead Interface
+	output        mem_la_read,
+	output        mem_la_write,
+	output [31:0] mem_la_addr,
+	output [31:0] mem_la_wdata,
+	output [ 3:0] mem_la_wstrb,
+
+	// Pico Co-Processor Interface (PCPI)
+	output        pcpi_valid,
+	output [31:0] pcpi_insn,
+	output [31:0] pcpi_rs1,
+	output [31:0] pcpi_rs2,
+	input         pcpi_wr,
+	input  [31:0] pcpi_rd,
+	input         pcpi_wait,
+	input         pcpi_ready,
+
+	// IRQ Interface
+	input  [31:0] irq,
+	output [31:0] eoi
+);
+	picorv32 #(
+		.COMPRESSED_ISA(1),
+		.BARREL_SHIFTER(1),
+		.ENABLE_PCPI(1),
+		.ENABLE_MUL(1),
+		.ENABLE_IRQ(1)
+	) picorv32 (
+		.clk            (clk            ),
+		.resetn         (resetn         ),
+		.trap           (trap           ),
+		.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      ),
+		.mem_la_read    (mem_la_read    ),
+		.mem_la_write   (mem_la_write   ),
+		.mem_la_addr    (mem_la_addr    ),
+		.mem_la_wdata   (mem_la_wdata   ),
+		.mem_la_wstrb   (mem_la_wstrb   ),
+		.pcpi_valid     (pcpi_valid     ),
+		.pcpi_insn      (pcpi_insn      ),
+		.pcpi_rs1       (pcpi_rs1       ),
+		.pcpi_rs2       (pcpi_rs2       ),
+		.pcpi_wr        (pcpi_wr        ),
+		.pcpi_rd        (pcpi_rd        ),
+		.pcpi_wait      (pcpi_wait      ),
+		.pcpi_ready     (pcpi_ready     ),
+		.irq            (irq            ),
+		.eoi            (eoi            )
+	);
+endmodule
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_speed.qsf b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_speed.qsf
new file mode 100644
index 0000000..64490d4
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_speed.qsf
@@ -0,0 +1,5 @@
+set_global_assignment -name DEVICE ep4ce40f29c7
+set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
+set_global_assignment -name TOP_LEVEL_ENTITY picorv32_axi
+set_global_assignment -name VERILOG_FILE ../../../picorv32.v
+set_global_assignment -name SDC_FILE ../synth_speed.sdc
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_speed.sdc b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_speed.sdc
new file mode 100644
index 0000000..fef5704
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_speed.sdc
@@ -0,0 +1 @@
+create_clock -period 2.5 [get_ports clk]
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_system.qsf b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_system.qsf
new file mode 100644
index 0000000..1a84293
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_system.qsf
@@ -0,0 +1,6 @@
+set_global_assignment -name DEVICE ep4ce40f29c7
+set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
+set_global_assignment -name TOP_LEVEL_ENTITY system
+set_global_assignment -name VERILOG_FILE ../system.v
+set_global_assignment -name VERILOG_FILE ../../../picorv32.v
+set_global_assignment -name SDC_FILE ../synth_system.sdc
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_system.sdc b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_system.sdc
new file mode 100644
index 0000000..90ee3a2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_system.sdc
@@ -0,0 +1 @@
+create_clock -period 10.00 [get_ports clk]
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_system.tcl b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_system.tcl
new file mode 100644
index 0000000..26ea01c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/synth_system.tcl
@@ -0,0 +1,17 @@
+
+read_verilog system.v
+read_verilog ../../picorv32.v
+read_xdc synth_system.xdc
+
+synth_design -part xc7a35t-cpg236-1 -top system
+opt_design
+place_design
+route_design
+
+report_utilization
+report_timing
+
+write_verilog -force synth_system.v
+write_bitstream -force synth_system.bit
+# write_mem_info -force synth_system.mmi
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/system.v b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/system.v
new file mode 100644
index 0000000..19a4b8d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/system.v
@@ -0,0 +1,101 @@
+`timescale 1 ns / 1 ps
+
+module system (
+	input            clk,
+	input            resetn,
+	output           trap,
+	output reg [7:0] out_byte,
+	output reg       out_byte_en
+);
+	// set this to 0 for better timing but less performance/MHz
+	parameter FAST_MEMORY = 0;
+
+	// 4096 32bit words = 16kB memory
+	parameter MEM_SIZE = 4096;
+
+	wire mem_valid;
+	wire mem_instr;
+	reg mem_ready;
+	wire [31:0] mem_addr;
+	wire [31:0] mem_wdata;
+	wire [3:0] mem_wstrb;
+	reg [31:0] mem_rdata;
+
+	wire mem_la_read;
+	wire mem_la_write;
+	wire [31:0] mem_la_addr;
+	wire [31:0] mem_la_wdata;
+	wire [3:0] mem_la_wstrb;
+
+	picorv32 picorv32_core (
+		.clk         (clk         ),
+		.resetn      (resetn      ),
+		.trap        (trap        ),
+		.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   ),
+		.mem_la_read (mem_la_read ),
+		.mem_la_write(mem_la_write),
+		.mem_la_addr (mem_la_addr ),
+		.mem_la_wdata(mem_la_wdata),
+		.mem_la_wstrb(mem_la_wstrb)
+	);
+
+	reg [31:0] memory [0:MEM_SIZE-1];
+	initial $readmemh("firmware.hex", memory);
+
+	reg [31:0] m_read_data;
+	reg m_read_en;
+
+	generate if (FAST_MEMORY) begin
+		always @(posedge clk) begin
+			mem_ready <= 1;
+			out_byte_en <= 0;
+			mem_rdata <= memory[mem_la_addr >> 2];
+			if (mem_la_write && (mem_la_addr >> 2) < MEM_SIZE) begin
+				if (mem_la_wstrb[0]) memory[mem_la_addr >> 2][ 7: 0] <= mem_la_wdata[ 7: 0];
+				if (mem_la_wstrb[1]) memory[mem_la_addr >> 2][15: 8] <= mem_la_wdata[15: 8];
+				if (mem_la_wstrb[2]) memory[mem_la_addr >> 2][23:16] <= mem_la_wdata[23:16];
+				if (mem_la_wstrb[3]) memory[mem_la_addr >> 2][31:24] <= mem_la_wdata[31:24];
+			end
+			else
+			if (mem_la_write && mem_la_addr == 32'h1000_0000) begin
+				out_byte_en <= 1;
+				out_byte <= mem_la_wdata;
+			end
+		end
+	end else begin
+		always @(posedge clk) begin
+			m_read_en <= 0;
+			mem_ready <= mem_valid && !mem_ready && m_read_en;
+
+			m_read_data <= memory[mem_addr >> 2];
+			mem_rdata <= m_read_data;
+
+			out_byte_en <= 0;
+
+			(* parallel_case *)
+			case (1)
+				mem_valid && !mem_ready && !mem_wstrb && (mem_addr >> 2) < MEM_SIZE: begin
+					m_read_en <= 1;
+				end
+				mem_valid && !mem_ready && |mem_wstrb && (mem_addr >> 2) < MEM_SIZE: begin
+					if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
+					if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
+					if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16];
+					if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24];
+					mem_ready <= 1;
+				end
+				mem_valid && !mem_ready && |mem_wstrb && mem_addr == 32'h1000_0000: begin
+					out_byte_en <= 1;
+					out_byte <= mem_wdata;
+					mem_ready <= 1;
+				end
+			endcase
+		end
+	end endgenerate
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/system_tb.v b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/system_tb.v
new file mode 100644
index 0000000..a66d612
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/system_tb.v
@@ -0,0 +1,38 @@
+`timescale 1 ns / 1 ps
+
+module system_tb;
+	reg clk = 1;
+	always #5 clk = ~clk;
+
+	reg resetn = 0;
+	initial begin
+		if ($test$plusargs("vcd")) begin
+			$dumpfile("system.vcd");
+			$dumpvars(0, system_tb);
+		end
+		repeat (100) @(posedge clk);
+		resetn <= 1;
+	end
+
+	wire trap;
+	wire [7:0] out_byte;
+	wire out_byte_en;
+
+	system uut (
+		.clk        (clk        ),
+		.resetn     (resetn     ),
+		.trap       (trap       ),
+		.out_byte   (out_byte   ),
+		.out_byte_en(out_byte_en)
+	);
+
+	always @(posedge clk) begin
+		if (resetn && out_byte_en) begin
+			$write("%c", out_byte);
+			$fflush;
+		end
+		if (resetn && trap) begin
+			$finish;
+		end
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/table.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/table.sh
new file mode 100644
index 0000000..f5e6efe
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/table.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+dashes="----------------------------------------------------------------"
+printf '| %-25s | %-10s | %-20s |\n' "Device" "Speedgrade" "Clock Period (Freq.)"
+printf '|:%.25s |:%.10s:| %.20s:|\n' $dashes $dashes $dashes
+
+for x in $( grep -H . tab_*/results.txt )
+do
+	read _ size device grade _ speed < <( echo "$x" | tr _/: ' ' )
+	case "$device" in
+		ep4ce)  d="Altera Cyclone IV E" ;;
+		ep4cgx) d="Altera Cyclone IV GX" ;;
+		5cgx)   d="Altera Cyclone V GX" ;;
+	esac
+	speedtxt=$( printf '%s.%s ns (%d MHz)' ${speed%?} ${speed#?} $((10000 / speed)) )
+	printf '| %-25s | %-10s | %20s |\n' "$d" "-$grade" "$speedtxt"
+done
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/tabtest.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/tabtest.sh
new file mode 100644
index 0000000..2fd1b40
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/tabtest.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+
+set -e
+read _ ip dev grade _ < <( echo $* | tr '_/' ' '; )
+
+# rm -rf tab_${ip}_${dev}_${grade}
+mkdir -p tab_${ip}_${dev}_${grade}
+cd tab_${ip}_${dev}_${grade}
+
+max_speed=99
+min_speed=01
+best_speed=99
+
+synth_case() {
+	if [ -f test_${1}.txt ]; then
+		echo "Reusing cached tab_${ip}_${dev}_${grade}/test_${1}."
+		return
+	fi
+
+	case "${dev}" in
+		ep4ce)  al_device="ep4ce30f23${grade}" ;;
+		ep4cgx) al_device="ep4cgx50df27${grade}" ;;
+		5cgx)   al_device="5cgxbc9c6f23${grade}" ;;
+	esac
+
+	cat > test_${1}.qsf <<- EOT
+set_global_assignment -name DEVICE ${al_device}
+set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
+set_global_assignment -name TOP_LEVEL_ENTITY top
+set_global_assignment -name VERILOG_FILE ../tabtest.v
+set_global_assignment -name VERILOG_FILE ../../../picorv32.v
+set_global_assignment -name SDC_FILE test_${1}.sdc
+	EOT
+
+	cat > test_${1}.sdc <<- EOT
+		create_clock -period ${speed%?}.${speed#?} [get_ports clk]
+	EOT
+
+	echo "Running tab_${ip}_${dev}_${grade}/test_${1}.."
+
+    if ! $QUARTUS_BIN/quartus_map test_${1}; then
+        exit 1
+    fi
+    if ! $QUARTUS_BIN/quartus_fit --read_settings_files=off --write_settings_files=off test_${1} -c test_${1}; then
+        exit 1
+    fi
+    if ! $QUARTUS_BIN/quartus_sta test_${1} -c test_${1}; then
+        exit 1
+    fi
+
+	cp output_files/test_${1}.sta.summary test_${1}.txt
+}
+
+countdown=7
+while [ $countdown -gt 0 ]; do
+    speed=$(((max_speed+min_speed)/2))
+	synth_case $speed
+
+    if grep -q '^Slack : -' test_${speed}.txt; then
+		echo "        tab_${ip}_${dev}_${grade}/test_${speed} VIOLATED"
+        min_speed=$((speed))
+    elif grep -q '^Slack : [^-]' test_${speed}.txt; then
+		echo "        tab_${ip}_${dev}_${grade}/test_${speed} MET"
+		[ $speed -lt $best_speed ] && best_speed=$speed
+        max_speed=$((speed))
+	else
+		echo "ERROR: No slack line found in $PWD/test_${speed}.txt!"
+		exit 1
+	fi
+
+    countdown=$((countdown-1))
+done
+
+echo "-----------------------"
+echo "Best speed for tab_${ip}_${dev}_${grade}: $best_speed"
+echo "-----------------------"
+echo $best_speed > results.txt
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/tabtest.v b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/tabtest.v
new file mode 100644
index 0000000..cdf2057
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/quartus/tabtest.v
@@ -0,0 +1,118 @@
+
+module top (
+	input clk, io_resetn,
+	output io_trap,
+
+	output        io_mem_axi_awvalid,
+	input         io_mem_axi_awready,
+	output [31:0] io_mem_axi_awaddr,
+	output [ 2:0] io_mem_axi_awprot,
+
+	output        io_mem_axi_wvalid,
+	input         io_mem_axi_wready,
+	output [31:0] io_mem_axi_wdata,
+	output [ 3:0] io_mem_axi_wstrb,
+
+	input         io_mem_axi_bvalid,
+	output        io_mem_axi_bready,
+
+	output        io_mem_axi_arvalid,
+	input         io_mem_axi_arready,
+	output [31:0] io_mem_axi_araddr,
+	output [ 2:0] io_mem_axi_arprot,
+
+	input         io_mem_axi_rvalid,
+	output        io_mem_axi_rready,
+	input  [31:0] io_mem_axi_rdata,
+
+	input  [31:0] io_irq,
+	output [31:0] io_eoi
+);
+	wire resetn;
+	wire trap;
+	wire mem_axi_awvalid;
+	wire mem_axi_awready;
+	wire [31:0] mem_axi_awaddr;
+	wire [2:0] mem_axi_awprot;
+	wire mem_axi_wvalid;
+	wire mem_axi_wready;
+	wire [31:0] mem_axi_wdata;
+	wire [3:0] mem_axi_wstrb;
+	wire mem_axi_bvalid;
+	wire mem_axi_bready;
+	wire mem_axi_arvalid;
+	wire mem_axi_arready;
+	wire [31:0] mem_axi_araddr;
+	wire [2:0] mem_axi_arprot;
+	wire mem_axi_rvalid;
+	wire mem_axi_rready;
+	wire [31:0] mem_axi_rdata;
+	wire [31:0] irq;
+	wire [31:0] eoi;
+
+	delay4 #( 1) delay_resetn          (clk, io_resetn         ,    resetn         );
+	delay4 #( 1) delay_trap            (clk,    trap           , io_trap           );
+	delay4 #( 1) delay_mem_axi_awvalid (clk,    mem_axi_awvalid, io_mem_axi_awvalid);
+	delay4 #( 1) delay_mem_axi_awready (clk, io_mem_axi_awready,    mem_axi_awready);
+	delay4 #(32) delay_mem_axi_awaddr  (clk,    mem_axi_awaddr , io_mem_axi_awaddr );
+	delay4 #( 3) delay_mem_axi_awprot  (clk,    mem_axi_awprot , io_mem_axi_awprot );
+	delay4 #( 1) delay_mem_axi_wvalid  (clk,    mem_axi_wvalid , io_mem_axi_wvalid );
+	delay4 #( 1) delay_mem_axi_wready  (clk, io_mem_axi_wready ,    mem_axi_wready );
+	delay4 #(32) delay_mem_axi_wdata   (clk,    mem_axi_wdata  , io_mem_axi_wdata  );
+	delay4 #( 4) delay_mem_axi_wstrb   (clk,    mem_axi_wstrb  , io_mem_axi_wstrb  );
+	delay4 #( 1) delay_mem_axi_bvalid  (clk, io_mem_axi_bvalid ,    mem_axi_bvalid );
+	delay4 #( 1) delay_mem_axi_bready  (clk,    mem_axi_bready , io_mem_axi_bready );
+	delay4 #( 1) delay_mem_axi_arvalid (clk,    mem_axi_arvalid, io_mem_axi_arvalid);
+	delay4 #( 1) delay_mem_axi_arready (clk, io_mem_axi_arready,    mem_axi_arready);
+	delay4 #(32) delay_mem_axi_araddr  (clk,    mem_axi_araddr , io_mem_axi_araddr );
+	delay4 #( 3) delay_mem_axi_arprot  (clk,    mem_axi_arprot , io_mem_axi_arprot );
+	delay4 #( 1) delay_mem_axi_rvalid  (clk, io_mem_axi_rvalid ,    mem_axi_rvalid );
+	delay4 #( 1) delay_mem_axi_rready  (clk,    mem_axi_rready , io_mem_axi_rready );
+	delay4 #(32) delay_mem_axi_rdata   (clk, io_mem_axi_rdata  ,    mem_axi_rdata  );
+	delay4 #(32) delay_irq             (clk, io_irq            ,    irq            );
+	delay4 #(32) delay_eoi             (clk,    eoi            , io_eoi            );
+
+	picorv32_axi #(
+		.TWO_CYCLE_ALU(1)
+	) cpu (
+		.clk            (clk            ),
+		.resetn         (resetn         ),
+		.trap           (trap           ),
+		.mem_axi_awvalid(mem_axi_awvalid),
+		.mem_axi_awready(mem_axi_awready),
+		.mem_axi_awaddr (mem_axi_awaddr ),
+		.mem_axi_awprot (mem_axi_awprot ),
+		.mem_axi_wvalid (mem_axi_wvalid ),
+		.mem_axi_wready (mem_axi_wready ),
+		.mem_axi_wdata  (mem_axi_wdata  ),
+		.mem_axi_wstrb  (mem_axi_wstrb  ),
+		.mem_axi_bvalid (mem_axi_bvalid ),
+		.mem_axi_bready (mem_axi_bready ),
+		.mem_axi_arvalid(mem_axi_arvalid),
+		.mem_axi_arready(mem_axi_arready),
+		.mem_axi_araddr (mem_axi_araddr ),
+		.mem_axi_arprot (mem_axi_arprot ),
+		.mem_axi_rvalid (mem_axi_rvalid ),
+		.mem_axi_rready (mem_axi_rready ),
+		.mem_axi_rdata  (mem_axi_rdata  ),
+		.irq            (irq            ),
+		.eoi            (eoi            )
+	);
+endmodule
+
+module delay4 #(
+	parameter WIDTH = 1
+) (
+	input clk,
+	input [WIDTH-1:0] in,
+	output reg [WIDTH-1:0] out
+);
+	reg [WIDTH-1:0] q1, q2, q3;
+	always @(posedge clk) begin
+		q1 <= in;
+		q2 <= q1;
+		q3 <= q2;
+		out <= q3;
+	end
+endmodule
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/romload/.gitignore b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/.gitignore
new file mode 100644
index 0000000..6f1295b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/.gitignore
@@ -0,0 +1,11 @@
+firmware.d
+firmware.elf
+firmware.hex
+firmware32.hex
+firmware.o
+firmware_addr.txt
+firmware_dbg.v
+syscalls.o
+testbench.vvp
+testbench.vcd
+start.elf
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/romload/Makefile b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/Makefile
new file mode 100644
index 0000000..d510fa8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/Makefile
@@ -0,0 +1,41 @@
+ifndef RISCV_TOOLS_PREFIX
+RISCV_TOOLS_PREFIX = /opt/riscv32ic/bin/riscv32-unknown-elf-
+endif
+CXX = $(RISCV_TOOLS_PREFIX)g++ -march=rv32i
+CC = $(RISCV_TOOLS_PREFIX)gcc -march=rv32i
+AS = $(RISCV_TOOLS_PREFIX)gcc -march=rv32i
+CXXFLAGS = -MD -Os -Wall -std=c++11
+CCFLAGS = -MD -Os -Wall
+#LDFLAGS = -Wl,--gc-sections,--no-relax
+LDFLAGS = -Wl,--gc-sections
+LDLIBS =
+
+test: testbench.vvp firmware32.hex
+	vvp -l testbench.log -N testbench.vvp
+
+testbench.vvp: testbench.v ../../picorv32.v firmware_dbg.v
+	iverilog -o testbench.vvp testbench.v ../../picorv32.v
+	chmod -x testbench.vvp
+
+firmware32.hex: firmware.elf hex8tohex32.py
+	$(RISCV_TOOLS_PREFIX)objcopy -O verilog firmware.elf firmware.tmp
+	python3 hex8tohex32.py firmware.tmp > firmware32.hex
+
+
+firmware_dbg.v: firmware.map
+	python3 map2debug.py
+
+start.o: start.S
+	$(CC) -c -nostdlib start.S $(LDLIBS)
+
+firmware.elf: firmware.o syscalls.o start.o
+	$(CC) $(LDFLAGS),-Map=firmware.map -o $@ $^ -T sections.ld $(LDLIBS)
+	chmod -x firmware.elf
+
+clean:
+	rm -f *.o *.d *.tmp start.elf
+	rm -f firmware.elf firmware.hex firmware32.hex
+	rm -f testbench.vvp testbench.vcd
+
+-include *.d
+.PHONY: test clean
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/romload/firmware.c b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/firmware.c
new file mode 100644
index 0000000..4bc9ed8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/firmware.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int x1 = 1000;
+int x2 = 2000;
+
+void main()
+{
+  int z;
+  x1 = 50;
+  x2 = 50;
+
+  printf("hello\n");
+  z = (x1 + x2);
+  if (z == 100)
+    printf("TEST PASSED\n");
+  else
+    printf("TEST FAILED, z=%d\n", z);
+  exit(0);
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/romload/hex8tohex32.py b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/hex8tohex32.py
new file mode 100644
index 0000000..ae44101
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/hex8tohex32.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+
+import fileinput
+import itertools
+
+ptr = 0
+data = []
+
+def write_data():
+    if len(data) != 0:
+        print("@%08x" % (ptr >> 2))
+        while len(data) % 4 != 0:
+            data.append(0)
+        for word_bytes in zip(*([iter(data)]*4)):
+            print("".join(["%02x" % b for b in reversed(word_bytes)]))
+
+for line in fileinput.input():
+    if line.startswith("@"):
+        addr = int(line[1:], 16)
+        if addr > ptr+4:
+            write_data()
+            ptr = addr
+            data = []
+            while ptr % 4 != 0:
+                data.append(0)
+                ptr -= 1
+        else:
+            while ptr + len(data) < addr:
+                data.append(0)
+    else:
+        data += [int(tok, 16) for tok in line.split()]
+
+write_data()
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/romload/map2debug.py b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/map2debug.py
new file mode 100644
index 0000000..fc5c97c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/map2debug.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+
+import re
+
+symbol = re.compile("\s*0x([0-9a-f]+)\s+([\w_]+)")
+symbol_map = {}
+with open("firmware.map", "r") as fh:
+    for fd in fh:
+        sym = symbol.match(fd)
+        if (sym):
+            addr = int(sym.group(1), 16)
+            symbol_map[addr] = sym.group(2)
+
+with open("firmware_dbg.v", "w") as fh:
+    for k, v in symbol_map.items():
+        fh.write("`define C_SYM_{1:s} 32'h{0:08x}\n".format(k, v.upper()))
+    fh.write("  task firmware_dbg;\n")
+    fh.write("  input [31:0] addr;\n");
+    fh.write("  begin\n");
+    fh.write("    case (addr)\n");
+    for k, v in symbol_map.items():
+        fh.write("      32'h{0:08x} : $display(\"%t: FCALL: {1:s}\", $time);\n".format(k, v))
+    fh.write("    endcase\n");
+    fh.write("  end\n");
+    fh.write("  endtask\n");
+
+with open("firmware_addr.txt", "w") as fh:
+    for k, v in symbol_map.items():
+        fh.write("{0:08x} {1:s}\n".format(k,v))
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/romload/sections.ld b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/sections.ld
new file mode 100644
index 0000000..2ec3954
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/sections.ld
@@ -0,0 +1,45 @@
+/*
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+*/
+
+/* starting address needs to be > 0 due to known bug in RISCV/GNU linker */
+MEMORY {
+	rom(rwx) : ORIGIN = 0x00000100, LENGTH = 63k
+        ram(rwx) : ORIGIN = 0x00020000, LENGTH = 16k
+}
+
+ENTRY(_pvstart);
+
+SECTIONS {
+	.rom : {
+                _pvstart*(.text);
+		start*(.text);
+                . = 0x100;
+                . = ALIGN(4);
+		*(.text);
+        } > rom
+
+        .data : {
+          _data_lma = LOADADDR(.data);
+          _data = .;
+          __global_pointer$ = . ;
+          *(.data .data.* )
+          *(.sdata .sdata.*)
+           . = ALIGN(4);
+          _edata = .;
+        } >ram AT>rom
+
+        .bss : {
+          _bss_start = .;
+          *(.bss .bss.*)
+           . = ALIGN(4);
+          _bss_end = .;
+          _end = .;
+        } >ram
+
+}
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/romload/start.S b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/start.S
new file mode 100644
index 0000000..be59808
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/start.S
@@ -0,0 +1,52 @@
+.section .text
+.global _start
+.global _pvstart
+
+_pvstart:
+/* zero-initialize all registers */
+addi x1, zero, 0
+addi x2, zero, 0
+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
+
+/* set stack pointer */
+
+lui sp, %hi(4*1024*1024)
+addi sp, sp, %lo(4*1024*1024)
+
+/* push zeros on the stack for argc and argv */
+/* (stack is aligned to 16 bytes in riscv calling convention) */
+addi sp,sp,-16
+sw zero,0(sp)
+sw zero,4(sp)
+sw zero,8(sp)
+sw zero,12(sp)
+
+j _start
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/romload/syscalls.c b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/syscalls.c
new file mode 100644
index 0000000..8ea84ca
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/syscalls.c
@@ -0,0 +1,95 @@
+// An extremely minimalist syscalls.c for newlib
+// Based on riscv newlib libgloss/riscv/sys_*.c
+// Written by Clifford Wolf.
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define UNIMPL_FUNC(_f) ".globl " #_f "\n.type " #_f ", @function\n" #_f ":\n"
+
+asm (
+	".text\n"
+	".align 2\n"
+	UNIMPL_FUNC(_open)
+	UNIMPL_FUNC(_openat)
+	UNIMPL_FUNC(_lseek)
+	UNIMPL_FUNC(_stat)
+	UNIMPL_FUNC(_lstat)
+	UNIMPL_FUNC(_fstatat)
+	UNIMPL_FUNC(_isatty)
+	UNIMPL_FUNC(_access)
+	UNIMPL_FUNC(_faccessat)
+	UNIMPL_FUNC(_link)
+	UNIMPL_FUNC(_unlink)
+	UNIMPL_FUNC(_execve)
+	UNIMPL_FUNC(_getpid)
+	UNIMPL_FUNC(_fork)
+	UNIMPL_FUNC(_kill)
+	UNIMPL_FUNC(_wait)
+	UNIMPL_FUNC(_times)
+	UNIMPL_FUNC(_gettimeofday)
+	UNIMPL_FUNC(_ftime)
+	UNIMPL_FUNC(_utime)
+	UNIMPL_FUNC(_chown)
+	UNIMPL_FUNC(_chmod)
+	UNIMPL_FUNC(_chdir)
+	UNIMPL_FUNC(_getcwd)
+	UNIMPL_FUNC(_sysconf)
+	"j unimplemented_syscall\n"
+);
+
+void unimplemented_syscall()
+{
+	const char *p = "Unimplemented system call called!\n";
+	while (*p)
+		*(volatile int*)0x10000000 = *(p++);
+	asm volatile ("ebreak");
+	__builtin_unreachable();
+}
+
+ssize_t _read(int file, void *ptr, size_t len)
+{
+	// always EOF
+	return 0;
+}
+
+ssize_t _write(int file, const void *ptr, size_t len)
+{
+	const void *eptr = ptr + len;
+	while (ptr != eptr)
+		*(volatile int*)0x10000000 = *(char*)(ptr++);
+	return len;
+}
+
+int _close(int file)
+{
+	// close is called before _exit()
+	return 0;
+}
+
+int _fstat(int file, struct stat *st)
+{
+	// fstat is called during libc startup
+	errno = ENOENT;
+	return -1;
+}
+
+void *_sbrk(ptrdiff_t incr)
+{
+	extern unsigned char _end[];   // Defined by linker
+	static unsigned long heap_end;
+
+	if (heap_end == 0)
+		heap_end = (long)_end;
+
+	heap_end += incr;
+	return (void *)(heap_end - incr);
+}
+
+void _exit(int exit_status)
+{
+	asm volatile ("ebreak");
+	__builtin_unreachable();
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/romload/testbench.v b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/testbench.v
new file mode 100644
index 0000000..e38819d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/romload/testbench.v
@@ -0,0 +1,140 @@
+`timescale 1 ns / 1 ps
+`undef VERBOSE_MEM
+//`undef WRITE_VCD
+`undef MEM8BIT
+
+// define the size of our ROM
+// simulates ROM by suppressing writes below this address
+`define ROM_SIZE 32'h0001_00FF
+
+module testbench;
+	reg clk = 1;
+	reg resetn = 0;
+	wire trap;
+
+	always #5 clk = ~clk;
+
+	initial begin
+		repeat (100) @(posedge clk);
+		resetn <= 1;
+	end
+
+	wire mem_valid;
+	wire mem_instr;
+	reg mem_ready;
+	wire [31:0] mem_addr;
+	wire [31:0] mem_wdata;
+	wire [3:0] mem_wstrb;
+	reg  [31:0] mem_rdata;
+
+`include "firmware_dbg.v"
+
+	picorv32 #(
+		.COMPRESSED_ISA(1),
+		.PROGADDR_RESET(32'h100)
+	) uut (
+		.clk         (clk        ),
+		.resetn      (resetn     ),
+		.trap        (trap       ),
+		.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  )
+	);
+
+	localparam MEM_SIZE = 4*1024*1024;
+`ifdef MEM8BIT
+	reg [7:0] memory [0:MEM_SIZE-1];
+	initial 
+		$readmemh("firmware.hex", memory);
+	end
+`else
+	reg [31:0] memory [0:MEM_SIZE/4-1];
+	integer x;
+
+	// simulate hardware assist of clearing RAM and copying ROM data into
+	// memory
+	initial
+	begin
+		// clear memory
+		for (x=0; x<MEM_SIZE/4; x=x+1) memory[x] = 0;
+		// load rom contents
+		$readmemh("firmware32.hex", memory);
+		// copy .data section
+		for (x=0; x<(`C_SYM__BSS_START - `C_SYM___GLOBAL_POINTER); x=x+4)
+			memory[(`C_SYM___GLOBAL_POINTER+x)/4] = memory[(`C_SYM__DATA_LMA+x)/4];
+	end
+`endif
+
+	always @(posedge clk) begin
+		mem_ready <= 0;
+		if (mem_valid && !mem_ready) begin
+			mem_ready <= 1;
+			mem_rdata <= 'bx;
+			case (1)
+				mem_addr < MEM_SIZE: begin
+`ifdef MEM8BIT
+					if (|mem_wstrb) begin
+						if (mem_wstrb[0]) memory[mem_addr + 0] <= mem_wdata[ 7: 0];
+						if (mem_wstrb[1]) memory[mem_addr + 1] <= mem_wdata[15: 8];
+						if (mem_wstrb[2]) memory[mem_addr + 2] <= mem_wdata[23:16];
+						if (mem_wstrb[3]) memory[mem_addr + 3] <= mem_wdata[31:24];
+					end else begin
+						mem_rdata <= {memory[mem_addr+3], memory[mem_addr+2], memory[mem_addr+1], memory[mem_addr]};
+					end
+`else
+					if ((|mem_wstrb) && (mem_addr >= `ROM_SIZE)) begin
+						if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
+						if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
+						if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16];
+						if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24];
+					end else begin
+						mem_rdata <= memory[mem_addr >> 2];
+					end
+`endif
+				end
+				mem_addr == 32'h 1000_0000: begin
+					$write("%c", mem_wdata[7:0]);
+				end
+			endcase
+		end
+		if (mem_valid && mem_ready) begin
+`ifdef FIRMWARE_DEBUG_ADDR
+			firmware_dbg(mem_addr);
+`endif
+			if ((mem_wstrb == 4'h0) && (mem_rdata === 32'bx)) $display("READ FROM UNITIALIZED ADDR=%x", mem_addr);
+`ifdef VERBOSE_MEM
+			if (|mem_wstrb)
+				$display("WR: ADDR=%x DATA=%x MASK=%b", mem_addr, mem_wdata, mem_wstrb);
+			else
+				$display("RD: ADDR=%x DATA=%x%s", mem_addr, mem_rdata, mem_instr ? " INSN" : "");
+`endif
+			if (^mem_addr === 1'bx ||
+					(mem_wstrb[0] && ^mem_wdata[ 7: 0] == 1'bx) ||
+					(mem_wstrb[1] && ^mem_wdata[15: 8] == 1'bx) ||
+					(mem_wstrb[2] && ^mem_wdata[23:16] == 1'bx) ||
+					(mem_wstrb[3] && ^mem_wdata[31:24] == 1'bx)) begin
+				$display("CRITICAL UNDEF MEM TRANSACTION");
+				$finish;
+			end
+		end
+	end
+
+`ifdef WRITE_VCD
+	initial begin
+		$dumpfile("testbench.vcd");
+		$dumpvars(0, testbench);
+	end
+`endif
+
+	always @(posedge clk) begin
+		if (resetn && trap) begin
+			repeat (10) @(posedge clk);
+			$display("TRAP");
+			$finish;
+		end
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/.gitignore b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/.gitignore
new file mode 100644
index 0000000..1ce906e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/.gitignore
@@ -0,0 +1,18 @@
+tracecmp.smt2
+tracecmp.yslog
+tracecmp2.smt2
+tracecmp2.yslog
+tracecmp3.blif
+tracecmp3.cex
+tracecmp3.smt2
+tracecmp3.yslog
+axicheck.smt2
+axicheck.yslog
+axicheck2.smt2
+axicheck2.yslog
+notrap_validop.smt2
+notrap_validop.yslog
+mulcmp.smt2
+mulcmp.yslog
+output.vcd
+output.smtc
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/axicheck.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/axicheck.sh
new file mode 100644
index 0000000..732b3b8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/axicheck.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -ex
+
+yosys -ql axicheck.yslog \
+	-p 'read_verilog -formal -norestrict -assume-asserts ../../picorv32.v' \
+	-p 'read_verilog -formal axicheck.v' \
+	-p 'prep -top testbench -nordff' \
+	-p 'write_smt2 -wires axicheck.smt2'
+
+yosys-smtbmc -t 50 -s boolector --dump-vcd output.vcd --dump-smtc output.smtc axicheck.smt2
+# yosys-smtbmc -t 50 -i -s boolector --dump-vcd output.vcd --dump-smtc output.smtc axicheck.smt2
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/axicheck.v b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/axicheck.v
new file mode 100644
index 0000000..80eda48
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/axicheck.v
@@ -0,0 +1,210 @@
+module testbench (
+	input         clk,
+	output        trap,
+
+	output        mem_axi_awvalid,
+	input         mem_axi_awready,
+	output [31:0] mem_axi_awaddr,
+	output [ 2:0] mem_axi_awprot,
+
+	output        mem_axi_wvalid,
+	input         mem_axi_wready,
+	output [31:0] mem_axi_wdata,
+	output [ 3:0] mem_axi_wstrb,
+
+	input         mem_axi_bvalid,
+	output        mem_axi_bready,
+
+	output        mem_axi_arvalid,
+	input         mem_axi_arready,
+	output [31:0] mem_axi_araddr,
+	output [ 2:0] mem_axi_arprot,
+
+	input         mem_axi_rvalid,
+	output        mem_axi_rready,
+	input  [31:0] mem_axi_rdata
+);
+	reg resetn = 0;
+
+	always @(posedge clk)
+		resetn <= 1;
+
+	picorv32_axi #(
+		.ENABLE_COUNTERS(1),
+		.ENABLE_COUNTERS64(1),
+		.ENABLE_REGS_16_31(1),
+		.ENABLE_REGS_DUALPORT(1),
+		.BARREL_SHIFTER(1),
+		.TWO_CYCLE_COMPARE(0),
+		.TWO_CYCLE_ALU(0),
+		.COMPRESSED_ISA(0),
+		.CATCH_MISALIGN(1),
+		.CATCH_ILLINSN(1)
+	) uut (
+		.clk             (clk            ),
+		.resetn          (resetn         ),
+		.trap            (trap           ),
+		.mem_axi_awvalid (mem_axi_awvalid),
+		.mem_axi_awready (mem_axi_awready),
+		.mem_axi_awaddr  (mem_axi_awaddr ),
+		.mem_axi_awprot  (mem_axi_awprot ),
+		.mem_axi_wvalid  (mem_axi_wvalid ),
+		.mem_axi_wready  (mem_axi_wready ),
+		.mem_axi_wdata   (mem_axi_wdata  ),
+		.mem_axi_wstrb   (mem_axi_wstrb  ),
+		.mem_axi_bvalid  (mem_axi_bvalid ),
+		.mem_axi_bready  (mem_axi_bready ),
+		.mem_axi_arvalid (mem_axi_arvalid),
+		.mem_axi_arready (mem_axi_arready),
+		.mem_axi_araddr  (mem_axi_araddr ),
+		.mem_axi_arprot  (mem_axi_arprot ),
+		.mem_axi_rvalid  (mem_axi_rvalid ),
+		.mem_axi_rready  (mem_axi_rready ),
+		.mem_axi_rdata   (mem_axi_rdata  )
+	);
+
+	reg expect_bvalid_aw = 0;
+	reg expect_bvalid_w  = 0;
+	reg expect_rvalid    = 0;
+
+	reg [3:0] timeout_aw = 0;
+	reg [3:0] timeout_w  = 0;
+	reg [3:0] timeout_b  = 0;
+	reg [3:0] timeout_ar = 0;
+	reg [3:0] timeout_r  = 0;
+	reg [3:0] timeout_ex = 0;
+
+	always @(posedge clk) begin
+		timeout_aw <= !mem_axi_awvalid || mem_axi_awready ? 0 : timeout_aw + 1;
+		timeout_w  <= !mem_axi_wvalid  || mem_axi_wready  ? 0 : timeout_w  + 1;
+		timeout_b  <= !mem_axi_bvalid  || mem_axi_bready  ? 0 : timeout_b  + 1;
+		timeout_ar <= !mem_axi_arvalid || mem_axi_arready ? 0 : timeout_ar + 1;
+		timeout_r  <= !mem_axi_rvalid  || mem_axi_rready  ? 0 : timeout_r  + 1;
+		timeout_ex <= !{expect_bvalid_aw, expect_bvalid_w, expect_rvalid} ? 0 : timeout_ex + 1;
+		restrict(timeout_aw != 15);
+		restrict(timeout_w  != 15);
+		restrict(timeout_b  != 15);
+		restrict(timeout_ar != 15);
+		restrict(timeout_r  != 15);
+		restrict(timeout_ex != 15);
+		restrict(!trap);
+
+	end
+
+	always @(posedge clk) begin
+		if (resetn) begin
+			if (!$past(resetn)) begin
+				assert(!mem_axi_awvalid);
+				assert(!mem_axi_wvalid );
+				assume(!mem_axi_bvalid );
+				assert(!mem_axi_arvalid);
+				assume(!mem_axi_rvalid );
+			end else begin
+				// Only one read/write transaction in flight at each point in time
+
+				if (expect_bvalid_aw) begin
+					assert(!mem_axi_awvalid);
+				end
+
+				if (expect_bvalid_w) begin
+					assert(!mem_axi_wvalid);
+				end
+
+				if (expect_rvalid) begin
+					assert(!mem_axi_arvalid);
+				end
+
+				expect_bvalid_aw = expect_bvalid_aw || (mem_axi_awvalid && mem_axi_awready);
+				expect_bvalid_w  = expect_bvalid_w  || (mem_axi_wvalid  && mem_axi_wready );
+				expect_rvalid    = expect_rvalid    || (mem_axi_arvalid && mem_axi_arready);
+
+				if (expect_bvalid_aw || expect_bvalid_w) begin
+					assert(!expect_rvalid);
+				end
+
+				if (expect_rvalid) begin
+					assert(!expect_bvalid_aw);
+					assert(!expect_bvalid_w);
+				end
+
+				if (!expect_bvalid_aw || !expect_bvalid_w) begin
+					assume(!mem_axi_bvalid);
+				end
+
+				if (!expect_rvalid) begin
+					assume(!mem_axi_rvalid);
+				end
+
+				if (mem_axi_bvalid && mem_axi_bready) begin
+					expect_bvalid_aw = 0;
+					expect_bvalid_w = 0;
+				end
+
+				if (mem_axi_rvalid && mem_axi_rready) begin
+					expect_rvalid = 0;
+				end
+
+				// Check AXI Master Streams
+
+				if ($past(mem_axi_awvalid && !mem_axi_awready)) begin
+					assert(mem_axi_awvalid);
+					assert($stable(mem_axi_awaddr));
+					assert($stable(mem_axi_awprot));
+				end
+				if ($fell(mem_axi_awvalid)) begin
+					assert($past(mem_axi_awready));
+				end
+				if ($fell(mem_axi_awready)) begin
+					assume($past(mem_axi_awvalid));
+				end
+
+				if ($past(mem_axi_arvalid && !mem_axi_arready)) begin
+					assert(mem_axi_arvalid);
+					assert($stable(mem_axi_araddr));
+					assert($stable(mem_axi_arprot));
+				end
+				if ($fell(mem_axi_arvalid)) begin
+					assert($past(mem_axi_arready));
+				end
+				if ($fell(mem_axi_arready)) begin
+					assume($past(mem_axi_arvalid));
+				end
+
+				if ($past(mem_axi_wvalid && !mem_axi_wready)) begin
+					assert(mem_axi_wvalid);
+					assert($stable(mem_axi_wdata));
+					assert($stable(mem_axi_wstrb));
+				end
+				if ($fell(mem_axi_wvalid)) begin
+					assert($past(mem_axi_wready));
+				end
+				if ($fell(mem_axi_wready)) begin
+					assume($past(mem_axi_wvalid));
+				end
+
+				// Check AXI Slave Streams
+
+				if ($past(mem_axi_bvalid && !mem_axi_bready)) begin
+					assume(mem_axi_bvalid);
+				end
+				if ($fell(mem_axi_bvalid)) begin
+					assume($past(mem_axi_bready));
+				end
+				if ($fell(mem_axi_bready)) begin
+					assert($past(mem_axi_bvalid));
+				end
+
+				if ($past(mem_axi_rvalid && !mem_axi_rready)) begin
+					assume(mem_axi_rvalid);
+					assume($stable(mem_axi_rdata));
+				end
+				if ($fell(mem_axi_rvalid)) begin
+					assume($past(mem_axi_rready));
+				end
+				if ($fell(mem_axi_rready)) begin
+					assert($past(mem_axi_rvalid));
+				end
+			end
+		end
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/axicheck2.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/axicheck2.sh
new file mode 100644
index 0000000..df20855
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/axicheck2.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+set -ex
+
+yosys -ql axicheck2.yslog \
+	-p 'read_verilog -formal -norestrict -assume-asserts ../../picorv32.v' \
+	-p 'read_verilog -formal axicheck2.v' \
+	-p 'prep -top testbench -nordff' \
+	-p 'write_smt2 -wires axicheck2.smt2'
+
+yosys-smtbmc -t 6 -s yices --dump-vcd output.vcd --dump-smtc output.smtc --smtc axicheck2.smtc axicheck2.smt2
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/axicheck2.smtc b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/axicheck2.smtc
new file mode 100644
index 0000000..1f8c5ea
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/axicheck2.smtc
@@ -0,0 +1,2 @@
+initial
+assume (= [uut_0] [uut_1])
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/axicheck2.v b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/axicheck2.v
new file mode 100644
index 0000000..3d24a2e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/axicheck2.v
@@ -0,0 +1,147 @@
+module testbench (
+	input         clk,
+	input         resetn,
+	output        trap_0,
+	output        trap_1,
+
+	output        mem_axi_awvalid_0,
+	input         mem_axi_awready_0,
+	output [31:0] mem_axi_awaddr_0,
+	output [ 2:0] mem_axi_awprot_0,
+
+	output        mem_axi_awvalid_1,
+	input         mem_axi_awready_1,
+	output [31:0] mem_axi_awaddr_1,
+	output [ 2:0] mem_axi_awprot_1,
+
+	output        mem_axi_wvalid_0,
+	input         mem_axi_wready_0,
+	output [31:0] mem_axi_wdata_0,
+	output [ 3:0] mem_axi_wstrb_0,
+
+	output        mem_axi_wvalid_1,
+	input         mem_axi_wready_1,
+	output [31:0] mem_axi_wdata_1,
+	output [ 3:0] mem_axi_wstrb_1,
+
+	input         mem_axi_bvalid,
+	output        mem_axi_bready_0,
+	output        mem_axi_bready_1,
+
+	output        mem_axi_arvalid_0,
+	input         mem_axi_arready_0,
+	output [31:0] mem_axi_araddr_0,
+	output [ 2:0] mem_axi_arprot_0,
+
+	output        mem_axi_arvalid_1,
+	input         mem_axi_arready_1,
+	output [31:0] mem_axi_araddr_1,
+	output [ 2:0] mem_axi_arprot_1,
+
+	input         mem_axi_rvalid,
+	output        mem_axi_rready_0,
+	output        mem_axi_rready_1,
+	input  [31:0] mem_axi_rdata
+);
+	picorv32_axi #(
+		.ENABLE_COUNTERS(1),
+		.ENABLE_COUNTERS64(1),
+		.ENABLE_REGS_16_31(1),
+		.ENABLE_REGS_DUALPORT(1),
+		.BARREL_SHIFTER(1),
+		.TWO_CYCLE_COMPARE(0),
+		.TWO_CYCLE_ALU(0),
+		.COMPRESSED_ISA(0),
+		.CATCH_MISALIGN(1),
+		.CATCH_ILLINSN(1)
+	) uut_0 (
+		.clk             (clk              ),
+		.resetn          (resetn           ),
+		.trap            (trap_0           ),
+		.mem_axi_awvalid (mem_axi_awvalid_0),
+		.mem_axi_awready (mem_axi_awready_0),
+		.mem_axi_awaddr  (mem_axi_awaddr_0 ),
+		.mem_axi_awprot  (mem_axi_awprot_0 ),
+		.mem_axi_wvalid  (mem_axi_wvalid_0 ),
+		.mem_axi_wready  (mem_axi_wready_0 ),
+		.mem_axi_wdata   (mem_axi_wdata_0  ),
+		.mem_axi_wstrb   (mem_axi_wstrb_0  ),
+		.mem_axi_bvalid  (mem_axi_bvalid   ),
+		.mem_axi_bready  (mem_axi_bready_0 ),
+		.mem_axi_arvalid (mem_axi_arvalid_0),
+		.mem_axi_arready (mem_axi_arready_0),
+		.mem_axi_araddr  (mem_axi_araddr_0 ),
+		.mem_axi_arprot  (mem_axi_arprot_0 ),
+		.mem_axi_rvalid  (mem_axi_rvalid   ),
+		.mem_axi_rready  (mem_axi_rready_0 ),
+		.mem_axi_rdata   (mem_axi_rdata    )
+	);
+
+	picorv32_axi #(
+		.ENABLE_COUNTERS(1),
+		.ENABLE_COUNTERS64(1),
+		.ENABLE_REGS_16_31(1),
+		.ENABLE_REGS_DUALPORT(1),
+		.BARREL_SHIFTER(1),
+		.TWO_CYCLE_COMPARE(0),
+		.TWO_CYCLE_ALU(0),
+		.COMPRESSED_ISA(0),
+		.CATCH_MISALIGN(1),
+		.CATCH_ILLINSN(1)
+	) uut_1 (
+		.clk             (clk              ),
+		.resetn          (resetn           ),
+		.trap            (trap_1           ),
+		.mem_axi_awvalid (mem_axi_awvalid_1),
+		.mem_axi_awready (mem_axi_awready_1),
+		.mem_axi_awaddr  (mem_axi_awaddr_1 ),
+		.mem_axi_awprot  (mem_axi_awprot_1 ),
+		.mem_axi_wvalid  (mem_axi_wvalid_1 ),
+		.mem_axi_wready  (mem_axi_wready_1 ),
+		.mem_axi_wdata   (mem_axi_wdata_1  ),
+		.mem_axi_wstrb   (mem_axi_wstrb_1  ),
+		.mem_axi_bvalid  (mem_axi_bvalid   ),
+		.mem_axi_bready  (mem_axi_bready_1 ),
+		.mem_axi_arvalid (mem_axi_arvalid_1),
+		.mem_axi_arready (mem_axi_arready_1),
+		.mem_axi_araddr  (mem_axi_araddr_1 ),
+		.mem_axi_arprot  (mem_axi_arprot_1 ),
+		.mem_axi_rvalid  (mem_axi_rvalid   ),
+		.mem_axi_rready  (mem_axi_rready_1 ),
+		.mem_axi_rdata   (mem_axi_rdata    )
+	);
+
+	always @(posedge clk) begin
+		if (resetn && $past(resetn)) begin
+			assert(trap_0            == trap_1           );
+			assert(mem_axi_awvalid_0 == mem_axi_awvalid_1);
+			assert(mem_axi_awaddr_0  == mem_axi_awaddr_1 );
+			assert(mem_axi_awprot_0  == mem_axi_awprot_1 );
+			assert(mem_axi_wvalid_0  == mem_axi_wvalid_1 );
+			assert(mem_axi_wdata_0   == mem_axi_wdata_1  );
+			assert(mem_axi_wstrb_0   == mem_axi_wstrb_1  );
+			assert(mem_axi_bready_0  == mem_axi_bready_1 );
+			assert(mem_axi_arvalid_0 == mem_axi_arvalid_1);
+			assert(mem_axi_araddr_0  == mem_axi_araddr_1 );
+			assert(mem_axi_arprot_0  == mem_axi_arprot_1 );
+			assert(mem_axi_rready_0  == mem_axi_rready_1 );
+
+			if (mem_axi_awvalid_0) assume(mem_axi_awready_0 == mem_axi_awready_1);
+			if (mem_axi_wvalid_0 ) assume(mem_axi_wready_0  == mem_axi_wready_1 );
+			if (mem_axi_arvalid_0) assume(mem_axi_arready_0 == mem_axi_arready_1);
+
+			if ($fell(mem_axi_awready_0)) assume($past(mem_axi_awvalid_0));
+			if ($fell(mem_axi_wready_0 )) assume($past(mem_axi_wvalid_0 ));
+			if ($fell(mem_axi_arready_0)) assume($past(mem_axi_arvalid_0));
+
+			if ($fell(mem_axi_awready_1)) assume($past(mem_axi_awvalid_1));
+			if ($fell(mem_axi_wready_1 )) assume($past(mem_axi_wvalid_1 ));
+			if ($fell(mem_axi_arready_1)) assume($past(mem_axi_arvalid_1));
+
+			if ($fell(mem_axi_bvalid)) assume($past(mem_axi_bready_0));
+			if ($fell(mem_axi_rvalid)) assume($past(mem_axi_rready_0));
+
+			if (mem_axi_rvalid && $past(mem_axi_rvalid)) assume($stable(mem_axi_rdata));
+		end
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/mulcmp.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/mulcmp.sh
new file mode 100644
index 0000000..586d72a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/mulcmp.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+set -ex
+
+yosys -ql mulcmp.yslog \
+        -p 'read_verilog -formal -norestrict -assume-asserts ../../picorv32.v' \
+        -p 'read_verilog -formal mulcmp.v' \
+	-p 'prep -top testbench -nordff' \
+	-p 'write_smt2 -wires mulcmp.smt2'
+
+yosys-smtbmc -s yices -t 100 --dump-vcd output.vcd --dump-smtc output.smtc mulcmp.smt2
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/mulcmp.v b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/mulcmp.v
new file mode 100644
index 0000000..20c47f3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/mulcmp.v
@@ -0,0 +1,87 @@
+module testbench(input clk, mem_ready_0, mem_ready_1);
+
+	reg resetn = 0;
+
+	always @(posedge clk)
+		resetn <= 1;
+
+	reg          pcpi_valid_0 = 1;
+	reg          pcpi_valid_1 = 1;
+
+	wire [31:0] pcpi_insn = $anyconst;
+	wire [31:0] pcpi_rs1 = $anyconst;
+	wire [31:0] pcpi_rs2 = $anyconst;
+
+	wire        pcpi_wr_0;
+	wire [31:0] pcpi_rd_0;
+	wire        pcpi_wait_0;
+	wire        pcpi_ready_0;
+
+	wire        pcpi_wr_1;
+	wire [31:0] pcpi_rd_1;
+	wire        pcpi_wait_1;
+	wire        pcpi_ready_1;
+
+	reg         pcpi_wr_ref;
+	reg  [31:0] pcpi_rd_ref;
+	reg         pcpi_ready_ref = 0;
+
+	picorv32_pcpi_mul mul_0 (
+		.clk       (clk         ),
+		.resetn    (resetn      ),
+		.pcpi_valid(pcpi_valid_0),
+		.pcpi_insn (pcpi_insn   ),
+		.pcpi_rs1  (pcpi_rs1    ),
+		.pcpi_rs2  (pcpi_rs2    ),
+		.pcpi_wr   (pcpi_wr_0   ),
+		.pcpi_rd   (pcpi_rd_0   ),
+		.pcpi_wait (pcpi_wait_0 ),
+		.pcpi_ready(pcpi_ready_0),
+
+	);
+
+	picorv32_pcpi_fast_mul mul_1 (
+		.clk       (clk         ),
+		.resetn    (resetn      ),
+		.pcpi_valid(pcpi_valid_1),
+		.pcpi_insn (pcpi_insn   ),
+		.pcpi_rs1  (pcpi_rs1    ),
+		.pcpi_rs2  (pcpi_rs2    ),
+		.pcpi_wr   (pcpi_wr_1   ),
+		.pcpi_rd   (pcpi_rd_1   ),
+		.pcpi_wait (pcpi_wait_1 ),
+		.pcpi_ready(pcpi_ready_1),
+
+	);
+
+	always @(posedge clk) begin
+		if (resetn) begin
+			if (pcpi_ready_0 && pcpi_ready_1) begin
+				assert(pcpi_wr_0 == pcpi_wr_1);
+				assert(pcpi_rd_0 == pcpi_rd_1);
+			end
+
+			if (pcpi_ready_0) begin
+				pcpi_valid_0 <= 0;
+				pcpi_wr_ref <= pcpi_wr_0;
+				pcpi_rd_ref <= pcpi_rd_0;
+				pcpi_ready_ref <= 1;
+				if (pcpi_ready_ref) begin
+					assert(pcpi_wr_0 == pcpi_wr_ref);
+					assert(pcpi_rd_0 == pcpi_rd_ref);
+				end
+			end
+
+			if (pcpi_ready_1) begin
+				pcpi_valid_1 <= 0;
+				pcpi_wr_ref <= pcpi_wr_1;
+				pcpi_rd_ref <= pcpi_rd_1;
+				pcpi_ready_ref <= 1;
+				if (pcpi_ready_ref) begin
+					assert(pcpi_wr_1 == pcpi_wr_ref);
+					assert(pcpi_rd_1 == pcpi_rd_ref);
+				end
+			end
+		end
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/notrap_validop.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/notrap_validop.sh
new file mode 100644
index 0000000..95e0f92
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/notrap_validop.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -ex
+
+yosys -ql notrap_validop.yslog \
+        -p 'read_verilog -formal -norestrict -assume-asserts ../../picorv32.v' \
+        -p 'read_verilog -formal notrap_validop.v' \
+	-p 'prep -top testbench -nordff' \
+	-p 'write_smt2 -wires notrap_validop.smt2'
+
+yosys-smtbmc -s yices -t 30 --dump-vcd output.vcd --dump-smtc output.smtc notrap_validop.smt2
+yosys-smtbmc -s yices -i -t 30 --dump-vcd output.vcd --dump-smtc output.smtc notrap_validop.smt2
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/notrap_validop.v b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/notrap_validop.v
new file mode 100644
index 0000000..8e50304
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/notrap_validop.v
@@ -0,0 +1,67 @@
+module testbench(input clk, mem_ready);
+	`include "opcode.v"
+
+	reg resetn = 0;
+	always @(posedge clk) resetn <= 1;
+
+	(* keep *) wire trap, mem_valid, mem_instr;
+	(* keep *) wire [3:0] mem_wstrb;
+	(* keep *) wire [31:0] mem_addr, mem_wdata, mem_rdata;
+	(* keep *) wire [35:0] trace_data;
+
+	reg [31:0] mem [0:2**30-1];
+
+	assign mem_rdata = mem[mem_addr >> 2];
+
+	always @(posedge clk) begin
+		if (resetn && mem_valid && mem_ready) begin
+			if (mem_wstrb[3]) mem[mem_addr >> 2][31:24] <= mem_wdata[31:24];
+			if (mem_wstrb[2]) mem[mem_addr >> 2][23:16] <= mem_wdata[23:16];
+			if (mem_wstrb[1]) mem[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
+			if (mem_wstrb[0]) mem[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
+		end
+	end
+
+	reg [1:0] mem_ready_stall = 0;
+
+	always @(posedge clk) begin
+		mem_ready_stall <= {mem_ready_stall, mem_valid && !mem_ready};
+		restrict(&mem_ready_stall == 0);
+
+		if (mem_instr && mem_ready && mem_valid) begin
+			assume(opcode_valid(mem_rdata));
+			assume(!opcode_branch(mem_rdata));
+			assume(!opcode_load(mem_rdata));
+			assume(!opcode_store(mem_rdata));
+		end
+
+		if (!mem_valid)
+			assume(!mem_ready);
+
+		if (resetn)
+			assert(!trap);
+	end
+
+	picorv32 #(
+		// change this settings as you like
+		.ENABLE_REGS_DUALPORT(1),
+		.TWO_STAGE_SHIFT(1),
+		.BARREL_SHIFTER(0),
+		.TWO_CYCLE_COMPARE(0),
+		.TWO_CYCLE_ALU(0),
+		.COMPRESSED_ISA(0),
+		.ENABLE_MUL(0),
+		.ENABLE_DIV(0)
+	) cpu (
+		.clk         (clk        ),
+		.resetn      (resetn     ),
+		.trap        (trap       ),
+		.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  )
+	);
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/opcode.v b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/opcode.v
new file mode 100644
index 0000000..7a13bd2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/opcode.v
@@ -0,0 +1,104 @@
+function opcode_jump;
+	input [31:0] opcode;
+	begin
+		opcode_jump = 0;
+		if (opcode[6:0] == 7'b1101111) opcode_jump = 1; // JAL
+		if (opcode[14:12] == 3'b000 && opcode[6:0] == 7'b1100111) opcode_jump = 1; // JALR
+	end
+endfunction
+
+function opcode_branch;
+	input [31:0] opcode;
+	begin
+		opcode_branch = 0;
+		if (opcode[14:12] == 3'b000 && opcode[6:0] == 7'b1100011) opcode_branch = 1; // BEQ
+		if (opcode[14:12] == 3'b001 && opcode[6:0] == 7'b1100011) opcode_branch = 1; // BNE
+		if (opcode[14:12] == 3'b100 && opcode[6:0] == 7'b1100011) opcode_branch = 1; // BLT
+		if (opcode[14:12] == 3'b101 && opcode[6:0] == 7'b1100011) opcode_branch = 1; // BGE
+		if (opcode[14:12] == 3'b110 && opcode[6:0] == 7'b1100011) opcode_branch = 1; // BLTU
+		if (opcode[14:12] == 3'b111 && opcode[6:0] == 7'b1100011) opcode_branch = 1; // BGEU
+	end
+endfunction
+
+function opcode_load;
+	input [31:0] opcode;
+	begin
+		opcode_load = 0;
+		if (opcode[14:12] == 3'b000 && opcode[6:0] == 7'b0000011) opcode_load = 1; // LB
+		if (opcode[14:12] == 3'b001 && opcode[6:0] == 7'b0000011) opcode_load = 1; // LH
+		if (opcode[14:12] == 3'b010 && opcode[6:0] == 7'b0000011) opcode_load = 1; // LW
+		if (opcode[14:12] == 3'b100 && opcode[6:0] == 7'b0000011) opcode_load = 1; // LBU
+		if (opcode[14:12] == 3'b101 && opcode[6:0] == 7'b0000011) opcode_load = 1; // LHU
+	end
+endfunction
+
+function opcode_store;
+	input [31:0] opcode;
+	begin
+		opcode_store = 0;
+		if (opcode[14:12] == 3'b000 && opcode[6:0] == 7'b0100011) opcode_store = 1; // SB
+		if (opcode[14:12] == 3'b001 && opcode[6:0] == 7'b0100011) opcode_store = 1; // SH
+		if (opcode[14:12] == 3'b010 && opcode[6:0] == 7'b0100011) opcode_store = 1; // SW
+	end
+endfunction
+
+function opcode_alui;
+	input [31:0] opcode;
+	begin
+		opcode_alui = 0;
+		if (opcode[14:12] == 3'b000 && opcode[6:0] == 7'b0010011) opcode_alui = 1; // ADDI
+		if (opcode[14:12] == 3'b010 && opcode[6:0] == 7'b0010011) opcode_alui = 1; // SLTI
+		if (opcode[14:12] == 3'b011 && opcode[6:0] == 7'b0010011) opcode_alui = 1; // SLTIU
+		if (opcode[14:12] == 3'b100 && opcode[6:0] == 7'b0010011) opcode_alui = 1; // XORI
+		if (opcode[14:12] == 3'b110 && opcode[6:0] == 7'b0010011) opcode_alui = 1; // ORI
+		if (opcode[14:12] == 3'b111 && opcode[6:0] == 7'b0010011) opcode_alui = 1; // ANDI
+		if (opcode[31:25] == 7'b0000000 && opcode[14:12] == 3'b001 && opcode[6:0] == 7'b0010011) opcode_alui = 1; // SLLI
+		if (opcode[31:25] == 7'b0000000 && opcode[14:12] == 3'b101 && opcode[6:0] == 7'b0010011) opcode_alui = 1; // SRLI
+		if (opcode[31:25] == 7'b0100000 && opcode[14:12] == 3'b101 && opcode[6:0] == 7'b0010011) opcode_alui = 1; // SRAI
+	end
+endfunction
+
+function opcode_alu;
+	input [31:0] opcode;
+	begin
+		opcode_alu = 0;
+		if (opcode[31:25] == 7'b0000000 && opcode[14:12] == 3'b000 && opcode[6:0] == 7'b0110011) opcode_alu = 1; // ADD
+		if (opcode[31:25] == 7'b0100000 && opcode[14:12] == 3'b000 && opcode[6:0] == 7'b0110011) opcode_alu = 1; // SUB
+		if (opcode[31:25] == 7'b0000000 && opcode[14:12] == 3'b001 && opcode[6:0] == 7'b0110011) opcode_alu = 1; // SLL
+		if (opcode[31:25] == 7'b0000000 && opcode[14:12] == 3'b010 && opcode[6:0] == 7'b0110011) opcode_alu = 1; // SLT
+		if (opcode[31:25] == 7'b0000000 && opcode[14:12] == 3'b011 && opcode[6:0] == 7'b0110011) opcode_alu = 1; // SLTU
+		if (opcode[31:25] == 7'b0000000 && opcode[14:12] == 3'b100 && opcode[6:0] == 7'b0110011) opcode_alu = 1; // XOR
+		if (opcode[31:25] == 7'b0000000 && opcode[14:12] == 3'b101 && opcode[6:0] == 7'b0110011) opcode_alu = 1; // SRL
+		if (opcode[31:25] == 7'b0100000 && opcode[14:12] == 3'b101 && opcode[6:0] == 7'b0110011) opcode_alu = 1; // SRA
+		if (opcode[31:25] == 7'b0000000 && opcode[14:12] == 3'b110 && opcode[6:0] == 7'b0110011) opcode_alu = 1; // OR
+		if (opcode[31:25] == 7'b0000000 && opcode[14:12] == 3'b111 && opcode[6:0] == 7'b0110011) opcode_alu = 1; // AND
+	end
+endfunction
+
+function opcode_sys;
+	input [31:0] opcode;
+	begin
+		opcode_sys = 0;
+		if (opcode[31:20] == 12'hC00 && opcode[19:12] == 3'b010 && opcode[6:0] == 7'b1110011) opcode_sys = 1; // RDCYCLE
+		if (opcode[31:20] == 12'hC01 && opcode[19:12] == 3'b010 && opcode[6:0] == 7'b1110011) opcode_sys = 1; // RDTIME
+		if (opcode[31:20] == 12'hC02 && opcode[19:12] == 3'b010 && opcode[6:0] == 7'b1110011) opcode_sys = 1; // RDINSTRET
+		if (opcode[31:20] == 12'hC80 && opcode[19:12] == 3'b010 && opcode[6:0] == 7'b1110011) opcode_sys = 1; // RDCYCLEH
+		if (opcode[31:20] == 12'hC81 && opcode[19:12] == 3'b010 && opcode[6:0] == 7'b1110011) opcode_sys = 1; // RDTIMEH
+		if (opcode[31:20] == 12'hC82 && opcode[19:12] == 3'b010 && opcode[6:0] == 7'b1110011) opcode_sys = 1; // RDINSTRETH
+	end
+
+endfunction
+
+function opcode_valid;
+	input [31:0] opcode;
+	begin
+		opcode_valid = 0;
+		if (opcode_jump  (opcode)) opcode_valid = 1;
+		if (opcode_branch(opcode)) opcode_valid = 1;
+		if (opcode_load  (opcode)) opcode_valid = 1;
+		if (opcode_store (opcode)) opcode_valid = 1;
+		if (opcode_alui  (opcode)) opcode_valid = 1;
+		if (opcode_alu   (opcode)) opcode_valid = 1;
+		if (opcode_sys   (opcode)) opcode_valid = 1;
+	end
+endfunction
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp.gtkw b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp.gtkw
new file mode 100644
index 0000000..09dd9b2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp.gtkw
@@ -0,0 +1,71 @@
+[*]
+[*] GTKWave Analyzer v3.3.65 (w)1999-2015 BSI
+[*] Fri Aug 26 15:42:37 2016
+[*]
+[dumpfile] "/home/clifford/Work/picorv32/scripts/smtbmc/output.vcd"
+[dumpfile_mtime] "Fri Aug 26 15:33:18 2016"
+[dumpfile_size] 80106
+[savefile] "/home/clifford/Work/picorv32/scripts/smtbmc/tracecmp.gtkw"
+[timestart] 0
+[size] 1216 863
+[pos] -1 -1
+*-2.860312 10 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] testbench.
+[sst_width] 241
+[signals_width] 337
+[sst_expanded] 1
+[sst_vpaned_height] 252
+@28
+smt_clock
+testbench.resetn
+testbench.trap_0
+testbench.trap_1
+@200
+-
+-Trace CMP
+@28
+testbench.trace_valid_0
+testbench.trace_valid_1
+@22
+testbench.trace_data_0[35:0]
+testbench.trace_data_1[35:0]
+@420
+testbench.trace_balance[7:0]
+@200
+-
+-CPU #0
+@28
+testbench.mem_valid_0
+testbench.mem_ready_0
+testbench.mem_instr_0
+@22
+testbench.mem_addr_0[31:0]
+testbench.mem_rdata_0[31:0]
+testbench.mem_wdata_0[31:0]
+@28
+testbench.mem_wstrb_0[3:0]
+@22
+testbench.cpu_0.cpu_state[7:0]
+@28
+testbench.cpu_0.mem_state[1:0]
+@200
+-
+-CPU #1
+@28
+testbench.mem_valid_1
+testbench.mem_ready_1
+testbench.mem_instr_1
+@22
+testbench.mem_addr_1[31:0]
+testbench.mem_rdata_1[31:0]
+testbench.mem_wdata_1[31:0]
+@28
+testbench.mem_wstrb_1[3:0]
+@22
+testbench.cpu_1.cpu_state[7:0]
+@28
+testbench.cpu_1.mem_state[1:0]
+@200
+-
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp.sh
new file mode 100644
index 0000000..449af52
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+set -ex
+
+yosys -ql tracecmp.yslog \
+        -p 'read_verilog -formal -norestrict -assume-asserts ../../picorv32.v' \
+        -p 'read_verilog -formal tracecmp.v' \
+	-p 'prep -top testbench -nordff' \
+	-p 'write_smt2 -wires tracecmp.smt2'
+
+yosys-smtbmc -s yices --smtc tracecmp.smtc --dump-vcd output.vcd --dump-smtc output.smtc tracecmp.smt2
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp.smtc b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp.smtc
new file mode 100644
index 0000000..477c7d0
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp.smtc
@@ -0,0 +1,12 @@
+initial
+assume (= [mem_0] [mem_1])
+assume (= [cpu_0.cpuregs] [cpu_1.cpuregs])
+assume (= [trace_data_0] [trace_data_1])
+
+always
+assume (=> (not [mem_valid_0]) (not [mem_ready_0]))
+assume (=> (not [mem_valid_1]) (not [mem_ready_1]))
+# assume (= [mem_ready_0] [mem_ready_1])
+
+always -1
+assert (=> (= [trace_balance] #x00) (= [trace_data_0] [trace_data_1]))
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp.v b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp.v
new file mode 100644
index 0000000..8ac4157
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp.v
@@ -0,0 +1,109 @@
+module testbench(input clk, mem_ready_0, mem_ready_1);
+	// set this to 1 to test generation of counter examples
+	localparam ENABLE_COUNTERS = 0;
+
+	reg resetn = 0;
+	always @(posedge clk) resetn <= 1;
+
+	(* keep *) wire trap_0, trace_valid_0, mem_valid_0, mem_instr_0;
+	(* keep *) wire [3:0] mem_wstrb_0;
+	(* keep *) wire [31:0] mem_addr_0, mem_wdata_0, mem_rdata_0;
+	(* keep *) wire [35:0] trace_data_0;
+
+	(* keep *) wire trap_1, trace_valid_1, mem_valid_1, mem_instr_1;
+	(* keep *) wire [3:0] mem_wstrb_1;
+	(* keep *) wire [31:0] mem_addr_1, mem_wdata_1, mem_rdata_1;
+	(* keep *) wire [35:0] trace_data_1;
+
+	reg [31:0] mem_0 [0:2**30-1];
+	reg [31:0] mem_1 [0:2**30-1];
+
+	assign mem_rdata_0 = mem_0[mem_addr_0 >> 2];
+	assign mem_rdata_1 = mem_1[mem_addr_1 >> 2];
+
+	always @(posedge clk) begin
+		if (resetn && mem_valid_0 && mem_ready_0) begin
+			if (mem_wstrb_0[3]) mem_0[mem_addr_0 >> 2][31:24] <= mem_wdata_0[31:24];
+			if (mem_wstrb_0[2]) mem_0[mem_addr_0 >> 2][23:16] <= mem_wdata_0[23:16];
+			if (mem_wstrb_0[1]) mem_0[mem_addr_0 >> 2][15: 8] <= mem_wdata_0[15: 8];
+			if (mem_wstrb_0[0]) mem_0[mem_addr_0 >> 2][ 7: 0] <= mem_wdata_0[ 7: 0];
+		end
+		if (resetn && mem_valid_1 && mem_ready_1) begin
+			if (mem_wstrb_1[3]) mem_1[mem_addr_1 >> 2][31:24] <= mem_wdata_1[31:24];
+			if (mem_wstrb_1[2]) mem_1[mem_addr_1 >> 2][23:16] <= mem_wdata_1[23:16];
+			if (mem_wstrb_1[1]) mem_1[mem_addr_1 >> 2][15: 8] <= mem_wdata_1[15: 8];
+			if (mem_wstrb_1[0]) mem_1[mem_addr_1 >> 2][ 7: 0] <= mem_wdata_1[ 7: 0];
+		end
+	end
+
+	(* keep *) reg [7:0] trace_balance;
+	reg [7:0] trace_balance_q;
+
+	always @* begin
+		trace_balance = trace_balance_q;
+		if (trace_valid_0) trace_balance = trace_balance + 1;
+		if (trace_valid_1) trace_balance = trace_balance - 1;
+	end
+
+	always @(posedge clk) begin
+		trace_balance_q <= resetn ? trace_balance : 0;
+	end
+
+	picorv32 #(
+		// do not change this settings
+		.ENABLE_COUNTERS(ENABLE_COUNTERS),
+		.ENABLE_TRACE(1),
+
+		// change this settings as you like
+		.ENABLE_REGS_DUALPORT(1),
+		.TWO_STAGE_SHIFT(1),
+		.BARREL_SHIFTER(0),
+		.TWO_CYCLE_COMPARE(0),
+		.TWO_CYCLE_ALU(0),
+		.COMPRESSED_ISA(0),
+		.ENABLE_MUL(0),
+		.ENABLE_DIV(0)
+	) cpu_0 (
+		.clk         (clk          ),
+		.resetn      (resetn       ),
+		.trap        (trap_0       ),
+		.mem_valid   (mem_valid_0  ),
+		.mem_instr   (mem_instr_0  ),
+		.mem_ready   (mem_ready_0  ),
+		.mem_addr    (mem_addr_0   ),
+		.mem_wdata   (mem_wdata_0  ),
+		.mem_wstrb   (mem_wstrb_0  ),
+		.mem_rdata   (mem_rdata_0  ),
+		.trace_valid (trace_valid_0),
+		.trace_data  (trace_data_0 )
+	);
+
+	picorv32 #(
+		// do not change this settings
+		.ENABLE_COUNTERS(ENABLE_COUNTERS),
+		.ENABLE_TRACE(1),
+
+		// change this settings as you like
+		.ENABLE_REGS_DUALPORT(1),
+		.TWO_STAGE_SHIFT(1),
+		.BARREL_SHIFTER(0),
+		.TWO_CYCLE_COMPARE(0),
+		.TWO_CYCLE_ALU(0),
+		.COMPRESSED_ISA(0),
+		.ENABLE_MUL(0),
+		.ENABLE_DIV(0)
+	) cpu_1 (
+		.clk         (clk          ),
+		.resetn      (resetn       ),
+		.trap        (trap_1       ),
+		.mem_valid   (mem_valid_1  ),
+		.mem_instr   (mem_instr_1  ),
+		.mem_ready   (mem_ready_1  ),
+		.mem_addr    (mem_addr_1   ),
+		.mem_wdata   (mem_wdata_1  ),
+		.mem_wstrb   (mem_wstrb_1  ),
+		.mem_rdata   (mem_rdata_1  ),
+		.trace_valid (trace_valid_1),
+		.trace_data  (trace_data_1 )
+	);
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp2.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp2.sh
new file mode 100644
index 0000000..ddaf285
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp2.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+set -ex
+
+yosys -ql tracecmp2.yslog \
+        -p 'read_verilog -formal -norestrict -assume-asserts ../../picorv32.v' \
+        -p 'read_verilog -formal tracecmp2.v' \
+	-p 'prep -top testbench -nordff' \
+	-p 'write_smt2 -wires tracecmp2.smt2'
+
+yosys-smtbmc -s boolector --smtc tracecmp2.smtc --dump-vcd output.vcd --dump-smtc output.smtc tracecmp2.smt2
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp2.smtc b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp2.smtc
new file mode 100644
index 0000000..3b7fd0a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp2.smtc
@@ -0,0 +1,2 @@
+initial
+assume (= [cpu_0.cpuregs] [cpu_1.cpuregs])
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp2.v b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp2.v
new file mode 100644
index 0000000..42f39a9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp2.v
@@ -0,0 +1,196 @@
+module testbench(
+	input clk, mem_ready_0, mem_ready_1,
+	input [31:0] mem_rdata
+);
+	// set this to 1 to test generation of counterexamples
+	localparam ENABLE_COUNTERS = 0;
+
+	reg resetn = 0;
+	always @(posedge clk) resetn <= 1;
+
+	(* keep *) wire trap_0, trace_valid_0, mem_valid_0, mem_instr_0;
+	(* keep *) wire [3:0] mem_wstrb_0;
+	(* keep *) wire [31:0] mem_addr_0, mem_wdata_0, mem_rdata_0;
+	(* keep *) wire [35:0] trace_data_0;
+
+	(* keep *) wire trap_1, trace_valid_1, mem_valid_1, mem_instr_1;
+	(* keep *) wire [3:0] mem_wstrb_1;
+	(* keep *) wire [31:0] mem_addr_1, mem_wdata_1, mem_rdata_1;
+	(* keep *) wire [35:0] trace_data_1;
+
+	reg [31:0] last_mem_rdata;
+
+	assign mem_rdata_0 = mem_rdata;
+	assign mem_rdata_1 = mem_rdata;
+
+	wire mem_xfer_0 = resetn && mem_valid_0 && mem_ready_0;
+	wire mem_xfer_1 = resetn && mem_valid_1 && mem_ready_1;
+
+	reg [1:0] cmp_mem_state = 0;
+	reg [31:0] cmp_mem_addr;
+	reg [31:0] cmp_mem_wdata;
+	reg [3:0] cmp_mem_wstrb;
+
+	always @* begin
+		if (mem_valid_0 == 0)
+			assume(!mem_ready_0 == 0);
+		if (mem_valid_1 == 0)
+			assume(mem_ready_1 == 0);
+	end
+
+	always @(posedge clk) begin
+		if (cmp_mem_state)
+			assume(last_mem_rdata == mem_rdata);
+		last_mem_rdata <= mem_rdata;
+	end
+
+	always @(posedge clk) begin
+		case (cmp_mem_state)
+			2'b 00: begin
+				case ({mem_xfer_1, mem_xfer_0})
+					2'b 11: begin
+						assert(mem_addr_0 == mem_addr_1);
+						assert(mem_wstrb_0 == mem_wstrb_1);
+						if (mem_wstrb_0[3]) assert(mem_wdata_0[31:24] == mem_wdata_1[31:24]);
+						if (mem_wstrb_0[2]) assert(mem_wdata_0[23:16] == mem_wdata_1[23:16]);
+						if (mem_wstrb_0[1]) assert(mem_wdata_0[15: 8] == mem_wdata_1[15: 8]);
+						if (mem_wstrb_0[0]) assert(mem_wdata_0[ 7: 0] == mem_wdata_1[ 7: 0]);
+					end
+					2'b 01: begin
+						cmp_mem_state <= 2'b 01;
+						cmp_mem_addr <= mem_addr_0;
+						cmp_mem_wdata <= mem_wdata_0;
+						cmp_mem_wstrb <= mem_wstrb_0;
+					end
+					2'b 10: begin
+						cmp_mem_state <= 2'b 10;
+						cmp_mem_addr <= mem_addr_1;
+						cmp_mem_wdata <= mem_wdata_1;
+						cmp_mem_wstrb <= mem_wstrb_1;
+					end
+				endcase
+			end
+			2'b 01: begin
+				assume(!mem_xfer_0);
+				if (mem_xfer_1) begin
+					cmp_mem_state <= 2'b 00;
+					assert(cmp_mem_addr == mem_addr_1);
+					assert(cmp_mem_wstrb == mem_wstrb_1);
+					if (cmp_mem_wstrb[3]) assert(cmp_mem_wdata[31:24] == mem_wdata_1[31:24]);
+					if (cmp_mem_wstrb[2]) assert(cmp_mem_wdata[23:16] == mem_wdata_1[23:16]);
+					if (cmp_mem_wstrb[1]) assert(cmp_mem_wdata[15: 8] == mem_wdata_1[15: 8]);
+					if (cmp_mem_wstrb[0]) assert(cmp_mem_wdata[ 7: 0] == mem_wdata_1[ 7: 0]);
+				end
+			end
+			2'b 10: begin
+				assume(!mem_xfer_1);
+				if (mem_xfer_0) begin
+					cmp_mem_state <= 2'b 00;
+					assert(cmp_mem_addr == mem_addr_0);
+					assert(cmp_mem_wstrb == mem_wstrb_0);
+					if (cmp_mem_wstrb[3]) assert(cmp_mem_wdata[31:24] == mem_wdata_0[31:24]);
+					if (cmp_mem_wstrb[2]) assert(cmp_mem_wdata[23:16] == mem_wdata_0[23:16]);
+					if (cmp_mem_wstrb[1]) assert(cmp_mem_wdata[15: 8] == mem_wdata_0[15: 8]);
+					if (cmp_mem_wstrb[0]) assert(cmp_mem_wdata[ 7: 0] == mem_wdata_0[ 7: 0]);
+				end
+			end
+		endcase
+	end
+
+	reg [1:0] cmp_trace_state = 0;
+	reg [35:0] cmp_trace_data;
+
+	always @(posedge clk) begin
+		if (resetn) begin
+			case (cmp_trace_state)
+				2'b 00: begin
+					case ({trace_valid_1, trace_valid_0})
+						2'b 11: begin
+							assert(trace_data_0 == trace_data_1);
+						end
+						2'b 01: begin
+							cmp_trace_state <= 2'b 01;
+							cmp_trace_data <= trace_data_0;
+						end
+						2'b 10: begin
+							cmp_trace_state <= 2'b 10;
+							cmp_trace_data <= trace_data_1;
+						end
+					endcase
+				end
+				2'b 01: begin
+					assume(!trace_valid_0);
+					if (trace_valid_1) begin
+						cmp_trace_state <= 2'b 00;
+						assert(cmp_trace_data == trace_data_1);
+					end
+				end
+				2'b 10: begin
+					assume(!trace_valid_1);
+					if (trace_valid_0) begin
+						cmp_trace_state <= 2'b 00;
+						assert(cmp_trace_data == trace_data_0);
+					end
+				end
+			endcase
+		end
+	end
+
+	picorv32 #(
+		// do not change this settings
+		.ENABLE_COUNTERS(ENABLE_COUNTERS),
+		.ENABLE_TRACE(1),
+
+		// change this settings as you like
+		.ENABLE_REGS_DUALPORT(1),
+		.TWO_STAGE_SHIFT(0),
+		.BARREL_SHIFTER(0),
+		.TWO_CYCLE_COMPARE(0),
+		.TWO_CYCLE_ALU(0),
+		.COMPRESSED_ISA(1),
+		.ENABLE_MUL(0),
+		.ENABLE_DIV(0)
+	) cpu_0 (
+		.clk         (clk          ),
+		.resetn      (resetn       ),
+		.trap        (trap_0       ),
+		.mem_valid   (mem_valid_0  ),
+		.mem_instr   (mem_instr_0  ),
+		.mem_ready   (mem_ready_0  ),
+		.mem_addr    (mem_addr_0   ),
+		.mem_wdata   (mem_wdata_0  ),
+		.mem_wstrb   (mem_wstrb_0  ),
+		.mem_rdata   (mem_rdata_0  ),
+		.trace_valid (trace_valid_0),
+		.trace_data  (trace_data_0 )
+	);
+
+	picorv32 #(
+		// do not change this settings
+		.ENABLE_COUNTERS(ENABLE_COUNTERS),
+		.ENABLE_TRACE(1),
+
+		// change this settings as you like
+		.ENABLE_REGS_DUALPORT(1),
+		.TWO_STAGE_SHIFT(1),
+		.BARREL_SHIFTER(0),
+		.TWO_CYCLE_COMPARE(0),
+		.TWO_CYCLE_ALU(0),
+		.COMPRESSED_ISA(1),
+		.ENABLE_MUL(0),
+		.ENABLE_DIV(0)
+	) cpu_1 (
+		.clk         (clk          ),
+		.resetn      (resetn       ),
+		.trap        (trap_1       ),
+		.mem_valid   (mem_valid_1  ),
+		.mem_instr   (mem_instr_1  ),
+		.mem_ready   (mem_ready_1  ),
+		.mem_addr    (mem_addr_1   ),
+		.mem_wdata   (mem_wdata_1  ),
+		.mem_wstrb   (mem_wstrb_1  ),
+		.mem_rdata   (mem_rdata_1  ),
+		.trace_valid (trace_valid_1),
+		.trace_data  (trace_data_1 )
+	);
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp3.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp3.sh
new file mode 100644
index 0000000..bfa0b3c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp3.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -ex
+
+yosys -l tracecmp3.yslog \
+        -p 'read_verilog ../../picorv32.v' \
+        -p 'read_verilog -formal tracecmp3.v' \
+	-p 'prep -top testbench -nordff' \
+	-p 'write_smt2 -wires tracecmp3.smt2' \
+	-p 'miter -assert -flatten testbench miter' \
+	-p 'hierarchy -top miter; memory_map; opt -full' \
+	-p 'techmap; opt; abc; opt -fast' \
+	-p 'write_blif tracecmp3.blif'
+
+yosys-abc -c 'read_blif tracecmp3.blif; undc; strash; zero; sim3 -v; undc -c; write_cex -n tracecmp3.cex'
+yosys-smtbmc -s yices --cex tracecmp3.cex --dump-vcd output.vcd --dump-smtc output.smtc tracecmp3.smt2
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp3.v b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp3.v
new file mode 100644
index 0000000..a1bb63b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/smtbmc/tracecmp3.v
@@ -0,0 +1,135 @@
+// Based on the benchmark from 2016 Yosys-SMTBMC presentation, which in turn is
+// based on the tracecmp2 test from this directory.
+
+module testbench (
+	input clk,
+	input [31:0] mem_rdata_in,
+
+	input             pcpi_wr,
+	input      [31:0] pcpi_rd,
+	input             pcpi_wait,
+	input             pcpi_ready
+);
+	reg resetn = 0;
+
+	always @(posedge clk)
+		resetn <= 1;
+
+	wire        cpu0_trap;
+	wire        cpu0_mem_valid;
+	wire        cpu0_mem_instr;
+	wire        cpu0_mem_ready;
+	wire [31:0] cpu0_mem_addr;
+	wire [31:0] cpu0_mem_wdata;
+	wire [3:0]  cpu0_mem_wstrb;
+	wire [31:0] cpu0_mem_rdata;
+	wire        cpu0_trace_valid;
+	wire [35:0] cpu0_trace_data;
+
+	wire        cpu1_trap;
+	wire        cpu1_mem_valid;
+	wire        cpu1_mem_instr;
+	wire        cpu1_mem_ready;
+	wire [31:0] cpu1_mem_addr;
+	wire [31:0] cpu1_mem_wdata;
+	wire [3:0]  cpu1_mem_wstrb;
+	wire [31:0] cpu1_mem_rdata;
+	wire        cpu1_trace_valid;
+	wire [35:0] cpu1_trace_data;
+
+	wire        mem_ready;
+	wire [31:0] mem_rdata;
+
+	assign mem_ready = cpu0_mem_valid && cpu1_mem_valid;
+	assign mem_rdata = mem_rdata_in;
+
+	assign cpu0_mem_ready = mem_ready;
+	assign cpu0_mem_rdata = mem_rdata;
+
+	assign cpu1_mem_ready = mem_ready;
+	assign cpu1_mem_rdata = mem_rdata;
+
+	reg [ 2:0] trace_balance = 3'b010;
+	reg [35:0] trace_buffer_cpu0 = 0, trace_buffer_cpu1 = 0;
+
+	always @(posedge clk) begin
+		if (resetn) begin
+			if (cpu0_trace_valid)
+				trace_buffer_cpu0 <= cpu0_trace_data;
+
+			if (cpu1_trace_valid)
+				trace_buffer_cpu1 <= cpu1_trace_data;
+
+			if (cpu0_trace_valid && !cpu1_trace_valid)
+				trace_balance <= trace_balance << 1;
+
+			if (!cpu0_trace_valid && cpu1_trace_valid)
+				trace_balance <= trace_balance >> 1;
+		end
+	end
+
+	always @* begin
+		if (resetn && cpu0_mem_ready) begin
+			assert(cpu0_mem_addr == cpu1_mem_addr);
+			assert(cpu0_mem_wstrb == cpu1_mem_wstrb);
+			if (cpu0_mem_wstrb[3]) assert(cpu0_mem_wdata[31:24] == cpu1_mem_wdata[31:24]);
+			if (cpu0_mem_wstrb[2]) assert(cpu0_mem_wdata[23:16] == cpu1_mem_wdata[23:16]);
+			if (cpu0_mem_wstrb[1]) assert(cpu0_mem_wdata[15: 8] == cpu1_mem_wdata[15: 8]);
+			if (cpu0_mem_wstrb[0]) assert(cpu0_mem_wdata[ 7: 0] == cpu1_mem_wdata[ 7: 0]);
+		end
+		if (trace_balance == 3'b010) begin
+			assert(trace_buffer_cpu0 == trace_buffer_cpu1);
+		end
+	end
+
+	picorv32 #(
+		.ENABLE_COUNTERS(0),
+		.REGS_INIT_ZERO(1),
+		.COMPRESSED_ISA(1),
+		.ENABLE_TRACE(1),
+
+		.TWO_STAGE_SHIFT(0),
+		.ENABLE_PCPI(1)
+	) cpu0 (
+		.clk         (clk             ),
+		.resetn      (resetn          ),
+		.trap        (cpu0_trap       ),
+		.mem_valid   (cpu0_mem_valid  ),
+		.mem_instr   (cpu0_mem_instr  ),
+		.mem_ready   (cpu0_mem_ready  ),
+		.mem_addr    (cpu0_mem_addr   ),
+		.mem_wdata   (cpu0_mem_wdata  ),
+		.mem_wstrb   (cpu0_mem_wstrb  ),
+		.mem_rdata   (cpu0_mem_rdata  ),
+		.pcpi_wr     (pcpi_wr         ),
+		.pcpi_rd     (pcpi_rd         ),
+		.pcpi_wait   (pcpi_wait       ),
+		.pcpi_ready  (pcpi_ready      ),
+		.trace_valid (cpu0_trace_valid),
+		.trace_data  (cpu0_trace_data )
+	);
+
+	picorv32 #(
+		.ENABLE_COUNTERS(0),
+		.REGS_INIT_ZERO(1),
+		.COMPRESSED_ISA(1),
+		.ENABLE_TRACE(1),
+
+		.TWO_STAGE_SHIFT(1),
+		.TWO_CYCLE_COMPARE(1),
+		.TWO_CYCLE_ALU(1)
+	) cpu1 (
+		.clk         (clk             ),
+		.resetn      (resetn          ),
+		.trap        (cpu1_trap       ),
+		.mem_valid   (cpu1_mem_valid  ),
+		.mem_instr   (cpu1_mem_instr  ),
+		.mem_ready   (cpu1_mem_ready  ),
+		.mem_addr    (cpu1_mem_addr   ),
+		.mem_wdata   (cpu1_mem_wdata  ),
+		.mem_wstrb   (cpu1_mem_wstrb  ),
+		.mem_rdata   (cpu1_mem_rdata  ),
+		.trace_valid (cpu1_trace_valid),
+		.trace_data  (cpu1_trace_data )
+	);
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/.gitignore b/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/.gitignore
new file mode 100644
index 0000000..c1e6b04
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/.gitignore
@@ -0,0 +1,15 @@
+testbench_a
+testbench_b
+testbench_c
+testbench_d
+testbench_e
+testbench_f
+testbench_g
+testbench_h
+testbench_i
+testbench_j
+testbench_k
+testbench_l
+testgen.tgz
+testgen
+tests
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/README b/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/README
new file mode 100644
index 0000000..4e12ba8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/README
@@ -0,0 +1,7 @@
+
+Testing PicoRV32 using the test case generator from
+the Tom Thumb RISC-V CPU project:
+
+https://github.com/maikmerten/riscv-tomthumb
+https://github.com/maikmerten/riscv-tomthumb-testgen
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/run.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/run.sh
new file mode 100644
index 0000000..63a6935
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/run.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+set -ex
+
+if [ ! -f testgen.tgz ]; then
+	rm -f testgen.tgz.part
+	wget -O testgen.tgz.part http://maikmerten.de/testgen.tgz
+	mv testgen.tgz.part testgen.tgz
+fi
+
+rm -rf tests testgen/
+tar xvzf testgen.tgz
+
+iverilog -o testbench_a -s testbench testbench.v ../../picorv32.v -DTWO_STAGE_SHIFT=0 -DBARREL_SHIFTER=0 -DTWO_CYCLE_COMPARE=0 -DTWO_CYCLE_ALU=0
+iverilog -o testbench_b -s testbench testbench.v ../../picorv32.v -DTWO_STAGE_SHIFT=1 -DBARREL_SHIFTER=0 -DTWO_CYCLE_COMPARE=0 -DTWO_CYCLE_ALU=0
+iverilog -o testbench_c -s testbench testbench.v ../../picorv32.v -DTWO_STAGE_SHIFT=0 -DBARREL_SHIFTER=1 -DTWO_CYCLE_COMPARE=0 -DTWO_CYCLE_ALU=0
+
+iverilog -o testbench_d -s testbench testbench.v ../../picorv32.v -DTWO_STAGE_SHIFT=0 -DBARREL_SHIFTER=0 -DTWO_CYCLE_COMPARE=1 -DTWO_CYCLE_ALU=0
+iverilog -o testbench_e -s testbench testbench.v ../../picorv32.v -DTWO_STAGE_SHIFT=1 -DBARREL_SHIFTER=0 -DTWO_CYCLE_COMPARE=1 -DTWO_CYCLE_ALU=0
+iverilog -o testbench_f -s testbench testbench.v ../../picorv32.v -DTWO_STAGE_SHIFT=0 -DBARREL_SHIFTER=1 -DTWO_CYCLE_COMPARE=1 -DTWO_CYCLE_ALU=0
+
+iverilog -o testbench_g -s testbench testbench.v ../../picorv32.v -DTWO_STAGE_SHIFT=0 -DBARREL_SHIFTER=0 -DTWO_CYCLE_COMPARE=0 -DTWO_CYCLE_ALU=1
+iverilog -o testbench_h -s testbench testbench.v ../../picorv32.v -DTWO_STAGE_SHIFT=1 -DBARREL_SHIFTER=0 -DTWO_CYCLE_COMPARE=0 -DTWO_CYCLE_ALU=1
+iverilog -o testbench_i -s testbench testbench.v ../../picorv32.v -DTWO_STAGE_SHIFT=0 -DBARREL_SHIFTER=1 -DTWO_CYCLE_COMPARE=0 -DTWO_CYCLE_ALU=1
+
+iverilog -o testbench_j -s testbench testbench.v ../../picorv32.v -DTWO_STAGE_SHIFT=0 -DBARREL_SHIFTER=0 -DTWO_CYCLE_COMPARE=1 -DTWO_CYCLE_ALU=1
+iverilog -o testbench_k -s testbench testbench.v ../../picorv32.v -DTWO_STAGE_SHIFT=1 -DBARREL_SHIFTER=0 -DTWO_CYCLE_COMPARE=1 -DTWO_CYCLE_ALU=1
+iverilog -o testbench_l -s testbench testbench.v ../../picorv32.v -DTWO_STAGE_SHIFT=0 -DBARREL_SHIFTER=1 -DTWO_CYCLE_COMPARE=1 -DTWO_CYCLE_ALU=1
+
+mkdir -p tests
+for i in {0..999}; do
+	fn="tests/test_`printf '%03d' $i`"
+
+	{
+		cat start.S
+		java -jar testgen/tomthumb-testgen-1.0-SNAPSHOT.jar
+	} > $fn.s
+
+	riscv32-unknown-elf-gcc -ffreestanding -nostdlib -Wl,-Bstatic,-T,sections.lds -o $fn.elf $fn.s
+	riscv32-unknown-elf-objcopy -O binary $fn.elf $fn.bin
+	python3 ../../firmware/makehex.py $fn.bin 16384 > $fn.hex
+	for tb in testbench_{a,b,c,d,e,f,g,h,i,j,k,l}; do vvp -N $tb +hex=$fn.hex; done
+done
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/sections.lds b/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/sections.lds
new file mode 100644
index 0000000..8962f5c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/sections.lds
@@ -0,0 +1,7 @@
+SECTIONS {
+	.memory : {
+		. = 0;
+		*(.text);
+		*(*);
+	}
+}
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/start.S b/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/start.S
new file mode 100644
index 0000000..541c8a4
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/start.S
@@ -0,0 +1,57 @@
+.section .text.start
+.global testcollection
+
+/* zero-initialize all registers */
+addi x1, zero, 0
+addi x2, zero, 0
+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
+
+/* set stack pointer */
+lui sp, %hi(64*1024)
+addi sp, sp, %lo(64*1024)
+
+/* push zeros on the stack for argc and argv */
+/* (stack is aligned to 16 bytes in riscv calling convention) */
+addi sp,sp,-16
+sw zero,0(sp)
+sw zero,4(sp)
+sw zero,8(sp)
+sw zero,12(sp)
+
+/* call test */
+call testcollection
+
+/* write test results */
+lui x1, %hi(0x10000000)
+addi x1, x1, %lo(0x10000000)
+sw x5, 0(x1)
+
+ebreak
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/testbench.v b/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/testbench.v
new file mode 100644
index 0000000..c39ebca
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/tomthumbtg/testbench.v
@@ -0,0 +1,83 @@
+`timescale 1 ns / 1 ps
+
+module testbench;
+	reg clk = 1;
+	reg resetn = 0;
+	wire trap;
+
+	always #5 clk = ~clk;
+
+	initial begin
+		repeat (100) @(posedge clk);
+		resetn <= 1;
+	end
+
+	wire mem_valid;
+	wire mem_instr;
+	reg mem_ready;
+	wire [31:0] mem_addr;
+	wire [31:0] mem_wdata;
+	wire [3:0] mem_wstrb;
+	reg  [31:0] mem_rdata;
+
+	picorv32 #(
+		.TWO_STAGE_SHIFT(`TWO_STAGE_SHIFT),
+		.BARREL_SHIFTER(`BARREL_SHIFTER),
+		.TWO_CYCLE_COMPARE(`TWO_CYCLE_COMPARE),
+		.TWO_CYCLE_ALU(`TWO_CYCLE_ALU)
+	) uut (
+		.clk         (clk        ),
+		.resetn      (resetn     ),
+		.trap        (trap       ),
+		.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  )
+	);
+
+	reg [31:0] memory [0:16*1024-1];
+	reg [1023:0] hex_filename;
+
+	initial begin
+		if ($value$plusargs("hex=%s", hex_filename))
+			$readmemh(hex_filename, memory);
+	end
+
+	initial begin
+		// $dumpfile("testbench.vcd");
+		// $dumpvars(0, testbench);
+	end
+
+	always @(posedge clk) begin
+		if (resetn && trap) begin
+			repeat (10) @(posedge clk);
+			$display("TRAP");
+			$stop;
+		end
+	end
+
+	always @(posedge clk) begin
+		mem_ready <= 0;
+		if (mem_valid && !mem_ready) begin
+			mem_ready <= 1;
+			if (mem_addr == 32'h 1000_0000) begin
+				if (mem_wdata != -32'd1) begin
+					$display("Failed test case: %d", mem_wdata);
+					$stop;
+				end else begin
+					$display("OK.");
+					$finish;
+				end
+			end else begin
+				mem_rdata <= memory[mem_addr >> 2];
+				if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
+				if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
+				if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16];
+				if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24];
+			end
+		end
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/torture/.gitignore b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/.gitignore
new file mode 100644
index 0000000..b58f70b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/.gitignore
@@ -0,0 +1,14 @@
+.looplog
+riscv-fesvr
+riscv-isa-sim
+riscv-torture
+config.vh
+obj_dir
+tests
+test.S
+test.elf
+test.bin
+test.hex
+test.ref
+test.vvp
+test.vcd
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/torture/Makefile b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/Makefile
new file mode 100644
index 0000000..4dd075c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/Makefile
@@ -0,0 +1,101 @@
+
+# Icarus Verilog
+#TESTBENCH_EXE = tests/testbench.vvp
+
+# Verilator
+TESTBENCH_EXE = obj_dir/Vtestbench
+
+test: riscv-torture/build.ok riscv-isa-sim/build.ok
+	bash test.sh
+
+riscv-torture/build.ok: riscv-torture-rv32.diff
+	rm -rf riscv-torture
+	git clone https://github.com/ucb-bar/riscv-torture.git riscv-torture
+	cd riscv-torture && git checkout 2bc0c42
+	cd riscv-torture && patch -p1 < ../riscv-torture-rv32.diff
+	cd riscv-torture && patch -p1 < ../riscv-torture-genloop.diff
+	cd riscv-torture && ./sbt generator/run && touch build.ok
+
+riscv-fesvr/build.ok:
+	rm -rf riscv-fesvr
+	git clone https://github.com/riscv/riscv-fesvr.git riscv-fesvr
+	+cd riscv-fesvr && git checkout 1c02bd6 && ./configure && make && touch build.ok
+
+riscv-isa-sim/build.ok: riscv-fesvr/build.ok
+	rm -rf riscv-isa-sim
+	git clone https://github.com/riscv/riscv-isa-sim.git riscv-isa-sim
+	cd riscv-isa-sim && git checkout 10ae74e
+	cd riscv-isa-sim && patch -p1 < ../riscv-isa-sim-sbreak.diff
+	cd riscv-isa-sim && patch -p1 < ../riscv-isa-sim-notrap.diff
+	cd riscv-isa-sim && LDFLAGS="-L../riscv-fesvr" ./configure --with-isa=RV32IMC
+	+cd riscv-isa-sim && ln -s ../riscv-fesvr/fesvr . && make && touch build.ok
+
+batch_size = 1000
+batch_list = $(shell bash -c 'for i in {0..$(shell expr $(batch_size) - 1)}; do printf "%03d\n" $$i; done')
+
+batch: $(addprefix tests/test_,$(addsuffix .ok,$(batch_list)))
+
+config.vh: config.py riscv-torture/build.ok
+	python3 config.py
+
+obj_dir/Vtestbench: testbench.v testbench.cc ../../picorv32.v config.vh
+	verilator --exe -Wno-fatal -DDEBUGASM --cc --top-module testbench testbench.v ../../picorv32.v testbench.cc
+	$(MAKE) -C obj_dir -f Vtestbench.mk
+
+tests/testbench.vvp: testbench.v ../../picorv32.v
+	mkdir -p tests
+	iverilog -o tests/testbench.vvp testbench.v ../../picorv32.v
+
+tests/generated.ok: config.vh riscv-torture/build.ok
+	mkdir -p tests
+	rm -f riscv-torture/output/test_*
+	cd riscv-torture && ./sbt 'generator/run -C config/test.config -n $(batch_size)'
+	touch tests/generated.ok
+
+define test_template
+tests/test_$(1).S: tests/generated.ok
+	mv riscv-torture/output/test_$(1).S tests/
+	touch tests/test_$(1).S
+
+tests/test_$(1).elf: tests/test_$(1).S
+	riscv32-unknown-elf-gcc `sed '/march=/ ! d; s,^// ,-,; y/RVIMC/rvimc/;' config.vh` -ffreestanding -nostdlib \
+			-Wl,-Bstatic,-T,sections.lds -I. -o tests/test_$(1).elf tests/test_$(1).S
+
+tests/test_$(1).bin: tests/test_$(1).elf
+	riscv32-unknown-elf-objcopy -O binary tests/test_$(1).elf tests/test_$(1).bin
+
+tests/test_$(1).dmp: tests/test_$(1).elf
+	riscv32-unknown-elf-objdump -d tests/test_$(1).elf > tests/test_$(1).dmp
+
+tests/test_$(1).hex: tests/test_$(1).bin
+	python3 ../../firmware/makehex.py tests/test_$(1).bin 4096 > tests/test_$(1).hex
+
+tests/test_$(1).ref: tests/test_$(1).elf riscv-isa-sim/build.ok
+	LD_LIBRARY_PATH="./riscv-isa-sim:./riscv-fesvr" ./riscv-isa-sim/spike tests/test_$(1).elf > tests/test_$(1).ref
+
+tests/test_$(1).ok: $(TESTBENCH_EXE) tests/test_$(1).hex tests/test_$(1).ref tests/test_$(1).dmp
+	$(TESTBENCH_EXE) +hex=tests/test_$(1).hex +ref=tests/test_$(1).ref > tests/test_$(1).out
+	grep -q PASSED tests/test_$(1).out || { cat tests/test_$(1).out; false; }
+	python3 asmcheck.py tests/test_$(1).out tests/test_$(1).dmp
+	mv tests/test_$(1).out tests/test_$(1).ok
+endef
+
+$(foreach id,$(batch_list),$(eval $(call test_template,$(id))))
+
+loop:
+	date +"%s %Y-%m-%d %H:%M:%S START" >> .looplog
+	+set -ex; while true; do \
+	  rm -rf tests obj_dir config.vh; $(MAKE) batch; \
+	  date +"%s %Y-%m-%d %H:%M:%S NEXT" >> .looplog; \
+	done
+
+clean:
+	rm -rf tests obj_dir
+	rm -f config.vh test.S test.elf test.bin
+	rm -f test.hex test.ref test.vvp test.vcd
+
+mrproper: clean
+	rm -rf riscv-torture riscv-fesvr riscv-isa-sim
+
+.PHONY: test batch loop clean mrproper
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/torture/README b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/README
new file mode 100644
index 0000000..d62671d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/README
@@ -0,0 +1,6 @@
+Use UCB-BAR's RISC-V Torture Test Generator to test PicoRV32.
+
+You might need to install the following addition dependecies:
+
+sudo apt-get install python3-pip
+pip3 install numpy
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/torture/asmcheck.py b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/asmcheck.py
new file mode 100644
index 0000000..8a22c67
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/asmcheck.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+
+import sys, re
+
+dmp_pattern = re.compile('^\s+([0-9a-f]+):\s+([0-9a-f]+)\s+(\S+)')
+disassembled_elf = dict()
+
+def match_insns(s1, s2):
+    if s1 == "*" or s1 == s2: return True
+    if s1 == "jal" and s2.startswith("j"): return True
+    if s1 == "addi" and s2 in ["li", "mv"]: return True
+    if s1 == "xori" and s2 == "not": return True
+    if s1 == "sub" and s2 == "neg": return True
+    if s1.startswith("b") and s2.startswith("b"): return True
+    if s1.startswith("s") and s2.startswith("s"): return True
+    print(s1, s2)
+    return False
+
+with open(sys.argv[2], "r") as f:
+    for line in f:
+        match = dmp_pattern.match(line)
+        if match:
+            addr = match.group(1).rjust(8, '0')
+            opcode = match.group(2).rjust(8, '0')
+            insn = match.group(3)
+            disassembled_elf[addr] = (opcode, insn)
+
+with open(sys.argv[1], "r") as f:
+    for line in f:
+        line = line.split()
+        if len(line) < 1 or line[0] != "debugasm":
+            continue
+        assert(line[1] in disassembled_elf)
+        assert(line[2] == disassembled_elf[line[1]][0])
+        assert(match_insns(line[3], disassembled_elf[line[1]][1]))
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/torture/config.py b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/config.py
new file mode 100644
index 0000000..478f046
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/config.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+
+import numpy as np
+
+compressed_isa = np.random.randint(2)
+enable_mul = np.random.randint(2)
+enable_div = np.random.randint(2)
+
+with open("config.vh", "w") as f:
+    print("// march=RV32I%s%s" % (
+            "M" if enable_mul or enable_div else "",
+            "C" if compressed_isa else ""), file=f)
+    print(".ENABLE_COUNTERS(%d)," % np.random.randint(2), file=f)
+    print(".ENABLE_COUNTERS64(%d)," % np.random.randint(2), file=f)
+    print(".ENABLE_REGS_DUALPORT(%d)," % np.random.randint(2), file=f)
+    print(".TWO_STAGE_SHIFT(%d)," % np.random.randint(2), file=f)
+    print(".BARREL_SHIFTER(%d)," % np.random.randint(2), file=f)
+    print(".TWO_CYCLE_COMPARE(%d)," % np.random.randint(2), file=f)
+    print(".TWO_CYCLE_ALU(%d)," % np.random.randint(2), file=f)
+    print(".CATCH_MISALIGN(%d)," % np.random.randint(2), file=f)
+    print(".CATCH_ILLINSN(%d)," % np.random.randint(2), file=f)
+    print(".COMPRESSED_ISA(%d)," % compressed_isa, file=f)
+    print(".ENABLE_MUL(%d)," % enable_mul, file=f)
+    print(".ENABLE_DIV(%d)" % enable_div, file=f)
+
+with open("riscv-torture/config/default.config", "r") as fi:
+    with open("riscv-torture/config/test.config", "w") as fo:
+        for line in fi:
+            line = line.strip()
+            if line.startswith("torture.generator.mul "):
+                line = "torture.generator.mul       %s" % ("true" if enable_mul else "false")
+            if line.startswith("torture.generator.divider "):
+                line = "torture.generator.divider   %s" % ("true" if enable_div else "false")
+            print(line, file=fo)
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/torture/riscv-isa-sim-notrap.diff b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/riscv-isa-sim-notrap.diff
new file mode 100644
index 0000000..df7c059
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/riscv-isa-sim-notrap.diff
@@ -0,0 +1,16 @@
+diff --git a/riscv/processor.cc b/riscv/processor.cc
+index 3b834c5..e112029 100644
+--- a/riscv/processor.cc
++++ b/riscv/processor.cc
+@@ -201,9 +201,10 @@ void processor_t::set_privilege(reg_t prv)
+ 
+ void processor_t::take_trap(trap_t& t, reg_t epc)
+ {
+-  if (debug)
++  // if (debug)
+     fprintf(stderr, "core %3d: exception %s, epc 0x%016" PRIx64 "\n",
+             id, t.name(), epc);
++  exit(1);
+ 
+   // by default, trap to M-mode, unless delegated to S-mode
+   reg_t bit = t.cause();
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/torture/riscv-isa-sim-sbreak.diff b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/riscv-isa-sim-sbreak.diff
new file mode 100644
index 0000000..9728fc8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/riscv-isa-sim-sbreak.diff
@@ -0,0 +1,26 @@
+diff --git a/riscv/insns/c_ebreak.h b/riscv/insns/c_ebreak.h
+index a17200f..af3a7ad 100644
+--- a/riscv/insns/c_ebreak.h
++++ b/riscv/insns/c_ebreak.h
+@@ -1,2 +1,9 @@
+ require_extension('C');
++
++for (int i = 0; i < 16*1024; i += 4) {
++  unsigned int dat = MMU.load_int32(i);
++  printf("%08x\n", dat);
++}
++exit(0);
++
+ throw trap_breakpoint();
+diff --git a/riscv/insns/sbreak.h b/riscv/insns/sbreak.h
+index c22776c..31397dd 100644
+--- a/riscv/insns/sbreak.h
++++ b/riscv/insns/sbreak.h
+@@ -1 +1,7 @@
++for (int i = 0; i < 16*1024; i += 4) {
++  unsigned int dat = MMU.load_int32(i);
++  printf("%08x\n", dat);
++}
++exit(0);
++
+ throw trap_breakpoint();
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/torture/riscv-torture-genloop.diff b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/riscv-torture-genloop.diff
new file mode 100644
index 0000000..a0a2fd1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/riscv-torture-genloop.diff
@@ -0,0 +1,40 @@
+diff --git a/generator/src/main/scala/main.scala b/generator/src/main/scala/main.scala
+index 7c78982..1572771 100644
+--- a/generator/src/main/scala/main.scala
++++ b/generator/src/main/scala/main.scala
+@@ -8,7 +8,7 @@ import java.util.Properties
+ import scala.collection.JavaConversions._
+ 
+ case class Options(var outFileName: String = "test",
+-  var confFileName: String = "config/default.config")
++  var confFileName: String = "config/default.config", var numOutFiles: Int = 0)
+ 
+ object Generator extends App
+ {
+@@ -17,15 +17,25 @@ object Generator extends App
+     val parser = new OptionParser[Options]("generator/run") {
+       opt[String]('C', "config") valueName("<file>") text("config file") action {(s: String, c) => c.copy(confFileName = s)}
+       opt[String]('o', "output") valueName("<filename>") text("output filename") action {(s: String, c) => c.copy(outFileName = s)}
++      opt[Int]('n', "numfiles") valueName("<num_files>") text("number of output files") action {(n: Int, c) => c.copy(numOutFiles = n)}
+     }
+     parser.parse(args, Options()) match {
+       case Some(opts) =>
+-        generate(opts.confFileName, opts.outFileName)
++        generate_loop(opts.confFileName, opts.outFileName, opts.numOutFiles)
+       case None =>
+         System.exit(1) //error message printed by parser
+     }
+   }
+ 
++  def generate_loop(confFile: String, outFileName: String, numOutFiles: Int) = {
++    if (numOutFiles > 0) {
++      for (i <- 0 to (numOutFiles-1))
++        generate(confFile, outFileName + ("_%03d" format (i)))
++    } else {
++      generate(confFile, outFileName)
++    }
++  }
++
+   def generate(confFile: String, outFileName: String): String = {
+     val config = new Properties()
+     val in = new FileInputStream(confFile)
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/torture/riscv-torture-rv32.diff b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/riscv-torture-rv32.diff
new file mode 100644
index 0000000..fef49b3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/riscv-torture-rv32.diff
@@ -0,0 +1,141 @@
+diff --git a/config/default.config b/config/default.config
+index b671223..c0b2bb4 100644
+--- a/config/default.config
++++ b/config/default.config
+@@ -1,18 +1,18 @@
+ torture.generator.nseqs     1000
+ torture.generator.memsize   1024
+ torture.generator.fprnd     0
+-torture.generator.amo       true
++torture.generator.amo       false
+ torture.generator.mul       true
+ torture.generator.divider   true
+ torture.generator.run_twice true
+ 
+ torture.generator.mix.xmem    10
+ torture.generator.mix.xbranch 20
+-torture.generator.mix.xalu    50
+-torture.generator.mix.fgen    10
+-torture.generator.mix.fpmem   5
+-torture.generator.mix.fax     3
+-torture.generator.mix.fdiv    2
++torture.generator.mix.xalu    70
++torture.generator.mix.fgen    0
++torture.generator.mix.fpmem   0
++torture.generator.mix.fax     0
++torture.generator.mix.fdiv    0
+ torture.generator.mix.vec     0
+ 
+ torture.generator.vec.vf 1
+diff --git a/generator/src/main/scala/HWRegPool.scala b/generator/src/main/scala/HWRegPool.scala
+index de2ad8d..864bcc4 100644
+--- a/generator/src/main/scala/HWRegPool.scala
++++ b/generator/src/main/scala/HWRegPool.scala
+@@ -86,7 +86,7 @@ trait PoolsMaster extends HWRegPool
+ 
+ class XRegsPool extends ScalarRegPool
+ {
+-  val (name, regname, ldinst, stinst) = ("xreg", "reg_x", "ld", "sd")
++  val (name, regname, ldinst, stinst) = ("xreg", "reg_x", "lw", "sw")
+   
+   hwregs += new HWReg("x0", true, false)
+   for (i <- 1 to 31)
+diff --git a/generator/src/main/scala/Prog.scala b/generator/src/main/scala/Prog.scala
+index 6fb49e2..685c2f8 100644
+--- a/generator/src/main/scala/Prog.scala
++++ b/generator/src/main/scala/Prog.scala
+@@ -385,7 +385,7 @@ class Prog(memsize: Int, veccfg: Map[String,String], run_twice: Boolean)
+     "\n" +
+     (if (using_vec) "RVTEST_RV64UV\n"
+      else if (using_fpu) "RVTEST_RV64UF\n"
+-     else "RVTEST_RV64U\n") +
++     else "RVTEST_RV32U\n") +
+     "RVTEST_CODE_BEGIN\n" +
+     (if (using_vec) init_vector() else "") + 
+     "\n" +
+diff --git a/generator/src/main/scala/Rand.scala b/generator/src/main/scala/Rand.scala
+index a677d2d..ec0745f 100644
+--- a/generator/src/main/scala/Rand.scala
++++ b/generator/src/main/scala/Rand.scala
+@@ -15,7 +15,7 @@ object Rand
+     low + Random.nextInt(span)
+   }
+ 
+-  def rand_shamt() = rand_range(0, 63)
++  def rand_shamt() = rand_range(0, 31)
+   def rand_shamtw() = rand_range(0, 31)
+   def rand_seglen() = rand_range(0, 7)
+   def rand_imm() = rand_range(-2048, 2047)
+diff --git a/generator/src/main/scala/SeqALU.scala b/generator/src/main/scala/SeqALU.scala
+index a1f27a5..18d6d7b 100644
+--- a/generator/src/main/scala/SeqALU.scala
++++ b/generator/src/main/scala/SeqALU.scala
+@@ -68,17 +68,12 @@ class SeqALU(xregs: HWRegPool, use_mul: Boolean, use_div: Boolean) extends InstS
+   candidates += seq_src1_immfn(SRAI, rand_shamt)
+   candidates += seq_src1_immfn(ORI, rand_imm)
+   candidates += seq_src1_immfn(ANDI, rand_imm)
+-  candidates += seq_src1_immfn(ADDIW, rand_imm)
+-  candidates += seq_src1_immfn(SLLIW, rand_shamtw)
+-  candidates += seq_src1_immfn(SRLIW, rand_shamtw)
+-  candidates += seq_src1_immfn(SRAIW, rand_shamtw)
+ 
+   val oplist = new ArrayBuffer[Opcode]
+ 
+   oplist += (ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND)
+-  oplist += (ADDW, SUBW, SLLW, SRLW, SRAW)
+-  if (use_mul) oplist += (MUL, MULH, MULHSU, MULHU, MULW)
+-  if (use_div) oplist += (DIV, DIVU, REM, REMU, DIVW, DIVUW, REMW, REMUW)
++  if (use_mul) oplist += (MUL, MULH, MULHSU, MULHU)
++  if (use_div) oplist += (DIV, DIVU, REM, REMU)
+ 
+   for (op <- oplist)
+   {
+diff --git a/generator/src/main/scala/SeqBranch.scala b/generator/src/main/scala/SeqBranch.scala
+index bba9895..0d257d7 100644
+--- a/generator/src/main/scala/SeqBranch.scala
++++ b/generator/src/main/scala/SeqBranch.scala
+@@ -75,7 +75,7 @@ class SeqBranch(xregs: HWRegPool) extends InstSeq
+     val reg_mask = reg_write_visible(xregs)
+ 
+     insts += ADDI(reg_one, reg_read_zero(xregs), Imm(1))
+-    insts += SLL(reg_one, reg_one, Imm(63))
++    insts += SLL(reg_one, reg_one, Imm(31))
+     insts += ADDI(reg_mask, reg_read_zero(xregs), Imm(-1))
+     insts += XOR(reg_mask, reg_mask, reg_one)
+     insts += AND(reg_dst1, reg_src, reg_mask)
+@@ -95,7 +95,7 @@ class SeqBranch(xregs: HWRegPool) extends InstSeq
+     val reg_mask = reg_write_visible(xregs)
+ 
+     insts += ADDI(reg_one, reg_read_zero(xregs), Imm(1))
+-    insts += SLL(reg_one, reg_one, Imm(63))
++    insts += SLL(reg_one, reg_one, Imm(31))
+     insts += ADDI(reg_mask, reg_read_zero(xregs), Imm(-1))
+     insts += XOR(reg_mask, reg_mask, reg_one)
+     insts += AND(reg_dst1, reg_src1, reg_mask)
+diff --git a/generator/src/main/scala/SeqMem.scala b/generator/src/main/scala/SeqMem.scala
+index 3c180ed..89200f6 100644
+--- a/generator/src/main/scala/SeqMem.scala
++++ b/generator/src/main/scala/SeqMem.scala
+@@ -51,7 +51,7 @@ class SeqMem(xregs: HWRegPool, mem: Mem, use_amo: Boolean) extends InstSeq
+ 
+        def getRandOpAndAddr (dw_addr: Int, is_store: Boolean): (Opcode, Int) =
+        {
+-          val typ = AccessType.values.toIndexedSeq(rand_range(0,6))
++          val typ = AccessType.values.toIndexedSeq(rand_range(0,4))
+           if (is_store)
+           {
+              if      (typ == byte  || typ ==ubyte)  (SB, dw_addr + rand_addr_b(8))
+@@ -110,13 +110,10 @@ class SeqMem(xregs: HWRegPool, mem: Mem, use_amo: Boolean) extends InstSeq
+   candidates += seq_load_addrfn(LH, rand_addr_h)
+   candidates += seq_load_addrfn(LHU, rand_addr_h)
+   candidates += seq_load_addrfn(LW, rand_addr_w)
+-  candidates += seq_load_addrfn(LWU, rand_addr_w)
+-  candidates += seq_load_addrfn(LD, rand_addr_d)
+ 
+   candidates += seq_store_addrfn(SB, rand_addr_b)
+   candidates += seq_store_addrfn(SH, rand_addr_h)
+   candidates += seq_store_addrfn(SW, rand_addr_w)
+-  candidates += seq_store_addrfn(SD, rand_addr_d)
+ 
+   if (use_amo) 
+   {
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/torture/riscv_test.h b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/riscv_test.h
new file mode 100644
index 0000000..36c5b54
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/riscv_test.h
@@ -0,0 +1,13 @@
+#ifndef RISCV_TEST_H
+#define RISCV_TEST_H
+
+#define RVTEST_RV32U
+#define RVTEST_CODE_BEGIN
+#define RVTEST_CODE_END
+#define RVTEST_DATA_BEGIN
+#define RVTEST_DATA_END
+
+#define RVTEST_FAIL ebreak
+#define RVTEST_PASS ebreak
+
+#endif
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/torture/sections.lds b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/sections.lds
new file mode 100644
index 0000000..a9487e2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/sections.lds
@@ -0,0 +1,9 @@
+SECTIONS {
+	.memory : {
+		. = 0x000000;
+		*(.text);
+		*(*);
+		end = .;
+	}
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/torture/test.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/test.sh
new file mode 100644
index 0000000..17c5a7c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/test.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+set -ex
+
+
+## Generate test case
+
+if ! test -f config.vh; then
+	python3 config.py
+fi
+
+if ! test -f test.S; then
+	cd riscv-torture
+	./sbt "generator/run -C config/test.config"
+	cp output/test.S ../test.S
+	cd ..
+fi
+
+
+## Compile test case and create reference
+
+riscv32-unknown-elf-gcc `sed '/march=/ ! d; s,^// ,-,; y/RVIMC/rvimc/;' config.vh` -ffreestanding -nostdlib -Wl,-Bstatic,-T,sections.lds -o test.elf test.S
+LD_LIBRARY_PATH="./riscv-isa-sim:./riscv-fesvr" ./riscv-isa-sim/spike test.elf > test.ref
+riscv32-unknown-elf-objcopy -O binary test.elf test.bin
+python3 ../../firmware/makehex.py test.bin 4096 > test.hex
+
+
+## Run test
+
+iverilog -o test.vvp testbench.v ../../picorv32.v
+vvp test.vvp +vcd +hex=test.hex +ref=test.ref
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/torture/testbench.cc b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/testbench.cc
new file mode 100644
index 0000000..2925d0b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/testbench.cc
@@ -0,0 +1,18 @@
+#include "Vtestbench.h"
+#include "verilated.h"
+
+int main(int argc, char **argv, char **env)
+{
+	Verilated::commandArgs(argc, argv);
+	Vtestbench* top = new Vtestbench;
+
+	top->clk = 0;
+	while (!Verilated::gotFinish()) {
+		top->clk = !top->clk;
+		top->eval();
+	}
+
+	delete top;
+	exit(0);
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/torture/testbench.v b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/testbench.v
new file mode 100644
index 0000000..326de0e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/torture/testbench.v
@@ -0,0 +1,134 @@
+module testbench (
+`ifdef VERILATOR
+	input clk
+`endif
+);
+`ifndef VERILATOR
+	reg clk = 1;
+	always #5 clk = ~clk;
+`endif
+	reg resetn = 0;
+	wire trap;
+
+	wire        mem_valid;
+	wire        mem_instr;
+	reg         mem_ready;
+	wire [31:0] mem_addr;
+	wire [31:0] mem_wdata;
+	wire [3:0]  mem_wstrb;
+	reg  [31:0] mem_rdata;
+
+	wire        mem_la_read;
+	wire        mem_la_write;
+	wire [31:0] mem_la_addr;
+	wire [31:0] mem_la_wdata;
+	wire [3:0]  mem_la_wstrb;
+
+	reg [31:0] x32 = 314159265;
+	reg [31:0] next_x32;
+
+	always @(posedge clk) begin
+		if (resetn) begin
+			next_x32 = x32;
+			next_x32 = next_x32 ^ (next_x32 << 13);
+			next_x32 = next_x32 ^ (next_x32 >> 17);
+			next_x32 = next_x32 ^ (next_x32 << 5);
+			x32 <= next_x32;
+		end
+	end
+
+	picorv32 #(
+`include "config.vh"
+	) uut (
+		.clk         (clk         ),
+		.resetn      (resetn      ),
+		.trap        (trap        ),
+
+		.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   ),
+
+		.mem_la_read (mem_la_read ),
+		.mem_la_write(mem_la_write),
+		.mem_la_addr (mem_la_addr ),
+		.mem_la_wdata(mem_la_wdata),
+		.mem_la_wstrb(mem_la_wstrb)
+	);
+
+	localparam integer filename_len = 18;
+	reg [8*filename_len-1:0] hex_filename;
+	reg [8*filename_len-1:0] ref_filename;
+
+	reg [31:0] memory [0:4095];
+	reg [31:0] memory_ref [0:4095];
+	integer i, errcount;
+	integer cycle = 0;
+
+	initial begin
+		if ($value$plusargs("hex=%s", hex_filename)) $readmemh(hex_filename, memory);
+		if ($value$plusargs("ref=%s", ref_filename)) $readmemh(ref_filename, memory_ref);
+`ifndef VERILATOR
+		if ($test$plusargs("vcd")) begin
+			$dumpfile("test.vcd");
+			$dumpvars(0, testbench);
+		end
+`endif
+	end
+
+	always @(posedge clk) begin
+		mem_ready <= 0;
+		mem_rdata <= 'bx;
+
+		if (!trap || !resetn) begin
+			if (x32[0] && resetn) begin
+				if (mem_la_read) begin
+					mem_ready <= 1;
+					mem_rdata <= memory[mem_la_addr >> 2];
+				end else
+				if (mem_la_write) begin
+					mem_ready <= 1;
+					if (mem_la_wstrb[0]) memory[mem_la_addr >> 2][ 7: 0] <= mem_la_wdata[ 7: 0];
+					if (mem_la_wstrb[1]) memory[mem_la_addr >> 2][15: 8] <= mem_la_wdata[15: 8];
+					if (mem_la_wstrb[2]) memory[mem_la_addr >> 2][23:16] <= mem_la_wdata[23:16];
+					if (mem_la_wstrb[3]) memory[mem_la_addr >> 2][31:24] <= mem_la_wdata[31:24];
+				end else
+				if (mem_valid && !mem_ready) begin
+					mem_ready <= 1;
+					if (mem_wstrb) begin
+						if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
+						if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
+						if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16];
+						if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24];
+					end else begin
+						mem_rdata <= memory[mem_addr >> 2];
+					end
+				end
+			end
+		end else begin
+			errcount = 0;
+			for (i=0; i < 4096; i=i+1) begin
+				if (memory[i] !== memory_ref[i]) begin
+					$display("Signature check failed at %04x: mem=%08x ref=%08x", i << 2, memory[i], memory_ref[i]);
+					errcount = errcount + 1;
+				end
+			end
+			if (errcount)
+				$display("FAILED: Got %1d errors for %1s => %1s!", errcount, hex_filename, ref_filename);
+			else
+				$display("PASSED %1s => %1s.", hex_filename, ref_filename);
+			$finish;
+		end
+
+		if (cycle > 100000) begin
+			$display("FAILED: Timeout!");
+			$finish;
+		end
+
+		resetn <= cycle > 10;
+		cycle <= cycle + 1;
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/.gitignore b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/.gitignore
new file mode 100644
index 0000000..2374269
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/.gitignore
@@ -0,0 +1,18 @@
+.Xil/
+firmware.bin
+firmware.elf
+firmware.hex
+firmware.map
+synth_*.log
+synth_*.mmi
+synth_*.bit
+synth_system.v
+table.txt
+tab_*/
+webtalk.jou
+webtalk.log
+webtalk_*.jou
+webtalk_*.log
+xelab.*
+xsim.*
+xvlog.*
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/Makefile b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/Makefile
new file mode 100644
index 0000000..3c92901
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/Makefile
@@ -0,0 +1,69 @@
+
+VIVADO_BASE = /opt/Xilinx/Vivado/2018.2
+VIVADO = $(VIVADO_BASE)/bin/vivado
+XVLOG = $(VIVADO_BASE)/bin/xvlog
+XELAB = $(VIVADO_BASE)/bin/xelab
+GLBL = $(VIVADO_BASE)/data/verilog/src/glbl.v
+TOOLCHAIN_PREFIX = riscv32-unknown-elf-
+
+export VIVADO
+
+# work-around for http://svn.clifford.at/handicraft/2016/vivadosig11
+export RDI_VERBOSE = False
+
+help:
+	@echo ""
+	@echo "Simple synthesis tests:"
+	@echo "  make synth_area_{small|regular|large}"
+	@echo "  make synth_speed"
+	@echo ""
+	@echo "Example system:"
+	@echo "  make synth_system"
+	@echo "  make sim_system"
+	@echo ""
+	@echo "Timing and Utilization Evaluation:"
+	@echo "  make table.txt"
+	@echo "  make area"
+	@echo ""
+
+synth_%:
+	rm -f $@.log
+	$(VIVADO) -nojournal -log $@.log -mode batch -source $@.tcl
+	rm -rf .Xil fsm_encoding.os synth_*.backup.log usage_statistics_webtalk.*
+	-grep -B4 -A10 'Slice LUTs' $@.log
+	-grep -B1 -A9 ^Slack $@.log && echo
+
+synth_system: firmware.hex
+
+sim_system:
+	$(XVLOG) system_tb.v synth_system.v
+	$(XVLOG) $(GLBL)
+	$(XELAB) -L unifast_ver -L unisims_ver -R system_tb glbl
+
+firmware.hex: firmware.S firmware.c firmware.lds
+	$(TOOLCHAIN_PREFIX)gcc -Os -ffreestanding -nostdlib -o firmware.elf firmware.S firmware.c \
+		 --std=gnu99 -Wl,-Bstatic,-T,firmware.lds,-Map,firmware.map,--strip-debug -lgcc
+	$(TOOLCHAIN_PREFIX)objcopy -O binary firmware.elf firmware.bin
+	python3 ../../firmware/makehex.py firmware.bin 4096 > firmware.hex
+
+tab_%/results.txt:
+	bash tabtest.sh $@
+
+area: synth_area_small synth_area_regular synth_area_large
+	-grep -B4 -A10 'Slice LUTs' synth_area_small.log synth_area_regular.log synth_area_large.log
+
+table.txt: tab_small_xc7k_2/results.txt  tab_small_xc7k_3/results.txt
+table.txt: tab_small_xc7v_2/results.txt  tab_small_xc7v_3/results.txt
+table.txt: tab_small_xcku_2/results.txt  tab_small_xcku_3/results.txt
+table.txt: tab_small_xcvu_2/results.txt  tab_small_xcvu_3/results.txt
+table.txt: tab_small_xckup_2/results.txt tab_small_xckup_3/results.txt
+table.txt: tab_small_xcvup_2/results.txt tab_small_xcvup_3/results.txt
+
+table.txt:
+	bash table.sh > table.txt
+
+clean:
+	rm -rf .Xil/ firmware.bin firmware.elf firmware.hex firmware.map synth_*.log
+	rm -rf synth_*.mmi synth_*.bit synth_system.v table.txt tab_*/ webtalk.jou
+	rm -rf webtalk.log webtalk_*.jou webtalk_*.log xelab.* xsim[._]* xvlog.*
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/firmware.S b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/firmware.S
new file mode 100644
index 0000000..c55a3ba
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/firmware.S
@@ -0,0 +1,12 @@
+.section .init
+.global main
+
+/* set stack pointer */
+lui sp, %hi(16*1024)
+addi sp, sp, %lo(16*1024)
+
+/* call main */
+jal ra, main
+
+/* break */
+ebreak
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/firmware.c b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/firmware.c
new file mode 100644
index 0000000..6c62169
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/firmware.c
@@ -0,0 +1,43 @@
+void putc(char c)
+{
+	*(volatile char*)0x10000000 = c;
+}
+
+void puts(const char *s)
+{
+	while (*s) putc(*s++);
+}
+
+void *memcpy(void *dest, const void *src, int n)
+{
+	while (n) {
+		n--;
+		((char*)dest)[n] = ((char*)src)[n];
+	}
+	return dest;
+}
+
+void main()
+{
+	char message[] = "$Uryyb+Jbeyq!+Vs+lbh+pna+ernq+guvf+zrffntr+gura$gur+CvpbEI32+PCH"
+			"+frrzf+gb+or+jbexvat+whfg+svar.$$++++++++++++++++GRFG+CNFFRQ!$$";
+	for (int i = 0; message[i]; i++)
+		switch (message[i])
+		{
+		case 'a' ... 'm':
+		case 'A' ... 'M':
+			message[i] += 13;
+			break;
+		case 'n' ... 'z':
+		case 'N' ... 'Z':
+			message[i] -= 13;
+			break;
+		case '$':
+			message[i] = '\n';
+			break;
+		case '+':
+			message[i] = ' ';
+			break;
+		}
+	puts(message);
+}
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/firmware.lds b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/firmware.lds
new file mode 100644
index 0000000..970000a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/firmware.lds
@@ -0,0 +1,11 @@
+SECTIONS {
+	.memory : {
+		. = 0x000000;
+		*(.init);
+		*(.text);
+		*(*);
+		. = ALIGN(4);
+		end = .;
+	}
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area.tcl b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area.tcl
new file mode 100644
index 0000000..c222a00
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area.tcl
@@ -0,0 +1,8 @@
+read_verilog ../../picorv32.v
+read_xdc synth_area.xdc
+
+synth_design -part xc7k70t-fbg676 -top picorv32_axi
+opt_design -resynth_seq_area
+
+report_utilization
+report_timing
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area.xdc b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area.xdc
new file mode 100644
index 0000000..3c3d5a1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area.xdc
@@ -0,0 +1 @@
+create_clock -period 20.00 [get_ports clk]
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area_large.tcl b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area_large.tcl
new file mode 100644
index 0000000..af611b5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area_large.tcl
@@ -0,0 +1,10 @@
+read_verilog ../../picorv32.v
+read_verilog synth_area_top.v
+read_xdc synth_area.xdc
+
+synth_design -part xc7k70t-fbg676 -top top_large
+opt_design -sweep -propconst -resynth_seq_area
+opt_design -directive ExploreSequentialArea
+
+report_utilization
+report_timing
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area_regular.tcl b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area_regular.tcl
new file mode 100644
index 0000000..2bf6b4c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area_regular.tcl
@@ -0,0 +1,10 @@
+read_verilog ../../picorv32.v
+read_verilog synth_area_top.v
+read_xdc synth_area.xdc
+
+synth_design -part xc7k70t-fbg676 -top top_regular
+opt_design -sweep -propconst -resynth_seq_area
+opt_design -directive ExploreSequentialArea
+
+report_utilization
+report_timing
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area_small.tcl b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area_small.tcl
new file mode 100644
index 0000000..11d2104
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area_small.tcl
@@ -0,0 +1,10 @@
+read_verilog ../../picorv32.v
+read_verilog synth_area_top.v
+read_xdc synth_area.xdc
+
+synth_design -part xc7k70t-fbg676 -top top_small
+opt_design -sweep -propconst -resynth_seq_area
+opt_design -directive ExploreSequentialArea
+
+report_utilization
+report_timing
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area_top.v b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area_top.v
new file mode 100644
index 0000000..6298a86
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_area_top.v
@@ -0,0 +1,140 @@
+
+module top_small (
+	input clk, resetn,
+
+	output        mem_valid,
+	output        mem_instr,
+	input         mem_ready,
+
+	output [31:0] mem_addr,
+	output [31:0] mem_wdata,
+	output [ 3:0] mem_wstrb,
+	input  [31:0] mem_rdata
+);
+	picorv32 #(
+		.ENABLE_COUNTERS(0),
+		.LATCHED_MEM_RDATA(1),
+		.TWO_STAGE_SHIFT(0),
+		.CATCH_MISALIGN(0),
+		.CATCH_ILLINSN(0)
+	) picorv32 (
+		.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)
+	);
+endmodule
+
+module top_regular (
+	input clk, resetn,
+	output trap,
+
+	output        mem_valid,
+	output        mem_instr,
+	input         mem_ready,
+
+	output [31:0] mem_addr,
+	output [31:0] mem_wdata,
+	output [ 3:0] mem_wstrb,
+	input  [31:0] mem_rdata,
+
+	// Look-Ahead Interface
+	output        mem_la_read,
+	output        mem_la_write,
+	output [31:0] mem_la_addr,
+	output [31:0] mem_la_wdata,
+	output [ 3:0] mem_la_wstrb
+);
+	picorv32 picorv32 (
+		.clk         (clk         ),
+		.resetn      (resetn      ),
+		.trap        (trap        ),
+		.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   ),
+		.mem_la_read (mem_la_read ),
+		.mem_la_write(mem_la_write),
+		.mem_la_addr (mem_la_addr ),
+		.mem_la_wdata(mem_la_wdata),
+		.mem_la_wstrb(mem_la_wstrb)
+	);
+endmodule
+
+module top_large (
+	input clk, resetn,
+	output trap,
+
+	output        mem_valid,
+	output        mem_instr,
+	input         mem_ready,
+
+	output [31:0] mem_addr,
+	output [31:0] mem_wdata,
+	output [ 3:0] mem_wstrb,
+	input  [31:0] mem_rdata,
+
+	// Look-Ahead Interface
+	output        mem_la_read,
+	output        mem_la_write,
+	output [31:0] mem_la_addr,
+	output [31:0] mem_la_wdata,
+	output [ 3:0] mem_la_wstrb,
+
+	// Pico Co-Processor Interface (PCPI)
+	output        pcpi_valid,
+	output [31:0] pcpi_insn,
+	output [31:0] pcpi_rs1,
+	output [31:0] pcpi_rs2,
+	input         pcpi_wr,
+	input  [31:0] pcpi_rd,
+	input         pcpi_wait,
+	input         pcpi_ready,
+
+	// IRQ Interface
+	input  [31:0] irq,
+	output [31:0] eoi
+);
+	picorv32 #(
+		.COMPRESSED_ISA(1),
+		.BARREL_SHIFTER(1),
+		.ENABLE_PCPI(1),
+		.ENABLE_MUL(1),
+		.ENABLE_IRQ(1)
+	) picorv32 (
+		.clk            (clk            ),
+		.resetn         (resetn         ),
+		.trap           (trap           ),
+		.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      ),
+		.mem_la_read    (mem_la_read    ),
+		.mem_la_write   (mem_la_write   ),
+		.mem_la_addr    (mem_la_addr    ),
+		.mem_la_wdata   (mem_la_wdata   ),
+		.mem_la_wstrb   (mem_la_wstrb   ),
+		.pcpi_valid     (pcpi_valid     ),
+		.pcpi_insn      (pcpi_insn      ),
+		.pcpi_rs1       (pcpi_rs1       ),
+		.pcpi_rs2       (pcpi_rs2       ),
+		.pcpi_wr        (pcpi_wr        ),
+		.pcpi_rd        (pcpi_rd        ),
+		.pcpi_wait      (pcpi_wait      ),
+		.pcpi_ready     (pcpi_ready     ),
+		.irq            (irq            ),
+		.eoi            (eoi            )
+	);
+endmodule
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_speed.tcl b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_speed.tcl
new file mode 100644
index 0000000..f3874e4
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_speed.tcl
@@ -0,0 +1,13 @@
+
+read_verilog ../../picorv32.v
+read_xdc synth_speed.xdc
+
+synth_design -part xc7k70t-fbg676 -top picorv32_axi
+opt_design
+place_design
+phys_opt_design
+route_design
+
+report_utilization
+report_timing
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_speed.xdc b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_speed.xdc
new file mode 100644
index 0000000..877ec8d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_speed.xdc
@@ -0,0 +1 @@
+create_clock -period 2.50 [get_ports clk]
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_system.tcl b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_system.tcl
new file mode 100644
index 0000000..26ea01c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_system.tcl
@@ -0,0 +1,17 @@
+
+read_verilog system.v
+read_verilog ../../picorv32.v
+read_xdc synth_system.xdc
+
+synth_design -part xc7a35t-cpg236-1 -top system
+opt_design
+place_design
+route_design
+
+report_utilization
+report_timing
+
+write_verilog -force synth_system.v
+write_bitstream -force synth_system.bit
+# write_mem_info -force synth_system.mmi
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_system.xdc b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_system.xdc
new file mode 100644
index 0000000..5748466
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/synth_system.xdc
@@ -0,0 +1,34 @@
+
+# XDC File for Basys3 Board
+###########################
+
+set_property PACKAGE_PIN W5 [get_ports clk]
+set_property IOSTANDARD LVCMOS33 [get_ports clk]
+create_clock -period 10.00 [get_ports clk]
+
+# Pmod Header JA (JA0..JA7)
+set_property PACKAGE_PIN J1 [get_ports {out_byte[0]}]
+set_property IOSTANDARD LVCMOS33 [get_ports {out_byte[0]}]
+set_property PACKAGE_PIN L2 [get_ports {out_byte[1]}]
+set_property IOSTANDARD LVCMOS33 [get_ports {out_byte[1]}]
+set_property PACKAGE_PIN J2 [get_ports {out_byte[2]}]
+set_property IOSTANDARD LVCMOS33 [get_ports {out_byte[2]}]
+set_property PACKAGE_PIN G2 [get_ports {out_byte[3]}]
+set_property IOSTANDARD LVCMOS33 [get_ports {out_byte[3]}]
+set_property PACKAGE_PIN H1 [get_ports {out_byte[4]}]
+set_property IOSTANDARD LVCMOS33 [get_ports {out_byte[4]}]
+set_property PACKAGE_PIN K2 [get_ports {out_byte[5]}]
+set_property IOSTANDARD LVCMOS33 [get_ports {out_byte[5]}]
+set_property PACKAGE_PIN H2 [get_ports {out_byte[6]}]
+set_property IOSTANDARD LVCMOS33 [get_ports {out_byte[6]}]
+set_property PACKAGE_PIN G3 [get_ports {out_byte[7]}]
+set_property IOSTANDARD LVCMOS33 [get_ports {out_byte[7]}]
+
+# Pmod Header JB (JB0..JB2)
+set_property PACKAGE_PIN A14 [get_ports {resetn}]
+set_property IOSTANDARD LVCMOS33 [get_ports {resetn}]
+set_property PACKAGE_PIN A16 [get_ports {trap}]
+set_property IOSTANDARD LVCMOS33 [get_ports {trap}]
+set_property PACKAGE_PIN B15 [get_ports {out_byte_en}]
+set_property IOSTANDARD LVCMOS33 [get_ports {out_byte_en}]
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/system.v b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/system.v
new file mode 100644
index 0000000..c4882a1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/system.v
@@ -0,0 +1,101 @@
+`timescale 1 ns / 1 ps
+
+module system (
+	input            clk,
+	input            resetn,
+	output           trap,
+	output reg [7:0] out_byte,
+	output reg       out_byte_en
+);
+	// set this to 0 for better timing but less performance/MHz
+	parameter FAST_MEMORY = 1;
+
+	// 4096 32bit words = 16kB memory
+	parameter MEM_SIZE = 4096;
+
+	wire mem_valid;
+	wire mem_instr;
+	reg mem_ready;
+	wire [31:0] mem_addr;
+	wire [31:0] mem_wdata;
+	wire [3:0] mem_wstrb;
+	reg [31:0] mem_rdata;
+
+	wire mem_la_read;
+	wire mem_la_write;
+	wire [31:0] mem_la_addr;
+	wire [31:0] mem_la_wdata;
+	wire [3:0] mem_la_wstrb;
+
+	picorv32 picorv32_core (
+		.clk         (clk         ),
+		.resetn      (resetn      ),
+		.trap        (trap        ),
+		.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   ),
+		.mem_la_read (mem_la_read ),
+		.mem_la_write(mem_la_write),
+		.mem_la_addr (mem_la_addr ),
+		.mem_la_wdata(mem_la_wdata),
+		.mem_la_wstrb(mem_la_wstrb)
+	);
+
+	reg [31:0] memory [0:MEM_SIZE-1];
+	initial $readmemh("firmware.hex", memory);
+
+	reg [31:0] m_read_data;
+	reg m_read_en;
+
+	generate if (FAST_MEMORY) begin
+		always @(posedge clk) begin
+			mem_ready <= 1;
+			out_byte_en <= 0;
+			mem_rdata <= memory[mem_la_addr >> 2];
+			if (mem_la_write && (mem_la_addr >> 2) < MEM_SIZE) begin
+				if (mem_la_wstrb[0]) memory[mem_la_addr >> 2][ 7: 0] <= mem_la_wdata[ 7: 0];
+				if (mem_la_wstrb[1]) memory[mem_la_addr >> 2][15: 8] <= mem_la_wdata[15: 8];
+				if (mem_la_wstrb[2]) memory[mem_la_addr >> 2][23:16] <= mem_la_wdata[23:16];
+				if (mem_la_wstrb[3]) memory[mem_la_addr >> 2][31:24] <= mem_la_wdata[31:24];
+			end
+			else
+			if (mem_la_write && mem_la_addr == 32'h1000_0000) begin
+				out_byte_en <= 1;
+				out_byte <= mem_la_wdata;
+			end
+		end
+	end else begin
+		always @(posedge clk) begin
+			m_read_en <= 0;
+			mem_ready <= mem_valid && !mem_ready && m_read_en;
+
+			m_read_data <= memory[mem_addr >> 2];
+			mem_rdata <= m_read_data;
+
+			out_byte_en <= 0;
+
+			(* parallel_case *)
+			case (1)
+				mem_valid && !mem_ready && !mem_wstrb && (mem_addr >> 2) < MEM_SIZE: begin
+					m_read_en <= 1;
+				end
+				mem_valid && !mem_ready && |mem_wstrb && (mem_addr >> 2) < MEM_SIZE: begin
+					if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
+					if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
+					if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16];
+					if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24];
+					mem_ready <= 1;
+				end
+				mem_valid && !mem_ready && |mem_wstrb && mem_addr == 32'h1000_0000: begin
+					out_byte_en <= 1;
+					out_byte <= mem_wdata;
+					mem_ready <= 1;
+				end
+			endcase
+		end
+	end endgenerate
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/system_tb.v b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/system_tb.v
new file mode 100644
index 0000000..a66d612
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/system_tb.v
@@ -0,0 +1,38 @@
+`timescale 1 ns / 1 ps
+
+module system_tb;
+	reg clk = 1;
+	always #5 clk = ~clk;
+
+	reg resetn = 0;
+	initial begin
+		if ($test$plusargs("vcd")) begin
+			$dumpfile("system.vcd");
+			$dumpvars(0, system_tb);
+		end
+		repeat (100) @(posedge clk);
+		resetn <= 1;
+	end
+
+	wire trap;
+	wire [7:0] out_byte;
+	wire out_byte_en;
+
+	system uut (
+		.clk        (clk        ),
+		.resetn     (resetn     ),
+		.trap       (trap       ),
+		.out_byte   (out_byte   ),
+		.out_byte_en(out_byte_en)
+	);
+
+	always @(posedge clk) begin
+		if (resetn && out_byte_en) begin
+			$write("%c", out_byte);
+			$fflush;
+		end
+		if (resetn && trap) begin
+			$finish;
+		end
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/table.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/table.sh
new file mode 100644
index 0000000..81e2cf4
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/table.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+dashes="----------------------------------------------------------------"
+printf '| %-25s | %-10s | %-20s |\n' "Device" "Speedgrade" "Clock Period (Freq.)"
+printf '|:%.25s |:%.10s:| %.20s:|\n' $dashes $dashes $dashes
+
+for x in $( grep -H . tab_*/results.txt )
+do
+	read _ size device grade _ speed < <( echo "$x" | tr _/: ' ' )
+	case "$device" in
+		xc7a) d="Xilinx Artix-7T" ;;
+		xc7k) d="Xilinx Kintex-7T" ;;
+		xc7v) d="Xilinx Virtex-7T" ;;
+		xcku) d="Xilinx Kintex UltraScale" ;;
+		xcvu) d="Xilinx Virtex UltraScale" ;;
+		xckup) d="Xilinx Kintex UltraScale+" ;;
+		xcvup) d="Xilinx Virtex UltraScale+" ;;
+	esac
+	speedtxt=$( printf '%s.%s ns (%d MHz)' ${speed%?} ${speed#?} $((10000 / speed)) )
+	printf '| %-25s | %-10s | %20s |\n' "$d" "-$grade" "$speedtxt"
+done
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/tabtest.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/tabtest.sh
new file mode 100644
index 0000000..bc3d840
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/tabtest.sh
@@ -0,0 +1,103 @@
+#!/bin/bash
+
+set -e
+read _ ip dev grade _ < <( echo $* | tr '_/' ' '; )
+
+# rm -rf tab_${ip}_${dev}_${grade}
+mkdir -p tab_${ip}_${dev}_${grade}
+cd tab_${ip}_${dev}_${grade}
+
+best_speed=99
+speed=20
+step=16
+
+synth_case() {
+	if [ -f test_${1}.txt ]; then
+		echo "Reusing cached tab_${ip}_${dev}_${grade}/test_${1}."
+		return
+	fi
+
+	case "${dev}" in
+		xc7k) xl_device="xc7k70t-fbg676-${grade}" ;;
+		xc7v) xl_device="xc7v585t-ffg1761-${grade}" ;;
+		xcku) xl_device="xcku035-fbva676-${grade}-e" ;;
+		xcvu) xl_device="xcvu065-ffvc1517-${grade}-e" ;;
+		xckup) xl_device="xcku3p-ffva676-${grade}-e" ;;
+		xcvup) xl_device="xcvu3p-ffvc1517-${grade}-e" ;;
+	esac
+
+	cat > test_${1}.tcl <<- EOT
+		read_verilog ../tabtest.v
+		read_verilog ../../../picorv32.v
+		read_xdc test_${1}.xdc
+		synth_design -flatten_hierarchy full -part ${xl_device} -top top
+		opt_design -sweep -remap -propconst
+		opt_design -directive Explore
+		place_design -directive Explore
+		phys_opt_design -retime -rewire -critical_pin_opt -placement_opt -critical_cell_opt
+		route_design -directive Explore
+		place_design -post_place_opt
+		phys_opt_design -retime
+		route_design -directive NoTimingRelaxation
+		report_utilization
+		report_timing
+	EOT
+
+	cat > test_${1}.xdc <<- EOT
+		create_clock -period ${speed%?}.${speed#?} [get_ports clk]
+	EOT
+
+	echo "Running tab_${ip}_${dev}_${grade}/test_${1}.."
+	if ! $VIVADO -nojournal -log test_${1}.log -mode batch -source test_${1}.tcl > /dev/null 2>&1; then
+		cat test_${1}.log
+		exit 1
+	fi
+	mv test_${1}.log test_${1}.txt
+}
+
+got_violated=false
+got_met=false
+
+countdown=2
+while [ $countdown -gt 0 ]; do
+	synth_case $speed
+
+	if grep -q '^Slack.*(VIOLATED)' test_${speed}.txt; then
+		echo "        tab_${ip}_${dev}_${grade}/test_${speed} VIOLATED"
+		step=$((step / 2))
+		speed=$((speed + step))
+		got_violated=true
+	elif grep -q '^Slack.*(MET)' test_${speed}.txt; then
+		echo "        tab_${ip}_${dev}_${grade}/test_${speed} MET"
+		[ $speed -lt $best_speed ] && best_speed=$speed
+		step=$((step / 2))
+		speed=$((speed - step))
+		got_met=true
+	else
+		echo "ERROR: No slack line found in $PWD/test_${speed}.txt!"
+		exit 1
+	fi
+
+	if [ $step -eq 0 ]; then
+		countdown=$((countdown - 1))
+		speed=$((best_speed - 2))
+		step=1
+	fi
+done
+
+if ! $got_violated; then
+	echo "ERROR: No timing violated in $PWD!"
+	exit 1
+fi
+
+if ! $got_met; then
+	echo "ERROR: No timing met in $PWD!"
+	exit 1
+fi
+
+
+echo "-----------------------"
+echo "Best speed for tab_${ip}_${dev}_${grade}: $best_speed"
+echo "-----------------------"
+echo $best_speed > results.txt
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/tabtest.v b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/tabtest.v
new file mode 100644
index 0000000..cdf2057
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/vivado/tabtest.v
@@ -0,0 +1,118 @@
+
+module top (
+	input clk, io_resetn,
+	output io_trap,
+
+	output        io_mem_axi_awvalid,
+	input         io_mem_axi_awready,
+	output [31:0] io_mem_axi_awaddr,
+	output [ 2:0] io_mem_axi_awprot,
+
+	output        io_mem_axi_wvalid,
+	input         io_mem_axi_wready,
+	output [31:0] io_mem_axi_wdata,
+	output [ 3:0] io_mem_axi_wstrb,
+
+	input         io_mem_axi_bvalid,
+	output        io_mem_axi_bready,
+
+	output        io_mem_axi_arvalid,
+	input         io_mem_axi_arready,
+	output [31:0] io_mem_axi_araddr,
+	output [ 2:0] io_mem_axi_arprot,
+
+	input         io_mem_axi_rvalid,
+	output        io_mem_axi_rready,
+	input  [31:0] io_mem_axi_rdata,
+
+	input  [31:0] io_irq,
+	output [31:0] io_eoi
+);
+	wire resetn;
+	wire trap;
+	wire mem_axi_awvalid;
+	wire mem_axi_awready;
+	wire [31:0] mem_axi_awaddr;
+	wire [2:0] mem_axi_awprot;
+	wire mem_axi_wvalid;
+	wire mem_axi_wready;
+	wire [31:0] mem_axi_wdata;
+	wire [3:0] mem_axi_wstrb;
+	wire mem_axi_bvalid;
+	wire mem_axi_bready;
+	wire mem_axi_arvalid;
+	wire mem_axi_arready;
+	wire [31:0] mem_axi_araddr;
+	wire [2:0] mem_axi_arprot;
+	wire mem_axi_rvalid;
+	wire mem_axi_rready;
+	wire [31:0] mem_axi_rdata;
+	wire [31:0] irq;
+	wire [31:0] eoi;
+
+	delay4 #( 1) delay_resetn          (clk, io_resetn         ,    resetn         );
+	delay4 #( 1) delay_trap            (clk,    trap           , io_trap           );
+	delay4 #( 1) delay_mem_axi_awvalid (clk,    mem_axi_awvalid, io_mem_axi_awvalid);
+	delay4 #( 1) delay_mem_axi_awready (clk, io_mem_axi_awready,    mem_axi_awready);
+	delay4 #(32) delay_mem_axi_awaddr  (clk,    mem_axi_awaddr , io_mem_axi_awaddr );
+	delay4 #( 3) delay_mem_axi_awprot  (clk,    mem_axi_awprot , io_mem_axi_awprot );
+	delay4 #( 1) delay_mem_axi_wvalid  (clk,    mem_axi_wvalid , io_mem_axi_wvalid );
+	delay4 #( 1) delay_mem_axi_wready  (clk, io_mem_axi_wready ,    mem_axi_wready );
+	delay4 #(32) delay_mem_axi_wdata   (clk,    mem_axi_wdata  , io_mem_axi_wdata  );
+	delay4 #( 4) delay_mem_axi_wstrb   (clk,    mem_axi_wstrb  , io_mem_axi_wstrb  );
+	delay4 #( 1) delay_mem_axi_bvalid  (clk, io_mem_axi_bvalid ,    mem_axi_bvalid );
+	delay4 #( 1) delay_mem_axi_bready  (clk,    mem_axi_bready , io_mem_axi_bready );
+	delay4 #( 1) delay_mem_axi_arvalid (clk,    mem_axi_arvalid, io_mem_axi_arvalid);
+	delay4 #( 1) delay_mem_axi_arready (clk, io_mem_axi_arready,    mem_axi_arready);
+	delay4 #(32) delay_mem_axi_araddr  (clk,    mem_axi_araddr , io_mem_axi_araddr );
+	delay4 #( 3) delay_mem_axi_arprot  (clk,    mem_axi_arprot , io_mem_axi_arprot );
+	delay4 #( 1) delay_mem_axi_rvalid  (clk, io_mem_axi_rvalid ,    mem_axi_rvalid );
+	delay4 #( 1) delay_mem_axi_rready  (clk,    mem_axi_rready , io_mem_axi_rready );
+	delay4 #(32) delay_mem_axi_rdata   (clk, io_mem_axi_rdata  ,    mem_axi_rdata  );
+	delay4 #(32) delay_irq             (clk, io_irq            ,    irq            );
+	delay4 #(32) delay_eoi             (clk,    eoi            , io_eoi            );
+
+	picorv32_axi #(
+		.TWO_CYCLE_ALU(1)
+	) cpu (
+		.clk            (clk            ),
+		.resetn         (resetn         ),
+		.trap           (trap           ),
+		.mem_axi_awvalid(mem_axi_awvalid),
+		.mem_axi_awready(mem_axi_awready),
+		.mem_axi_awaddr (mem_axi_awaddr ),
+		.mem_axi_awprot (mem_axi_awprot ),
+		.mem_axi_wvalid (mem_axi_wvalid ),
+		.mem_axi_wready (mem_axi_wready ),
+		.mem_axi_wdata  (mem_axi_wdata  ),
+		.mem_axi_wstrb  (mem_axi_wstrb  ),
+		.mem_axi_bvalid (mem_axi_bvalid ),
+		.mem_axi_bready (mem_axi_bready ),
+		.mem_axi_arvalid(mem_axi_arvalid),
+		.mem_axi_arready(mem_axi_arready),
+		.mem_axi_araddr (mem_axi_araddr ),
+		.mem_axi_arprot (mem_axi_arprot ),
+		.mem_axi_rvalid (mem_axi_rvalid ),
+		.mem_axi_rready (mem_axi_rready ),
+		.mem_axi_rdata  (mem_axi_rdata  ),
+		.irq            (irq            ),
+		.eoi            (eoi            )
+	);
+endmodule
+
+module delay4 #(
+	parameter WIDTH = 1
+) (
+	input clk,
+	input [WIDTH-1:0] in,
+	output reg [WIDTH-1:0] out
+);
+	reg [WIDTH-1:0] q1, q2, q3;
+	always @(posedge clk) begin
+		q1 <= in;
+		q2 <= q1;
+		q3 <= q2;
+		out <= q3;
+	end
+endmodule
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/README.md b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/README.md
new file mode 100644
index 0000000..acb2c6c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/README.md
@@ -0,0 +1,62 @@
+
+Synthesis results for the PicoRV32 core (in its default configuration) with Yosys 0.5+383 (git sha1 8648089), Synplify Pro and Lattice LSE from iCEcube2.2014.08, and Xilinx Vivado 2015.3.
+
+No timing constraints were used for synthesis; only resource utilisation is compared.
+
+Last updated: 2015-10-30
+
+
+Results for iCE40 Synthesis
+---------------------------
+
+| Cell          | Yosys | Synplify Pro | Lattice LSE |
+|:--------------|------:|-------------:|------------:|
+| `SB_CARRY`    |   405 |          349 |         309 |
+| `SB_DFF`      |   125 |          256 |         114 |
+| `SB_DFFE`     |   251 |          268 |          76 |
+| `SB_DFFESR`   |   172 |           39 |         147 |
+| `SB_DFFESS`   |     1 |            0 |          69 |
+| `SB_DFFSR`    |    69 |          137 |         134 |
+| `SB_DFFSS`    |     0 |            0 |          36 |
+| `SB_LUT4`     |  1795 |         1657 |        1621 |
+| `SB_RAM40_4K` |     4 |            4 |           4 |
+
+Summary:
+
+| Cell          | Yosys | Synplify Pro | Lattice LSE |
+|:--------------|------:|-------------:|------------:|
+| `SB_CARRY`    |   405 |          349 |         309 |
+| `SB_DFF*`     |   618 |          700 |         576 |
+| `SB_LUT4`     |  1795 |         1657 |        1621 |
+| `SB_RAM40_4K` |     4 |            4 |           4 |
+
+
+Results for Xilinx 7-Series Synthesis
+-------------------------------------
+
+| Cell        | Yosys | Vivado |
+|:------------|------:|-------:|
+| `FDRE`      |   671 |    553 |
+| `FDSE`      |     0 |     21 |
+| `LUT1`      |    41 |    160 |
+| `LUT2`      |   517 |    122 |
+| `LUT3`      |    77 |    120 |
+| `LUT4`      |   136 |    204 |
+| `LUT5`      |   142 |    135 |
+| `LUT6`      |   490 |    405 |
+| `MUXF7`     |    54 |      0 |
+| `MUXF8`     |    15 |      0 |
+| `MUXCY`     |   420 |      0 |
+| `XORCY`     |   359 |      0 |
+| `CARRY4`    |     0 |     83 |
+| `RAMD32`    |     0 |     72 |
+| `RAMS32`    |     0 |     24 |
+| `RAM64X1D`  |    64 |      0 |
+
+Summary:
+
+| Cell        | Yosys | Vivado |
+|:------------|------:|-------:|
+| `FD*`       |   671 |    574 |
+| `LUT*`      |  1403 |   1146 |
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/lse.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/lse.sh
new file mode 100644
index 0000000..a802c67
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/lse.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+set -ex
+
+rm -rf lse.tmp
+mkdir lse.tmp
+cd lse.tmp
+
+cat > lse.prj << EOT
+#device
+-a SBTiCE40
+-d iCE40HX8K
+-t CT256
+#constraint file
+
+#options
+-frequency 200
+-optimization_goal Area
+-twr_paths 3
+-bram_utilization 100.00
+-ramstyle Auto
+-romstyle Auto
+-use_carry_chain 1
+-carry_chain_length 0
+-resource_sharing 1
+-propagate_constants 1
+-remove_duplicate_regs 1
+-max_fanout 10000
+-fsm_encoding_style Auto
+-use_io_insertion 1
+-use_io_reg auto
+-ifd
+-resolve_mixed_drivers 0
+-RWCheckOnRam 0
+-fix_gated_clocks 1
+-top picorv32
+
+-ver "../../../picorv32.v"
+-p "."
+
+#set result format/file last
+-output_edif output.edf
+
+#set log file
+-logfile "lse.log"
+EOT
+
+icecubedir="${ICECUBEDIR:-/opt/lscc/iCEcube2.2014.08}"
+export FOUNDRY="$icecubedir/LSE"
+export LD_LIBRARY_PATH="$LD_LIBRARY_PATH${LD_LIBRARY_PATH:+:}$icecubedir/LSE/bin/lin"
+"$icecubedir"/LSE/bin/lin/synthesis -f lse.prj
+
+grep 'viewRef.*cellRef' output.edf | sed 's,.*cellRef *,,; s,[ )].*,,;' | sort | uniq -c
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/synplify.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/synplify.sh
new file mode 100644
index 0000000..d0a2a08
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/synplify.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+
+set -ex
+
+rm -rf synplify.tmp
+mkdir synplify.tmp
+cd synplify.tmp
+
+cat > impl_syn.prj << EOT
+add_file -verilog -lib work ../../../picorv32.v
+impl -add impl -type fpga
+
+# implementation attributes
+set_option -vlog_std v2001
+set_option -project_relative_includes 1
+
+# device options
+set_option -technology SBTiCE40
+set_option -part iCE40HX8K
+set_option -package CT256
+set_option -speed_grade
+set_option -part_companion ""
+
+# compilation/mapping options
+set_option -top_module "picorv32"
+
+# mapper_options
+set_option -frequency auto
+set_option -write_verilog 0
+set_option -write_vhdl 0
+
+# Silicon Blue iCE40
+set_option -maxfan 10000
+set_option -disable_io_insertion 0
+set_option -pipe 1
+set_option -retiming 0
+set_option -update_models_cp 0
+set_option -fixgatedclocks 2
+set_option -fixgeneratedclocks 0
+
+# NFilter
+set_option -popfeed 0
+set_option -constprop 0
+set_option -createhierarchy 0
+
+# sequential_optimization_options
+set_option -symbolic_fsm_compiler 1
+
+# Compiler Options
+set_option -compiler_compatible 0
+set_option -resource_sharing 1
+
+# automatic place and route (vendor) options
+set_option -write_apr_constraint 1
+
+# set result format/file last
+project -result_format edif
+project -result_file impl.edf
+impl -active impl
+project -run synthesis -clean
+EOT
+
+icecubedir="${ICECUBEDIR:-/opt/lscc/iCEcube2.2014.08}"
+export SBT_DIR="$icecubedir/sbt_backend"
+export SYNPLIFY_PATH="$icecubedir/synpbase"
+export LM_LICENSE_FILE="$icecubedir/license.dat"
+export TCL_LIBRARY="$icecubedir/sbt_backend/bin/linux/lib/tcl8.4"
+export LD_LIBRARY_PATH="$LD_LIBRARY_PATH${LD_LIBRARY_PATH:+:}$icecubedir/sbt_backend/bin/linux/opt"
+export LD_LIBRARY_PATH="$LD_LIBRARY_PATH${LD_LIBRARY_PATH:+:}$icecubedir/sbt_backend/bin/linux/opt/synpwrap"
+export LD_LIBRARY_PATH="$LD_LIBRARY_PATH${LD_LIBRARY_PATH:+:}$icecubedir/sbt_backend/lib/linux/opt"
+export LD_LIBRARY_PATH="$LD_LIBRARY_PATH${LD_LIBRARY_PATH:+:}$icecubedir/LSE/bin/lin"
+"$icecubedir"/sbt_backend/bin/linux/opt/synpwrap/synpwrap -prj impl_syn.prj -log impl.srr
+
+grep 'instance.*cellRef' impl/impl.edf | sed 's,.*cellRef *,,; s,[ )].*,,;' | sort | uniq -c
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/vivado.tcl b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/vivado.tcl
new file mode 100644
index 0000000..560b880
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/vivado.tcl
@@ -0,0 +1,3 @@
+read_verilog ../../picorv32.v
+synth_design -part xc7k70t-fbg676 -top picorv32
+report_utilization
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/yosys_ice40.ys b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/yosys_ice40.ys
new file mode 100644
index 0000000..b14b338
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/yosys_ice40.ys
@@ -0,0 +1,2 @@
+read_verilog ../../picorv32.v
+synth_ice40 -top picorv32
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/yosys_xilinx.ys b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/yosys_xilinx.ys
new file mode 100644
index 0000000..ead52a4
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys-cmp/yosys_xilinx.ys
@@ -0,0 +1,2 @@
+read_verilog ../../picorv32.v
+synth_xilinx -top picorv32
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/.gitignore b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/.gitignore
new file mode 100644
index 0000000..d6fc3e3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/.gitignore
@@ -0,0 +1 @@
+osu018_stdcells.lib
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/synth_gates.lib b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/synth_gates.lib
new file mode 100644
index 0000000..be706dd
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/synth_gates.lib
@@ -0,0 +1,38 @@
+library(gates) {
+  cell(NOT) {
+    area: 2; // 7404 hex inverter
+    pin(A) { direction: input; }
+    pin(Y) { direction: output;
+              function: "A'"; }
+  }
+  cell(BUF) {
+    area: 4; // 2x 7404 hex inverter
+    pin(A) { direction: input; }
+    pin(Y) { direction: output;
+              function: "A"; }
+  }
+  cell(NAND) {
+    area: 3; // 7400 quad 2-input NAND gate
+    pin(A) { direction: input; }
+    pin(B) { direction: input; }
+    pin(Y) { direction: output;
+             function: "(A*B)'"; }
+  }
+  cell(NOR) {
+    area: 3; // 7402 quad 2-input NOR gate
+    pin(A) { direction: input; }
+    pin(B) { direction: input; }
+    pin(Y) { direction: output;
+             function: "(A+B)'"; }
+  }
+  cell(DFF) {
+    area: 6; // 7474 dual D positive edge triggered flip-flop
+    ff(IQ, IQN) { clocked_on: C;
+                  next_state: D; }
+    pin(C) { direction: input;
+                 clock: true; }
+    pin(D) { direction: input; }
+    pin(Q) { direction: output;
+              function: "IQ"; }
+  }
+}
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/synth_gates.v b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/synth_gates.v
new file mode 100644
index 0000000..8e2504e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/synth_gates.v
@@ -0,0 +1,30 @@
+module top (
+	input clk, resetn,
+
+	output        mem_valid,
+	output        mem_instr,
+	input         mem_ready,
+
+	output [31:0] mem_addr,
+	output [31:0] mem_wdata,
+	output [ 3:0] mem_wstrb,
+	input  [31:0] mem_rdata
+);
+	picorv32 #(
+		.ENABLE_COUNTERS(0),
+		.LATCHED_MEM_RDATA(1),
+		.TWO_STAGE_SHIFT(0),
+		.CATCH_MISALIGN(0),
+		.CATCH_ILLINSN(0)
+	) picorv32 (
+		.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)
+	);
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/synth_gates.ys b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/synth_gates.ys
new file mode 100644
index 0000000..311d767
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/synth_gates.ys
@@ -0,0 +1,14 @@
+read_verilog synth_gates.v
+read_verilog ../../picorv32.v
+
+hierarchy -top top
+proc; flatten
+
+synth
+
+dfflibmap -prepare -liberty synth_gates.lib
+abc -dff -liberty synth_gates.lib
+dfflibmap -liberty synth_gates.lib
+
+stat
+write_blif synth_gates.blif
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/synth_osu018.sh b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/synth_osu018.sh
new file mode 100644
index 0000000..7a8693d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/synth_osu018.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+set -ex
+if test ! -s osu018_stdcells.lib; then
+	wget --continue -O osu018_stdcells.lib.part http://vlsiarch.ecen.okstate.edu/flows/MOSIS_SCMOS/`
+			`latest/cadence/lib/tsmc018/signalstorm/osu018_stdcells.lib
+	mv osu018_stdcells.lib.part osu018_stdcells.lib
+fi
+yosys -p 'synth -top picorv32; dfflibmap -liberty osu018_stdcells.lib; abc -liberty osu018_stdcells.lib; stat' ../../picorv32.v
diff --git a/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/synth_sim.ys b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/synth_sim.ys
new file mode 100644
index 0000000..ded89d9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/scripts/yosys/synth_sim.ys
@@ -0,0 +1,8 @@
+# yosys synthesis script for post-synthesis simulation (make test_synth)
+
+read_verilog picorv32.v
+chparam -set COMPRESSED_ISA 1 -set ENABLE_MUL 1 -set ENABLE_DIV 1 \
+        -set ENABLE_IRQ 1 -set ENABLE_TRACE 1 picorv32_axi
+hierarchy -top picorv32_axi
+synth
+write_verilog synth.v
diff --git a/verilog/rtl/softshell/third_party/picorv32/shell.nix b/verilog/rtl/softshell/third_party/picorv32/shell.nix
new file mode 100644
index 0000000..92ec1ff
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/shell.nix
@@ -0,0 +1,139 @@
+# nix.shell: PicoRV32 Development Environment
+#
+# This file allows you to use the Nix Package Manager (https://nixos.org/nix)
+# in order to download, install, and prepare a working environment for doing
+# PicoRV32/PicoSoC development on _any_ existing Linux distribution, provided
+# the Nix package manager is installed.
+#
+# Current included tools:
+#
+#   - Synthesis: Recent Yosys and SymbiYosys
+#   - Place and Route: arachne-pnr and nextpnr (ICE40, ECP5, Python, no GUI)
+#   - Packing: Project IceStorm (Trellis tools may be included later?)
+#   - SMT Solvers: Z3 4.7.x, Yices 2.6.x, and Boolector 3.0.x
+#   - Verification: Recent Verilator, Recent (unreleased) Icarus Verilog
+#   - A bare-metal RISC-V cross compiler toolchain, based on GCC 8.2.x
+#
+# With these tools, you can immediately begin development, simulation, firmware
+# hacking, etc with almost no need to fiddle with recent tools yourself. Almost
+# all of the tools will be downloaded on-demand (except the GCC toolchain)
+# meaning you don't have to compile any recent tools yourself. Due to the
+# "hermetic" nature of Nix, these packages should also work on practically any
+# Linux distribution, as well.
+#
+# (This environment should also be suitable for running riscv-formal test
+# harnesses on PicoRV32, as well. In fact it is probably useful for almost
+# _any_ RTL implementation of the RV32I core.)
+#
+# Usage
+# -----
+#
+# At the top-level of the picorv32 directory, simply run the 'nix-shell' command,
+# which will then drop you into a bash prompt:
+#
+#
+#     $ nix-shell
+#     ...
+#     [nix-shell:~/src/picorv32]$
+#
+#
+# When you run 'nix-shell', you will automatically begin downloading all of the
+# various tools you need from an upstream "cache", so most of this will execute
+# very quickly. However, this may take a while, as you will at least have to
+# build a cross-compiled RISC-V toolchain, which may take some time. (These
+# binaries are not available from the cache, so they must be built by you.) Once
+# you have done this once, you do not need to do it again.
+#
+# At this point, once you are inside the shell, you can begin running tests
+# like normal. For example, to run the Verilator tests with the included test
+# firmware, which is substantially faster than Icarus:
+#
+#     [nix-shell:~/src/picorv32]$ make test_verilator TOOLCHAIN_PREFIX=riscv32-unknown-elf-
+#     ...
+#
+#
+# Note that you must override TOOLCHAIN_PREFIX (in the top-level Makefile, it
+# looks in /opt by default).
+#
+# This will work immediately with no extra fiddling necessary. You can also run
+# formal verification tests using a provided SMT solver, for example, yices and
+# boolector (Z3 is not used since it does not complete in a reasonable amount
+# of time for these examples):
+#
+#     [nix-shell:~/src/picorv32]$ make check-yices check-boolector
+#     ...
+#
+# You can also run the PicoSoC tests and build bitstreams. To run the
+# simulation tests and then build bitstreams for the HX8K and IceBreaker
+# boards:
+#
+#     [nix-shell:~/src/picorv32]$ cd picosoc/
+#     [nix-shell:~/src/picorv32/picosoc]$ make hx8ksynsim icebsynsim
+#     ...
+#     [nix-shell:~/src/picorv32/picosoc]$ make hx8kdemo.bin icebreaker.bin
+#     ...
+#
+# The HX8K simulation and IceBreaker simulation will be synthesized with Yosys
+# and then run with Icarus Verilog. The bitstreams for HX8K and IceBreaker will
+# be P&R'd with arachne-pnr and nextpnr, respectively.
+#
+
+{ architecture ? "rv32imc"
+}:
+
+# TODO FIXME: fix this to a specific version of nixpkgs.
+# ALSO: maybe use cachix to make it easier for contributors(?)
+with import <nixpkgs> {};
+
+let
+  # risc-v toolchain source code. TODO FIXME: this should be replaced with
+  # upstream versions of GCC. in the future we could also include LLVM (the
+  # upstream nixpkgs LLVM expression should be built with it in time)
+  riscv-toolchain-ver = "8.2.0";
+  riscv-src = pkgs.fetchFromGitHub {
+    owner  = "riscv";
+    repo   = "riscv-gnu-toolchain";
+    rev    = "c3ad5556197e374c25bc475ffc9285b831f869f8";
+    sha256 = "1j9y3ai42xzzph9rm116sxfzhdlrjrk4z0v4yrk197j72isqyxbc";
+    fetchSubmodules = true;
+  };
+
+  # given an architecture like 'rv32i', this will generate the given
+  # toolchain derivation based on the above source code.
+  make-riscv-toolchain = arch:
+    stdenv.mkDerivation rec {
+      name    = "riscv-${arch}-toolchain-${version}";
+      version = "${riscv-toolchain-ver}-${builtins.substring 0 7 src.rev}";
+      src     = riscv-src;
+
+      configureFlags   = [ "--with-arch=${arch}" ];
+      installPhase     = ":"; # 'make' installs on its own
+      hardeningDisable = [ "all" ];
+      enableParallelBuilding = true;
+
+      # Stripping/fixups break the resulting libgcc.a archives, somehow.
+      # Maybe something in stdenv that does this...
+      dontStrip = true;
+      dontFixup = true;
+
+      nativeBuildInputs = with pkgs; [ curl gawk texinfo bison flex gperf ];
+      buildInputs = with pkgs; [ libmpc mpfr gmp expat ];
+    };
+
+  riscv-toolchain = make-riscv-toolchain architecture;
+
+  # These are all the packages that will be available inside the nix-shell
+  # environment.
+  buildInputs = with pkgs;
+    # these are generally useful packages for tests, verification, synthesis
+    # and deployment, etc
+    [ python3 gcc
+      yosys symbiyosys nextpnr arachne-pnr icestorm
+      z3 boolector yices
+      verilog verilator
+      # also include the RISC-V toolchain
+      riscv-toolchain
+    ];
+
+# Export a usable shell environment
+in runCommand "picorv32-shell" { inherit buildInputs; } ""
diff --git a/verilog/rtl/softshell/third_party/picorv32/showtrace.py b/verilog/rtl/softshell/third_party/picorv32/showtrace.py
new file mode 100644
index 0000000..a5d1021
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/showtrace.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+
+import sys, re, subprocess
+
+trace_filename = sys.argv[1]
+elf_filename = sys.argv[2]
+
+insns = dict()
+
+with subprocess.Popen(["riscv32-unknown-elf-objdump", "-d", elf_filename], stdout=subprocess.PIPE) as proc:
+    while True:
+        line = proc.stdout.readline().decode("ascii")
+        if line == '': break
+        match = re.match(r'^\s*([0-9a-f]+):\s+([0-9a-f]+)\s*(.*)', line)
+        if match: insns[int(match.group(1), 16)] = (int(match.group(2), 16), match.group(3).replace("\t", " "))
+
+with open(trace_filename, "r") as f:
+    pc = -1
+    last_irq = False
+    for line in f:
+        raw_data = int(line.replace("x", "0"), 16)
+        payload = raw_data & 0xffffffff
+        irq_active = (raw_data & 0x800000000) != 0
+        is_addr = (raw_data & 0x200000000) != 0
+        is_branch = (raw_data & 0x100000000) != 0
+        info = "%s %s%08x" % ("IRQ" if irq_active or last_irq else "   ",
+                ">" if is_branch else "@" if is_addr else "=", payload)
+
+        if irq_active and not last_irq:
+            pc = 0x10
+
+        if pc >= 0:
+            if pc in insns:
+                insn_opcode, insn_desc = insns[pc]
+                opname = insn_desc.split()[0]
+
+                if insn_opcode == 0x0400000b:
+                    insn_desc = "retirq"
+                    opname = "retirq"
+
+                if is_branch and opname not in ["j", "jal", "jr", "jalr", "ret", "retirq",
+                        "beq", "bne", "blt", "ble", "bge", "bgt", "bltu", "bleu", "bgeu", "bgtu",
+                        "beqz", "bnez", "blez", "bgez", "bltz", "bgtz"]:
+                    print("%s ** UNEXPECTED BRANCH DATA FOR INSN AT %08x! **" % (info, pc))
+
+                if is_addr and opname not in ["lb", "lh", "lw", "lbu", "lhu", "sb", "sh", "sw"]:
+                    print("%s ** UNEXPECTED ADDR DATA FOR INSN AT %08x! **" % (info, pc))
+
+                opcode_fmt = "%08x" if (insn_opcode & 3) == 3 else "    %04x"
+                print(("%s | %08x | " + opcode_fmt + " | %s") % (info, pc, insn_opcode, insn_desc))
+                if not is_addr:
+                    pc += 4 if (insn_opcode & 3) == 3 else 2
+            else:
+                print("%s ** NO INFORMATION ON INSN AT %08x! **" % (info, pc))
+                pc = -1
+        else:
+            if is_branch:
+                print("%s ** FOUND BRANCH AND STARTING DECODING **" % info)
+            else:
+                print("%s ** SKIPPING DATA UNTIL NEXT BRANCH **" % info)
+
+        if is_branch:
+            pc = payload
+
+        last_irq = irq_active
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/testbench.cc b/verilog/rtl/softshell/third_party/picorv32/testbench.cc
new file mode 100644
index 0000000..61c4366
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/testbench.cc
@@ -0,0 +1,44 @@
+#include "Vpicorv32_wrapper.h"
+#include "verilated_vcd_c.h"
+
+int main(int argc, char **argv, char **env)
+{
+	printf("Built with %s %s.\n", Verilated::productName(), Verilated::productVersion());
+	printf("Recommended: Verilator 4.0 or later.\n");
+
+	Verilated::commandArgs(argc, argv);
+	Vpicorv32_wrapper* top = new Vpicorv32_wrapper;
+
+	// Tracing (vcd)
+	VerilatedVcdC* tfp = NULL;
+	const char* flag_vcd = Verilated::commandArgsPlusMatch("vcd");
+	if (flag_vcd && 0==strcmp(flag_vcd, "+vcd")) {
+		Verilated::traceEverOn(true);
+		tfp = new VerilatedVcdC;
+		top->trace (tfp, 99);
+		tfp->open("testbench.vcd");
+	}
+
+	// Tracing (data bus, see showtrace.py)
+	FILE *trace_fd = NULL;
+	const char* flag_trace = Verilated::commandArgsPlusMatch("trace");
+	if (flag_trace && 0==strcmp(flag_trace, "+trace")) {
+		trace_fd = fopen("testbench.trace", "w");
+	}
+
+	top->clk = 0;
+	int t = 0;
+	while (!Verilated::gotFinish()) {
+		if (t > 200)
+			top->resetn = 1;
+		top->clk = !top->clk;
+		top->eval();
+		if (tfp) tfp->dump (t);
+		if (trace_fd && top->clk && top->trace_valid) fprintf(trace_fd, "%9.9lx\n", top->trace_data);
+		t += 5;
+	}
+	if (tfp) tfp->close();
+	delete top;
+	exit(0);
+}
+
diff --git a/verilog/rtl/softshell/third_party/picorv32/testbench.v b/verilog/rtl/softshell/third_party/picorv32/testbench.v
new file mode 100644
index 0000000..9d8e249
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/testbench.v
@@ -0,0 +1,479 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+
+`timescale 1 ns / 1 ps
+
+`ifndef VERILATOR
+module testbench #(
+	parameter AXI_TEST = 0,
+	parameter VERBOSE = 0
+);
+	reg clk = 1;
+	reg resetn = 0;
+	wire trap;
+
+	always #5 clk = ~clk;
+
+	initial begin
+		repeat (100) @(posedge clk);
+		resetn <= 1;
+	end
+
+	initial begin
+		if ($test$plusargs("vcd")) begin
+			$dumpfile("testbench.vcd");
+			$dumpvars(0, testbench);
+		end
+		repeat (1000000) @(posedge clk);
+		$display("TIMEOUT");
+		$finish;
+	end
+
+	wire trace_valid;
+	wire [35:0] trace_data;
+	integer trace_file;
+
+	initial begin
+		if ($test$plusargs("trace")) begin
+			trace_file = $fopen("testbench.trace", "w");
+			repeat (10) @(posedge clk);
+			while (!trap) begin
+				@(posedge clk);
+				if (trace_valid)
+					$fwrite(trace_file, "%x\n", trace_data);
+			end
+			$fclose(trace_file);
+			$display("Finished writing testbench.trace.");
+		end
+	end
+
+	picorv32_wrapper #(
+		.AXI_TEST (AXI_TEST),
+		.VERBOSE  (VERBOSE)
+	) top (
+		.clk(clk),
+		.resetn(resetn),
+		.trap(trap),
+		.trace_valid(trace_valid),
+		.trace_data(trace_data)
+	);
+endmodule
+`endif
+
+module picorv32_wrapper #(
+	parameter AXI_TEST = 0,
+	parameter VERBOSE = 0
+) (
+	input clk,
+	input resetn,
+	output trap,
+	output trace_valid,
+	output [35:0] trace_data
+);
+	wire tests_passed;
+	reg [31:0] irq = 0;
+
+	reg [15:0] count_cycle = 0;
+	always @(posedge clk) count_cycle <= resetn ? count_cycle + 1 : 0;
+
+	always @* begin
+		irq = 0;
+		irq[4] = &count_cycle[12:0];
+		irq[5] = &count_cycle[15:0];
+	end
+
+	wire        mem_axi_awvalid;
+	wire        mem_axi_awready;
+	wire [31:0] mem_axi_awaddr;
+	wire [ 2:0] mem_axi_awprot;
+
+	wire        mem_axi_wvalid;
+	wire        mem_axi_wready;
+	wire [31:0] mem_axi_wdata;
+	wire [ 3:0] mem_axi_wstrb;
+
+	wire        mem_axi_bvalid;
+	wire        mem_axi_bready;
+
+	wire        mem_axi_arvalid;
+	wire        mem_axi_arready;
+	wire [31:0] mem_axi_araddr;
+	wire [ 2:0] mem_axi_arprot;
+
+	wire        mem_axi_rvalid;
+	wire        mem_axi_rready;
+	wire [31:0] mem_axi_rdata;
+
+	axi4_memory #(
+		.AXI_TEST (AXI_TEST),
+		.VERBOSE  (VERBOSE)
+	) mem (
+		.clk             (clk             ),
+		.mem_axi_awvalid (mem_axi_awvalid ),
+		.mem_axi_awready (mem_axi_awready ),
+		.mem_axi_awaddr  (mem_axi_awaddr  ),
+		.mem_axi_awprot  (mem_axi_awprot  ),
+
+		.mem_axi_wvalid  (mem_axi_wvalid  ),
+		.mem_axi_wready  (mem_axi_wready  ),
+		.mem_axi_wdata   (mem_axi_wdata   ),
+		.mem_axi_wstrb   (mem_axi_wstrb   ),
+
+		.mem_axi_bvalid  (mem_axi_bvalid  ),
+		.mem_axi_bready  (mem_axi_bready  ),
+
+		.mem_axi_arvalid (mem_axi_arvalid ),
+		.mem_axi_arready (mem_axi_arready ),
+		.mem_axi_araddr  (mem_axi_araddr  ),
+		.mem_axi_arprot  (mem_axi_arprot  ),
+
+		.mem_axi_rvalid  (mem_axi_rvalid  ),
+		.mem_axi_rready  (mem_axi_rready  ),
+		.mem_axi_rdata   (mem_axi_rdata   ),
+
+		.tests_passed    (tests_passed    )
+	);
+
+`ifdef RISCV_FORMAL
+	wire        rvfi_valid;
+	wire [63:0] rvfi_order;
+	wire [31:0] rvfi_insn;
+	wire        rvfi_trap;
+	wire        rvfi_halt;
+	wire        rvfi_intr;
+	wire [4:0]  rvfi_rs1_addr;
+	wire [4:0]  rvfi_rs2_addr;
+	wire [31:0] rvfi_rs1_rdata;
+	wire [31:0] rvfi_rs2_rdata;
+	wire [4:0]  rvfi_rd_addr;
+	wire [31:0] rvfi_rd_wdata;
+	wire [31:0] rvfi_pc_rdata;
+	wire [31:0] rvfi_pc_wdata;
+	wire [31:0] rvfi_mem_addr;
+	wire [3:0]  rvfi_mem_rmask;
+	wire [3:0]  rvfi_mem_wmask;
+	wire [31:0] rvfi_mem_rdata;
+	wire [31:0] rvfi_mem_wdata;
+`endif
+
+	picorv32_axi #(
+`ifndef SYNTH_TEST
+`ifdef SP_TEST
+		.ENABLE_REGS_DUALPORT(0),
+`endif
+`ifdef COMPRESSED_ISA
+		.COMPRESSED_ISA(1),
+`endif
+		.ENABLE_MUL(1),
+		.ENABLE_DIV(1),
+		.ENABLE_IRQ(1),
+		.ENABLE_TRACE(1)
+`endif
+	) uut (
+		.clk            (clk            ),
+		.resetn         (resetn         ),
+		.trap           (trap           ),
+		.mem_axi_awvalid(mem_axi_awvalid),
+		.mem_axi_awready(mem_axi_awready),
+		.mem_axi_awaddr (mem_axi_awaddr ),
+		.mem_axi_awprot (mem_axi_awprot ),
+		.mem_axi_wvalid (mem_axi_wvalid ),
+		.mem_axi_wready (mem_axi_wready ),
+		.mem_axi_wdata  (mem_axi_wdata  ),
+		.mem_axi_wstrb  (mem_axi_wstrb  ),
+		.mem_axi_bvalid (mem_axi_bvalid ),
+		.mem_axi_bready (mem_axi_bready ),
+		.mem_axi_arvalid(mem_axi_arvalid),
+		.mem_axi_arready(mem_axi_arready),
+		.mem_axi_araddr (mem_axi_araddr ),
+		.mem_axi_arprot (mem_axi_arprot ),
+		.mem_axi_rvalid (mem_axi_rvalid ),
+		.mem_axi_rready (mem_axi_rready ),
+		.mem_axi_rdata  (mem_axi_rdata  ),
+		.irq            (irq            ),
+`ifdef RISCV_FORMAL
+		.rvfi_valid     (rvfi_valid     ),
+		.rvfi_order     (rvfi_order     ),
+		.rvfi_insn      (rvfi_insn      ),
+		.rvfi_trap      (rvfi_trap      ),
+		.rvfi_halt      (rvfi_halt      ),
+		.rvfi_intr      (rvfi_intr      ),
+		.rvfi_rs1_addr  (rvfi_rs1_addr  ),
+		.rvfi_rs2_addr  (rvfi_rs2_addr  ),
+		.rvfi_rs1_rdata (rvfi_rs1_rdata ),
+		.rvfi_rs2_rdata (rvfi_rs2_rdata ),
+		.rvfi_rd_addr   (rvfi_rd_addr   ),
+		.rvfi_rd_wdata  (rvfi_rd_wdata  ),
+		.rvfi_pc_rdata  (rvfi_pc_rdata  ),
+		.rvfi_pc_wdata  (rvfi_pc_wdata  ),
+		.rvfi_mem_addr  (rvfi_mem_addr  ),
+		.rvfi_mem_rmask (rvfi_mem_rmask ),
+		.rvfi_mem_wmask (rvfi_mem_wmask ),
+		.rvfi_mem_rdata (rvfi_mem_rdata ),
+		.rvfi_mem_wdata (rvfi_mem_wdata ),
+`endif
+		.trace_valid    (trace_valid    ),
+		.trace_data     (trace_data     )
+	);
+
+`ifdef RISCV_FORMAL
+	picorv32_rvfimon rvfi_monitor (
+		.clock          (clk           ),
+		.reset          (!resetn       ),
+		.rvfi_valid     (rvfi_valid    ),
+		.rvfi_order     (rvfi_order    ),
+		.rvfi_insn      (rvfi_insn     ),
+		.rvfi_trap      (rvfi_trap     ),
+		.rvfi_halt      (rvfi_halt     ),
+		.rvfi_intr      (rvfi_intr     ),
+		.rvfi_rs1_addr  (rvfi_rs1_addr ),
+		.rvfi_rs2_addr  (rvfi_rs2_addr ),
+		.rvfi_rs1_rdata (rvfi_rs1_rdata),
+		.rvfi_rs2_rdata (rvfi_rs2_rdata),
+		.rvfi_rd_addr   (rvfi_rd_addr  ),
+		.rvfi_rd_wdata  (rvfi_rd_wdata ),
+		.rvfi_pc_rdata  (rvfi_pc_rdata ),
+		.rvfi_pc_wdata  (rvfi_pc_wdata ),
+		.rvfi_mem_addr  (rvfi_mem_addr ),
+		.rvfi_mem_rmask (rvfi_mem_rmask),
+		.rvfi_mem_wmask (rvfi_mem_wmask),
+		.rvfi_mem_rdata (rvfi_mem_rdata),
+		.rvfi_mem_wdata (rvfi_mem_wdata)
+	);
+`endif
+
+	reg [1023:0] firmware_file;
+	initial begin
+		if (!$value$plusargs("firmware=%s", firmware_file))
+			firmware_file = "firmware/firmware.hex";
+		$readmemh(firmware_file, mem.memory);
+	end
+
+	integer cycle_counter;
+	always @(posedge clk) begin
+		cycle_counter <= resetn ? cycle_counter + 1 : 0;
+		if (resetn && trap) begin
+`ifndef VERILATOR
+			repeat (10) @(posedge clk);
+`endif
+			$display("TRAP after %1d clock cycles", cycle_counter);
+			if (tests_passed) begin
+				$display("ALL TESTS PASSED.");
+				$finish;
+			end else begin
+				$display("ERROR!");
+				if ($test$plusargs("noerror"))
+					$finish;
+				$stop;
+			end
+		end
+	end
+endmodule
+
+module axi4_memory #(
+	parameter AXI_TEST = 0,
+	parameter VERBOSE = 0
+) (
+	/* verilator lint_off MULTIDRIVEN */
+
+	input             clk,
+	input             mem_axi_awvalid,
+	output reg        mem_axi_awready,
+	input      [31:0] mem_axi_awaddr,
+	input      [ 2:0] mem_axi_awprot,
+
+	input             mem_axi_wvalid,
+	output reg        mem_axi_wready,
+	input      [31:0] mem_axi_wdata,
+	input      [ 3:0] mem_axi_wstrb,
+
+	output reg        mem_axi_bvalid,
+	input             mem_axi_bready,
+
+	input             mem_axi_arvalid,
+	output reg        mem_axi_arready,
+	input      [31:0] mem_axi_araddr,
+	input      [ 2:0] mem_axi_arprot,
+
+	output reg        mem_axi_rvalid,
+	input             mem_axi_rready,
+	output reg [31:0] mem_axi_rdata,
+
+	output reg        tests_passed
+);
+	reg [31:0]   memory [0:128*1024/4-1] /* verilator public */;
+	reg verbose;
+	initial verbose = $test$plusargs("verbose") || VERBOSE;
+
+	reg axi_test;
+	initial axi_test = $test$plusargs("axi_test") || AXI_TEST;
+
+	initial begin
+		mem_axi_awready = 0;
+		mem_axi_wready = 0;
+		mem_axi_bvalid = 0;
+		mem_axi_arready = 0;
+		mem_axi_rvalid = 0;
+		tests_passed = 0;
+	end
+
+	reg [63:0] xorshift64_state = 64'd88172645463325252;
+
+	task xorshift64_next;
+		begin
+			// see page 4 of Marsaglia, George (July 2003). "Xorshift RNGs". Journal of Statistical Software 8 (14).
+			xorshift64_state = xorshift64_state ^ (xorshift64_state << 13);
+			xorshift64_state = xorshift64_state ^ (xorshift64_state >>  7);
+			xorshift64_state = xorshift64_state ^ (xorshift64_state << 17);
+		end
+	endtask
+
+	reg [2:0] fast_axi_transaction = ~0;
+	reg [4:0] async_axi_transaction = ~0;
+	reg [4:0] delay_axi_transaction = 0;
+
+	always @(posedge clk) begin
+		if (axi_test) begin
+				xorshift64_next;
+				{fast_axi_transaction, async_axi_transaction, delay_axi_transaction} <= xorshift64_state;
+		end
+	end
+
+	reg latched_raddr_en = 0;
+	reg latched_waddr_en = 0;
+	reg latched_wdata_en = 0;
+
+	reg fast_raddr = 0;
+	reg fast_waddr = 0;
+	reg fast_wdata = 0;
+
+	reg [31:0] latched_raddr;
+	reg [31:0] latched_waddr;
+	reg [31:0] latched_wdata;
+	reg [ 3:0] latched_wstrb;
+	reg        latched_rinsn;
+
+	task handle_axi_arvalid; begin
+		mem_axi_arready <= 1;
+		latched_raddr = mem_axi_araddr;
+		latched_rinsn = mem_axi_arprot[2];
+		latched_raddr_en = 1;
+		fast_raddr <= 1;
+	end endtask
+
+	task handle_axi_awvalid; begin
+		mem_axi_awready <= 1;
+		latched_waddr = mem_axi_awaddr;
+		latched_waddr_en = 1;
+		fast_waddr <= 1;
+	end endtask
+
+	task handle_axi_wvalid; begin
+		mem_axi_wready <= 1;
+		latched_wdata = mem_axi_wdata;
+		latched_wstrb = mem_axi_wstrb;
+		latched_wdata_en = 1;
+		fast_wdata <= 1;
+	end endtask
+
+	task handle_axi_rvalid; begin
+		if (verbose)
+			$display("RD: ADDR=%08x DATA=%08x%s", latched_raddr, memory[latched_raddr >> 2], latched_rinsn ? " INSN" : "");
+		if (latched_raddr < 128*1024) begin
+			mem_axi_rdata <= memory[latched_raddr >> 2];
+			mem_axi_rvalid <= 1;
+			latched_raddr_en = 0;
+		end else begin
+			$display("OUT-OF-BOUNDS MEMORY READ FROM %08x", latched_raddr);
+			$finish;
+		end
+	end endtask
+
+	task handle_axi_bvalid; begin
+		if (verbose)
+			$display("WR: ADDR=%08x DATA=%08x STRB=%04b", latched_waddr, latched_wdata, latched_wstrb);
+		if (latched_waddr < 128*1024) begin
+			if (latched_wstrb[0]) memory[latched_waddr >> 2][ 7: 0] <= latched_wdata[ 7: 0];
+			if (latched_wstrb[1]) memory[latched_waddr >> 2][15: 8] <= latched_wdata[15: 8];
+			if (latched_wstrb[2]) memory[latched_waddr >> 2][23:16] <= latched_wdata[23:16];
+			if (latched_wstrb[3]) memory[latched_waddr >> 2][31:24] <= latched_wdata[31:24];
+		end else
+		if (latched_waddr == 32'h1000_0000) begin
+			if (verbose) begin
+				if (32 <= latched_wdata && latched_wdata < 128)
+					$display("OUT: '%c'", latched_wdata[7:0]);
+				else
+					$display("OUT: %3d", latched_wdata);
+			end else begin
+				$write("%c", latched_wdata[7:0]);
+`ifndef VERILATOR
+				$fflush();
+`endif
+			end
+		end else
+		if (latched_waddr == 32'h2000_0000) begin
+			if (latched_wdata == 123456789)
+				tests_passed = 1;
+		end else begin
+			$display("OUT-OF-BOUNDS MEMORY WRITE TO %08x", latched_waddr);
+			$finish;
+		end
+		mem_axi_bvalid <= 1;
+		latched_waddr_en = 0;
+		latched_wdata_en = 0;
+	end endtask
+
+	always @(negedge clk) begin
+		if (mem_axi_arvalid && !(latched_raddr_en || fast_raddr) && async_axi_transaction[0]) handle_axi_arvalid;
+		if (mem_axi_awvalid && !(latched_waddr_en || fast_waddr) && async_axi_transaction[1]) handle_axi_awvalid;
+		if (mem_axi_wvalid  && !(latched_wdata_en || fast_wdata) && async_axi_transaction[2]) handle_axi_wvalid;
+		if (!mem_axi_rvalid && latched_raddr_en && async_axi_transaction[3]) handle_axi_rvalid;
+		if (!mem_axi_bvalid && latched_waddr_en && latched_wdata_en && async_axi_transaction[4]) handle_axi_bvalid;
+	end
+
+	always @(posedge clk) begin
+		mem_axi_arready <= 0;
+		mem_axi_awready <= 0;
+		mem_axi_wready <= 0;
+
+		fast_raddr <= 0;
+		fast_waddr <= 0;
+		fast_wdata <= 0;
+
+		if (mem_axi_rvalid && mem_axi_rready) begin
+			mem_axi_rvalid <= 0;
+		end
+
+		if (mem_axi_bvalid && mem_axi_bready) begin
+			mem_axi_bvalid <= 0;
+		end
+
+		if (mem_axi_arvalid && mem_axi_arready && !fast_raddr) begin
+			latched_raddr = mem_axi_araddr;
+			latched_rinsn = mem_axi_arprot[2];
+			latched_raddr_en = 1;
+		end
+
+		if (mem_axi_awvalid && mem_axi_awready && !fast_waddr) begin
+			latched_waddr = mem_axi_awaddr;
+			latched_waddr_en = 1;
+		end
+
+		if (mem_axi_wvalid && mem_axi_wready && !fast_wdata) begin
+			latched_wdata = mem_axi_wdata;
+			latched_wstrb = mem_axi_wstrb;
+			latched_wdata_en = 1;
+		end
+
+		if (mem_axi_arvalid && !(latched_raddr_en || fast_raddr) && !delay_axi_transaction[0]) handle_axi_arvalid;
+		if (mem_axi_awvalid && !(latched_waddr_en || fast_waddr) && !delay_axi_transaction[1]) handle_axi_awvalid;
+		if (mem_axi_wvalid  && !(latched_wdata_en || fast_wdata) && !delay_axi_transaction[2]) handle_axi_wvalid;
+
+		if (!mem_axi_rvalid && latched_raddr_en && !delay_axi_transaction[3]) handle_axi_rvalid;
+		if (!mem_axi_bvalid && latched_waddr_en && latched_wdata_en && !delay_axi_transaction[4]) handle_axi_bvalid;
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/testbench_ez.v b/verilog/rtl/softshell/third_party/picorv32/testbench_ez.v
new file mode 100644
index 0000000..55c9c69
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/testbench_ez.v
@@ -0,0 +1,86 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+
+`timescale 1 ns / 1 ps
+
+module testbench;
+	reg clk = 1;
+	reg resetn = 0;
+	wire trap;
+
+	always #5 clk = ~clk;
+
+	initial begin
+		if ($test$plusargs("vcd")) begin
+			$dumpfile("testbench.vcd");
+			$dumpvars(0, testbench);
+		end
+		repeat (100) @(posedge clk);
+		resetn <= 1;
+		repeat (1000) @(posedge clk);
+		$finish;
+	end
+
+	wire mem_valid;
+	wire mem_instr;
+	reg mem_ready;
+	wire [31:0] mem_addr;
+	wire [31:0] mem_wdata;
+	wire [3:0] mem_wstrb;
+	reg  [31:0] mem_rdata;
+
+	always @(posedge clk) begin
+		if (mem_valid && mem_ready) begin
+			if (mem_instr)
+				$display("ifetch 0x%08x: 0x%08x", mem_addr, mem_rdata);
+			else if (mem_wstrb)
+				$display("write  0x%08x: 0x%08x (wstrb=%b)", mem_addr, mem_wdata, mem_wstrb);
+			else
+				$display("read   0x%08x: 0x%08x", mem_addr, mem_rdata);
+		end
+	end
+
+	picorv32 #(
+	) uut (
+		.clk         (clk        ),
+		.resetn      (resetn     ),
+		.trap        (trap       ),
+		.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  )
+	);
+
+	reg [31:0] memory [0:255];
+
+	initial begin
+		memory[0] = 32'h 3fc00093; //       li      x1,1020
+		memory[1] = 32'h 0000a023; //       sw      x0,0(x1)
+		memory[2] = 32'h 0000a103; // loop: lw      x2,0(x1)
+		memory[3] = 32'h 00110113; //       addi    x2,x2,1
+		memory[4] = 32'h 0020a023; //       sw      x2,0(x1)
+		memory[5] = 32'h ff5ff06f; //       j       <loop>
+	end
+
+	always @(posedge clk) begin
+		mem_ready <= 0;
+		if (mem_valid && !mem_ready) begin
+			if (mem_addr < 1024) begin
+				mem_ready <= 1;
+				mem_rdata <= memory[mem_addr >> 2];
+				if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
+				if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
+				if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16];
+				if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24];
+			end
+			/* add memory-mapped IO here */
+		end
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/testbench_wb.v b/verilog/rtl/softshell/third_party/picorv32/testbench_wb.v
new file mode 100644
index 0000000..4e1a8eb
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/testbench_wb.v
@@ -0,0 +1,293 @@
+`timescale 1 ns / 1 ps
+
+`ifndef VERILATOR
+module testbench #(
+	parameter VERBOSE = 0
+);
+	reg clk = 1;
+	reg resetn = 1;
+	wire trap;
+
+	always #5 clk = ~clk;
+
+	initial begin
+		repeat (100) @(posedge clk);
+		resetn <= 0;
+	end
+
+	initial begin
+		if ($test$plusargs("vcd")) begin
+			$dumpfile("testbench.vcd");
+			$dumpvars(0, testbench);
+		end
+		repeat (1000000) @(posedge clk);
+		$display("TIMEOUT");
+		$finish;
+	end
+
+	wire trace_valid;
+	wire [35:0] trace_data;
+	integer trace_file;
+
+	initial begin
+		if ($test$plusargs("trace")) begin
+			trace_file = $fopen("testbench.trace", "w");
+			repeat (10) @(posedge clk);
+			while (!trap) begin
+				@(posedge clk);
+				if (trace_valid)
+					$fwrite(trace_file, "%x\n", trace_data);
+			end
+			$fclose(trace_file);
+			$display("Finished writing testbench.trace.");
+		end
+	end
+
+	picorv32_wrapper #(
+		.VERBOSE (VERBOSE)
+	) top (
+		.wb_clk(clk),
+		.wb_rst(resetn),
+		.trap(trap),
+		.trace_valid(trace_valid),
+		.trace_data(trace_data)
+	);
+endmodule
+`endif
+
+module picorv32_wrapper #(
+	parameter VERBOSE = 0
+) (
+	input wb_clk,
+	input wb_rst,
+	output trap,
+	output trace_valid,
+	output [35:0] trace_data
+);
+	wire tests_passed;
+	reg [31:0] irq = 0;
+	wire mem_instr;
+
+	reg [15:0] count_cycle = 0;
+	always @(posedge wb_clk) count_cycle <= !wb_rst ? count_cycle + 1 : 0;
+
+	always @* begin
+		irq = 0;
+		irq[4] = &count_cycle[12:0];
+		irq[5] = &count_cycle[15:0];
+	end
+
+	wire [31:0] wb_m2s_adr;
+	wire [31:0] wb_m2s_dat;
+	wire [3:0] wb_m2s_sel;
+	wire wb_m2s_we;
+	wire wb_m2s_cyc;
+	wire wb_m2s_stb;
+	wire [31:0] wb_s2m_dat;
+	wire wb_s2m_ack;
+
+	wb_ram #(
+		.depth (128*1024),
+		.VERBOSE (VERBOSE)
+	) ram ( // Wishbone interface
+		.wb_clk_i(wb_clk),
+		.wb_rst_i(wb_rst),
+
+		.wb_adr_i(wb_m2s_adr),
+		.wb_dat_i(wb_m2s_dat),
+		.wb_stb_i(wb_m2s_stb),
+		.wb_cyc_i(wb_m2s_cyc),
+		.wb_dat_o(wb_s2m_dat),
+		.wb_ack_o(wb_s2m_ack),
+		.wb_sel_i(wb_m2s_sel),
+		.wb_we_i(wb_m2s_we),
+
+		.mem_instr(mem_instr),
+		.tests_passed(tests_passed)
+	);
+
+	picorv32_wb #(
+`ifndef SYNTH_TEST
+`ifdef SP_TEST
+		.ENABLE_REGS_DUALPORT(0),
+`endif
+`ifdef COMPRESSED_ISA
+		.COMPRESSED_ISA(1),
+`endif
+		.ENABLE_MUL(1),
+		.ENABLE_DIV(1),
+		.ENABLE_IRQ(1),
+		.ENABLE_TRACE(1)
+`endif
+	) uut (
+		.trap (trap),
+		.irq (irq),
+		.trace_valid (trace_valid),
+		.trace_data (trace_data),
+		.mem_instr(mem_instr),
+
+		.wb_clk_i(wb_clk),
+		.wb_rst_i(wb_rst),
+
+		.wbm_adr_o(wb_m2s_adr),
+		.wbm_dat_i(wb_s2m_dat),
+		.wbm_stb_o(wb_m2s_stb),
+		.wbm_ack_i(wb_s2m_ack),
+		.wbm_cyc_o(wb_m2s_cyc),
+		.wbm_dat_o(wb_m2s_dat),
+		.wbm_we_o(wb_m2s_we),
+		.wbm_sel_o(wb_m2s_sel)
+	);
+
+	reg [1023:0] firmware_file;
+	initial begin
+		if (!$value$plusargs("firmware=%s", firmware_file))
+			firmware_file = "firmware/firmware.hex";
+		$readmemh(firmware_file, ram.mem);
+	end
+
+	integer cycle_counter;
+	always @(posedge wb_clk) begin
+		cycle_counter <= !wb_rst ? cycle_counter + 1 : 0;
+		if (!wb_rst && trap) begin
+`ifndef VERILATOR
+			repeat (10) @(posedge wb_clk);
+`endif
+			$display("TRAP after %1d clock cycles", cycle_counter);
+			if (tests_passed) begin
+				$display("ALL TESTS PASSED.");
+				$finish;
+			end else begin
+				$display("ERROR!");
+				if ($test$plusargs("noerror"))
+					$finish;
+				$stop;
+			end
+		end
+	end
+endmodule
+
+/* ISC License
+ *
+ * Verilog on-chip RAM with Wishbone interface
+ *
+ * Copyright (C) 2014, 2016 Olof Kindgren <olof.kindgren@gmail.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 wb_ram #(
+	parameter depth = 256,
+	parameter memfile = "",
+	parameter VERBOSE = 0
+) (
+	input wb_clk_i,
+	input wb_rst_i,
+
+	input [31:0] wb_adr_i,
+	input [31:0] wb_dat_i,
+	input [3:0] wb_sel_i,
+	input wb_we_i,
+	input wb_cyc_i,
+	input wb_stb_i,
+
+	output reg wb_ack_o,
+	output reg [31:0] wb_dat_o,
+
+	input mem_instr,
+	output reg tests_passed
+);
+
+	reg verbose;
+	initial verbose = $test$plusargs("verbose") || VERBOSE;
+
+	initial tests_passed = 0;
+
+	reg [31:0] adr_r;
+	wire valid = wb_cyc_i & wb_stb_i;
+
+	always @(posedge wb_clk_i) begin
+		adr_r <= wb_adr_i;
+		// Ack generation
+		wb_ack_o <= valid & !wb_ack_o;
+		if (wb_rst_i)
+		begin
+			adr_r <= {32{1'b0}};
+			wb_ack_o <= 1'b0;
+		end
+	end
+
+	wire ram_we = wb_we_i & valid & wb_ack_o;
+
+	wire [31:0] waddr = adr_r[31:2];
+	wire [31:0] raddr = wb_adr_i[31:2];
+	wire [3:0] we = {4{ram_we}} & wb_sel_i;
+
+	wire [$clog2(depth/4)-1:0] raddr2 = raddr[$clog2(depth/4)-1:0];
+	wire [$clog2(depth/4)-1:0] waddr2 = waddr[$clog2(depth/4)-1:0];
+
+	reg [31:0] mem [0:depth/4-1] /* verilator public */;
+
+	always @(posedge wb_clk_i) begin
+		if (ram_we) begin
+			if (verbose)
+				$display("WR: ADDR=%08x DATA=%08x STRB=%04b",
+					adr_r, wb_dat_i, we);
+
+			if (adr_r[31:0] == 32'h1000_0000)
+				if (verbose) begin
+					if (32 <= wb_dat_i[7:0] && wb_dat_i[7:0] < 128)
+						$display("OUT: '%c'", wb_dat_i[7:0]);
+					else
+						$display("OUT: %3d", wb_dat_i[7:0]);
+				end else begin
+					$write("%c", wb_dat_i[7:0]);
+`ifndef VERILATOR
+					$fflush();
+`endif
+				end
+			else
+			if (adr_r[31:0] == 32'h2000_0000)
+				if (wb_dat_i[31:0] == 123456789)
+					tests_passed = 1;
+		end
+	end
+
+	always @(posedge wb_clk_i) begin
+		if (waddr2 < 128 * 1024 / 4) begin
+			if (we[0])
+				mem[waddr2][7:0] <= wb_dat_i[7:0];
+
+			if (we[1])
+				mem[waddr2][15:8] <= wb_dat_i[15:8];
+
+			if (we[2])
+				mem[waddr2][23:16] <= wb_dat_i[23:16];
+
+			if (we[3])
+				mem[waddr2][31:24] <= wb_dat_i[31:24];
+
+		end
+
+		if (valid & wb_ack_o & !ram_we)
+			if (verbose)
+				$display("RD: ADDR=%08x DATA=%08x%s", adr_r, mem[raddr2], mem_instr ? " INSN" : "");
+
+		wb_dat_o <= mem[raddr2];
+	end
+
+	initial begin
+		if (memfile != "")
+			$readmemh(memfile, mem);
+	end
+endmodule
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/LICENSE b/verilog/rtl/softshell/third_party/picorv32/tests/LICENSE
new file mode 100644
index 0000000..48fe522
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2012-2015, The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the Regents nor the
+   names of its contributors may be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
+OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
+BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
+HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
+MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/README b/verilog/rtl/softshell/third_party/picorv32/tests/README
new file mode 100644
index 0000000..3c1a912
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/README
@@ -0,0 +1 @@
+Tests from https://github.com/riscv/riscv-tests/tree/master/isa/rv32ui
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/add.S b/verilog/rtl/softshell/third_party/picorv32/tests/add.S
new file mode 100644
index 0000000..2eb330e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/add.S
@@ -0,0 +1,85 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# add.S
+#-----------------------------------------------------------------------------
+#
+# Test add instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2,  add, 0x00000000, 0x00000000, 0x00000000 );
+  TEST_RR_OP( 3,  add, 0x00000002, 0x00000001, 0x00000001 );
+  TEST_RR_OP( 4,  add, 0x0000000a, 0x00000003, 0x00000007 );
+
+  TEST_RR_OP( 5,  add, 0xffff8000, 0x00000000, 0xffff8000 );
+  TEST_RR_OP( 6,  add, 0x80000000, 0x80000000, 0x00000000 );
+  TEST_RR_OP( 7,  add, 0x7fff8000, 0x80000000, 0xffff8000 );
+
+  TEST_RR_OP( 8,  add, 0x00007fff, 0x00000000, 0x00007fff );
+  TEST_RR_OP( 9,  add, 0x7fffffff, 0x7fffffff, 0x00000000 );
+  TEST_RR_OP( 10, add, 0x80007ffe, 0x7fffffff, 0x00007fff );
+
+  TEST_RR_OP( 11, add, 0x80007fff, 0x80000000, 0x00007fff );
+  TEST_RR_OP( 12, add, 0x7fff7fff, 0x7fffffff, 0xffff8000 );
+
+  TEST_RR_OP( 13, add, 0xffffffff, 0x00000000, 0xffffffff );
+  TEST_RR_OP( 14, add, 0x00000000, 0xffffffff, 0x00000001 );
+  TEST_RR_OP( 15, add, 0xfffffffe, 0xffffffff, 0xffffffff );
+
+  TEST_RR_OP( 16, add, 0x80000000, 0x00000001, 0x7fffffff );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_RR_SRC1_EQ_DEST( 17, add, 24, 13, 11 );
+  TEST_RR_SRC2_EQ_DEST( 18, add, 25, 14, 11 );
+  TEST_RR_SRC12_EQ_DEST( 19, add, 26, 13 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_RR_DEST_BYPASS( 20, 0, add, 24, 13, 11 );
+  TEST_RR_DEST_BYPASS( 21, 1, add, 25, 14, 11 );
+  TEST_RR_DEST_BYPASS( 22, 2, add, 26, 15, 11 );
+
+  TEST_RR_SRC12_BYPASS( 23, 0, 0, add, 24, 13, 11 );
+  TEST_RR_SRC12_BYPASS( 24, 0, 1, add, 25, 14, 11 );
+  TEST_RR_SRC12_BYPASS( 25, 0, 2, add, 26, 15, 11 );
+  TEST_RR_SRC12_BYPASS( 26, 1, 0, add, 24, 13, 11 );
+  TEST_RR_SRC12_BYPASS( 27, 1, 1, add, 25, 14, 11 );
+  TEST_RR_SRC12_BYPASS( 28, 2, 0, add, 26, 15, 11 );
+
+  TEST_RR_SRC21_BYPASS( 29, 0, 0, add, 24, 13, 11 );
+  TEST_RR_SRC21_BYPASS( 30, 0, 1, add, 25, 14, 11 );
+  TEST_RR_SRC21_BYPASS( 31, 0, 2, add, 26, 15, 11 );
+  TEST_RR_SRC21_BYPASS( 32, 1, 0, add, 24, 13, 11 );
+  TEST_RR_SRC21_BYPASS( 33, 1, 1, add, 25, 14, 11 );
+  TEST_RR_SRC21_BYPASS( 34, 2, 0, add, 26, 15, 11 );
+
+  TEST_RR_ZEROSRC1( 35, add, 15, 15 );
+  TEST_RR_ZEROSRC2( 36, add, 32, 32 );
+  TEST_RR_ZEROSRC12( 37, add, 0 );
+  TEST_RR_ZERODEST( 38, add, 16, 30 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/addi.S b/verilog/rtl/softshell/third_party/picorv32/tests/addi.S
new file mode 100644
index 0000000..f7a418b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/addi.S
@@ -0,0 +1,71 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# addi.S
+#-----------------------------------------------------------------------------
+#
+# Test addi instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_OP( 2,  addi, 0x00000000, 0x00000000, 0x000 );
+  TEST_IMM_OP( 3,  addi, 0x00000002, 0x00000001, 0x001 );
+  TEST_IMM_OP( 4,  addi, 0x0000000a, 0x00000003, 0x007 );
+
+  TEST_IMM_OP( 5,  addi, 0xfffff800, 0x00000000, 0x800 );
+  TEST_IMM_OP( 6,  addi, 0x80000000, 0x80000000, 0x000 );
+  TEST_IMM_OP( 7,  addi, 0x7ffff800, 0x80000000, 0x800 );
+
+  TEST_IMM_OP( 8,  addi, 0x000007ff, 0x00000000, 0x7ff );
+  TEST_IMM_OP( 9,  addi, 0x7fffffff, 0x7fffffff, 0x000 );
+  TEST_IMM_OP( 10, addi, 0x800007fe, 0x7fffffff, 0x7ff );
+
+  TEST_IMM_OP( 11, addi, 0x800007ff, 0x80000000, 0x7ff );
+  TEST_IMM_OP( 12, addi, 0x7ffff7ff, 0x7fffffff, 0x800 );
+
+  TEST_IMM_OP( 13, addi, 0xffffffff, 0x00000000, 0xfff );
+  TEST_IMM_OP( 14, addi, 0x00000000, 0xffffffff, 0x001 );
+  TEST_IMM_OP( 15, addi, 0xfffffffe, 0xffffffff, 0xfff );
+
+  TEST_IMM_OP( 16, addi, 0x80000000, 0x7fffffff, 0x001 );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_SRC1_EQ_DEST( 17, addi, 24, 13, 11 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_DEST_BYPASS( 18, 0, addi, 24, 13, 11 );
+  TEST_IMM_DEST_BYPASS( 19, 1, addi, 23, 13, 10 );
+  TEST_IMM_DEST_BYPASS( 20, 2, addi, 22, 13,  9 );
+
+  TEST_IMM_SRC1_BYPASS( 21, 0, addi, 24, 13, 11 );
+  TEST_IMM_SRC1_BYPASS( 22, 1, addi, 23, 13, 10 );
+  TEST_IMM_SRC1_BYPASS( 23, 2, addi, 22, 13,  9 );
+
+  TEST_IMM_ZEROSRC1( 24, addi, 32, 32 );
+  TEST_IMM_ZERODEST( 25, addi, 33, 50 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/and.S b/verilog/rtl/softshell/third_party/picorv32/tests/and.S
new file mode 100644
index 0000000..561ae3b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/and.S
@@ -0,0 +1,69 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# and.S
+#-----------------------------------------------------------------------------
+#
+# Test and instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Logical tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_OP( 3, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_OP( 4, and, 0x000f000f, 0x00ff00ff, 0x0f0f0f0f );
+  TEST_RR_OP( 5, and, 0xf000f000, 0xf00ff00f, 0xf0f0f0f0 );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_RR_SRC1_EQ_DEST( 6, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC2_EQ_DEST( 7, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_SRC12_EQ_DEST( 8, and, 0xff00ff00, 0xff00ff00 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_RR_DEST_BYPASS( 9,  0, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_DEST_BYPASS( 10, 1, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_DEST_BYPASS( 11, 2, and, 0x000f000f, 0x00ff00ff, 0x0f0f0f0f );
+
+  TEST_RR_SRC12_BYPASS( 12, 0, 0, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC12_BYPASS( 13, 0, 1, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_SRC12_BYPASS( 14, 0, 2, and, 0x000f000f, 0x00ff00ff, 0x0f0f0f0f );
+  TEST_RR_SRC12_BYPASS( 15, 1, 0, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC12_BYPASS( 16, 1, 1, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_SRC12_BYPASS( 17, 2, 0, and, 0x000f000f, 0x00ff00ff, 0x0f0f0f0f );
+
+  TEST_RR_SRC21_BYPASS( 18, 0, 0, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC21_BYPASS( 19, 0, 1, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_SRC21_BYPASS( 20, 0, 2, and, 0x000f000f, 0x00ff00ff, 0x0f0f0f0f );
+  TEST_RR_SRC21_BYPASS( 21, 1, 0, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC21_BYPASS( 22, 1, 1, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_SRC21_BYPASS( 23, 2, 0, and, 0x000f000f, 0x00ff00ff, 0x0f0f0f0f );
+
+  TEST_RR_ZEROSRC1( 24, and, 0, 0xff00ff00 );
+  TEST_RR_ZEROSRC2( 25, and, 0, 0x00ff00ff );
+  TEST_RR_ZEROSRC12( 26, and, 0 );
+  TEST_RR_ZERODEST( 27, and, 0x11111111, 0x22222222 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/andi.S b/verilog/rtl/softshell/third_party/picorv32/tests/andi.S
new file mode 100644
index 0000000..c2ae94d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/andi.S
@@ -0,0 +1,55 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# andi.S
+#-----------------------------------------------------------------------------
+#
+# Test andi instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Logical tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_OP( 2, andi, 0xff00ff00, 0xff00ff00, 0xf0f );
+  TEST_IMM_OP( 3, andi, 0x000000f0, 0x0ff00ff0, 0x0f0 );
+  TEST_IMM_OP( 4, andi, 0x0000000f, 0x00ff00ff, 0x70f );
+  TEST_IMM_OP( 5, andi, 0x00000000, 0xf00ff00f, 0x0f0 );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_SRC1_EQ_DEST( 6, andi, 0x00000000, 0xff00ff00, 0x0f0 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_DEST_BYPASS( 7,  0, andi, 0x00000700, 0x0ff00ff0, 0x70f );
+  TEST_IMM_DEST_BYPASS( 8,  1, andi, 0x000000f0, 0x00ff00ff, 0x0f0 );
+  TEST_IMM_DEST_BYPASS( 9,  2, andi, 0xf00ff00f, 0xf00ff00f, 0xf0f );
+
+  TEST_IMM_SRC1_BYPASS( 10, 0, andi, 0x00000700, 0x0ff00ff0, 0x70f );
+  TEST_IMM_SRC1_BYPASS( 11, 1, andi, 0x000000f0, 0x00ff00ff, 0x0f0 );
+  TEST_IMM_SRC1_BYPASS( 12, 2, andi, 0x0000000f, 0xf00ff00f, 0x70f );
+
+  TEST_IMM_ZEROSRC1( 13, andi, 0, 0x0f0 );
+  TEST_IMM_ZERODEST( 14, andi, 0x00ff00ff, 0x70f );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/auipc.S b/verilog/rtl/softshell/third_party/picorv32/tests/auipc.S
new file mode 100644
index 0000000..c67e3c9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/auipc.S
@@ -0,0 +1,39 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# auipc.S
+#-----------------------------------------------------------------------------
+#
+# Test auipc instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  TEST_CASE(2, a0, 10000, \
+    .align 3; \
+    lla a0, 1f + 10000; \
+    jal a1, 1f; \
+    1: sub a0, a0, a1; \
+  )
+
+  TEST_CASE(3, a0, -10000, \
+    .align 3; \
+    lla a0, 1f - 10000; \
+    jal a1, 1f; \
+    1: sub a0, a0, a1; \
+  )
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/beq.S b/verilog/rtl/softshell/third_party/picorv32/tests/beq.S
new file mode 100644
index 0000000..c972eff
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/beq.S
@@ -0,0 +1,73 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# beq.S
+#-----------------------------------------------------------------------------
+#
+# Test beq instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Branch tests
+  #-------------------------------------------------------------
+
+  # Each test checks both forward and backward branches
+
+  TEST_BR2_OP_TAKEN( 2, beq,  0,  0 );
+  TEST_BR2_OP_TAKEN( 3, beq,  1,  1 );
+  TEST_BR2_OP_TAKEN( 4, beq, -1, -1 );
+
+  TEST_BR2_OP_NOTTAKEN( 5, beq,  0,  1 );
+  TEST_BR2_OP_NOTTAKEN( 6, beq,  1,  0 );
+  TEST_BR2_OP_NOTTAKEN( 7, beq, -1,  1 );
+  TEST_BR2_OP_NOTTAKEN( 8, beq,  1, -1 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_BR2_SRC12_BYPASS( 9,  0, 0, beq, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 10, 0, 1, beq, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 11, 0, 2, beq, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 12, 1, 0, beq, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 13, 1, 1, beq, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 14, 2, 0, beq, 0, -1 );
+
+  TEST_BR2_SRC12_BYPASS( 15, 0, 0, beq, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 16, 0, 1, beq, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 17, 0, 2, beq, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 18, 1, 0, beq, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 19, 1, 1, beq, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 20, 2, 0, beq, 0, -1 );
+
+  #-------------------------------------------------------------
+  # Test delay slot instructions not executed nor bypassed
+  #-------------------------------------------------------------
+
+  TEST_CASE( 21, x1, 3, \
+    li  x1, 1; \
+    beq x0, x0, 1f; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+1:  addi x1, x1, 1; \
+    addi x1, x1, 1; \
+  )
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/bge.S b/verilog/rtl/softshell/third_party/picorv32/tests/bge.S
new file mode 100644
index 0000000..d6aea7c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/bge.S
@@ -0,0 +1,76 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# bge.S
+#-----------------------------------------------------------------------------
+#
+# Test bge instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Branch tests
+  #-------------------------------------------------------------
+
+  # Each test checks both forward and backward branches
+
+  TEST_BR2_OP_TAKEN( 2, bge,  0,  0 );
+  TEST_BR2_OP_TAKEN( 3, bge,  1,  1 );
+  TEST_BR2_OP_TAKEN( 4, bge, -1, -1 );
+  TEST_BR2_OP_TAKEN( 5, bge,  1,  0 );
+  TEST_BR2_OP_TAKEN( 6, bge,  1, -1 );
+  TEST_BR2_OP_TAKEN( 7, bge, -1, -2 );
+
+  TEST_BR2_OP_NOTTAKEN(  8, bge,  0,  1 );
+  TEST_BR2_OP_NOTTAKEN(  9, bge, -1,  1 );
+  TEST_BR2_OP_NOTTAKEN( 10, bge, -2, -1 );
+  TEST_BR2_OP_NOTTAKEN( 11, bge, -2,  1 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_BR2_SRC12_BYPASS( 12, 0, 0, bge, -1, 0 );
+  TEST_BR2_SRC12_BYPASS( 13, 0, 1, bge, -1, 0 );
+  TEST_BR2_SRC12_BYPASS( 14, 0, 2, bge, -1, 0 );
+  TEST_BR2_SRC12_BYPASS( 15, 1, 0, bge, -1, 0 );
+  TEST_BR2_SRC12_BYPASS( 16, 1, 1, bge, -1, 0 );
+  TEST_BR2_SRC12_BYPASS( 17, 2, 0, bge, -1, 0 );
+
+  TEST_BR2_SRC12_BYPASS( 18, 0, 0, bge, -1, 0 );
+  TEST_BR2_SRC12_BYPASS( 19, 0, 1, bge, -1, 0 );
+  TEST_BR2_SRC12_BYPASS( 20, 0, 2, bge, -1, 0 );
+  TEST_BR2_SRC12_BYPASS( 21, 1, 0, bge, -1, 0 );
+  TEST_BR2_SRC12_BYPASS( 22, 1, 1, bge, -1, 0 );
+  TEST_BR2_SRC12_BYPASS( 23, 2, 0, bge, -1, 0 );
+
+  #-------------------------------------------------------------
+  # Test delay slot instructions not executed nor bypassed
+  #-------------------------------------------------------------
+
+  TEST_CASE( 24, x1, 3, \
+    li  x1, 1; \
+    bge x1, x0, 1f; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+1:  addi x1, x1, 1; \
+    addi x1, x1, 1; \
+  )
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/bgeu.S b/verilog/rtl/softshell/third_party/picorv32/tests/bgeu.S
new file mode 100644
index 0000000..114c845
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/bgeu.S
@@ -0,0 +1,76 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# bgeu.S
+#-----------------------------------------------------------------------------
+#
+# Test bgeu instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Branch tests
+  #-------------------------------------------------------------
+
+  # Each test checks both forward and backward branches
+
+  TEST_BR2_OP_TAKEN( 2, bgeu, 0x00000000, 0x00000000 );
+  TEST_BR2_OP_TAKEN( 3, bgeu, 0x00000001, 0x00000001 );
+  TEST_BR2_OP_TAKEN( 4, bgeu, 0xffffffff, 0xffffffff );
+  TEST_BR2_OP_TAKEN( 5, bgeu, 0x00000001, 0x00000000 );
+  TEST_BR2_OP_TAKEN( 6, bgeu, 0xffffffff, 0xfffffffe );
+  TEST_BR2_OP_TAKEN( 7, bgeu, 0xffffffff, 0x00000000 );
+
+  TEST_BR2_OP_NOTTAKEN(  8, bgeu, 0x00000000, 0x00000001 );
+  TEST_BR2_OP_NOTTAKEN(  9, bgeu, 0xfffffffe, 0xffffffff );
+  TEST_BR2_OP_NOTTAKEN( 10, bgeu, 0x00000000, 0xffffffff );
+  TEST_BR2_OP_NOTTAKEN( 11, bgeu, 0x7fffffff, 0x80000000 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_BR2_SRC12_BYPASS( 12, 0, 0, bgeu, 0xefffffff, 0xf0000000 );
+  TEST_BR2_SRC12_BYPASS( 13, 0, 1, bgeu, 0xefffffff, 0xf0000000 );
+  TEST_BR2_SRC12_BYPASS( 14, 0, 2, bgeu, 0xefffffff, 0xf0000000 );
+  TEST_BR2_SRC12_BYPASS( 15, 1, 0, bgeu, 0xefffffff, 0xf0000000 );
+  TEST_BR2_SRC12_BYPASS( 16, 1, 1, bgeu, 0xefffffff, 0xf0000000 );
+  TEST_BR2_SRC12_BYPASS( 17, 2, 0, bgeu, 0xefffffff, 0xf0000000 );
+
+  TEST_BR2_SRC12_BYPASS( 18, 0, 0, bgeu, 0xefffffff, 0xf0000000 );
+  TEST_BR2_SRC12_BYPASS( 19, 0, 1, bgeu, 0xefffffff, 0xf0000000 );
+  TEST_BR2_SRC12_BYPASS( 20, 0, 2, bgeu, 0xefffffff, 0xf0000000 );
+  TEST_BR2_SRC12_BYPASS( 21, 1, 0, bgeu, 0xefffffff, 0xf0000000 );
+  TEST_BR2_SRC12_BYPASS( 22, 1, 1, bgeu, 0xefffffff, 0xf0000000 );
+  TEST_BR2_SRC12_BYPASS( 23, 2, 0, bgeu, 0xefffffff, 0xf0000000 );
+
+  #-------------------------------------------------------------
+  # Test delay slot instructions not executed nor bypassed
+  #-------------------------------------------------------------
+
+  TEST_CASE( 24, x1, 3, \
+    li  x1, 1; \
+    bgeu x1, x0, 1f; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+1:  addi x1, x1, 1; \
+    addi x1, x1, 1; \
+  )
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/blt.S b/verilog/rtl/softshell/third_party/picorv32/tests/blt.S
new file mode 100644
index 0000000..12e28c3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/blt.S
@@ -0,0 +1,73 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# blt.S
+#-----------------------------------------------------------------------------
+#
+# Test blt instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Branch tests
+  #-------------------------------------------------------------
+
+  # Each test checks both forward and backward branches
+
+  TEST_BR2_OP_TAKEN( 2, blt,  0,  1 );
+  TEST_BR2_OP_TAKEN( 3, blt, -1,  1 );
+  TEST_BR2_OP_TAKEN( 4, blt, -2, -1 );
+
+  TEST_BR2_OP_NOTTAKEN( 5, blt,  1,  0 );
+  TEST_BR2_OP_NOTTAKEN( 6, blt,  1, -1 );
+  TEST_BR2_OP_NOTTAKEN( 7, blt, -1, -2 );
+  TEST_BR2_OP_NOTTAKEN( 8, blt,  1, -2 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_BR2_SRC12_BYPASS( 9,  0, 0, blt, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 10, 0, 1, blt, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 11, 0, 2, blt, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 12, 1, 0, blt, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 13, 1, 1, blt, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 14, 2, 0, blt, 0, -1 );
+
+  TEST_BR2_SRC12_BYPASS( 15, 0, 0, blt, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 16, 0, 1, blt, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 17, 0, 2, blt, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 18, 1, 0, blt, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 19, 1, 1, blt, 0, -1 );
+  TEST_BR2_SRC12_BYPASS( 20, 2, 0, blt, 0, -1 );
+
+  #-------------------------------------------------------------
+  # Test delay slot instructions not executed nor bypassed
+  #-------------------------------------------------------------
+
+  TEST_CASE( 21, x1, 3, \
+    li  x1, 1; \
+    blt x0, x1, 1f; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+1:  addi x1, x1, 1; \
+    addi x1, x1, 1; \
+  )
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/bltu.S b/verilog/rtl/softshell/third_party/picorv32/tests/bltu.S
new file mode 100644
index 0000000..5dcfe7e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/bltu.S
@@ -0,0 +1,73 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# bltu.S
+#-----------------------------------------------------------------------------
+#
+# Test bltu instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Branch tests
+  #-------------------------------------------------------------
+
+  # Each test checks both forward and backward branches
+
+  TEST_BR2_OP_TAKEN( 2, bltu, 0x00000000, 0x00000001 );
+  TEST_BR2_OP_TAKEN( 3, bltu, 0xfffffffe, 0xffffffff );
+  TEST_BR2_OP_TAKEN( 4, bltu, 0x00000000, 0xffffffff );
+
+  TEST_BR2_OP_NOTTAKEN( 5, bltu, 0x00000001, 0x00000000 );
+  TEST_BR2_OP_NOTTAKEN( 6, bltu, 0xffffffff, 0xfffffffe );
+  TEST_BR2_OP_NOTTAKEN( 7, bltu, 0xffffffff, 0x00000000 );
+  TEST_BR2_OP_NOTTAKEN( 8, bltu, 0x80000000, 0x7fffffff );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_BR2_SRC12_BYPASS( 9,  0, 0, bltu, 0xf0000000, 0xefffffff );
+  TEST_BR2_SRC12_BYPASS( 10, 0, 1, bltu, 0xf0000000, 0xefffffff );
+  TEST_BR2_SRC12_BYPASS( 11, 0, 2, bltu, 0xf0000000, 0xefffffff );
+  TEST_BR2_SRC12_BYPASS( 12, 1, 0, bltu, 0xf0000000, 0xefffffff );
+  TEST_BR2_SRC12_BYPASS( 13, 1, 1, bltu, 0xf0000000, 0xefffffff );
+  TEST_BR2_SRC12_BYPASS( 14, 2, 0, bltu, 0xf0000000, 0xefffffff );
+
+  TEST_BR2_SRC12_BYPASS( 15, 0, 0, bltu, 0xf0000000, 0xefffffff );
+  TEST_BR2_SRC12_BYPASS( 16, 0, 1, bltu, 0xf0000000, 0xefffffff );
+  TEST_BR2_SRC12_BYPASS( 17, 0, 2, bltu, 0xf0000000, 0xefffffff );
+  TEST_BR2_SRC12_BYPASS( 18, 1, 0, bltu, 0xf0000000, 0xefffffff );
+  TEST_BR2_SRC12_BYPASS( 19, 1, 1, bltu, 0xf0000000, 0xefffffff );
+  TEST_BR2_SRC12_BYPASS( 20, 2, 0, bltu, 0xf0000000, 0xefffffff );
+
+  #-------------------------------------------------------------
+  # Test delay slot instructions not executed nor bypassed
+  #-------------------------------------------------------------
+
+  TEST_CASE( 21, x1, 3, \
+    li  x1, 1; \
+    bltu x0, x1, 1f; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+1:  addi x1, x1, 1; \
+    addi x1, x1, 1; \
+  )
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/bne.S b/verilog/rtl/softshell/third_party/picorv32/tests/bne.S
new file mode 100644
index 0000000..0b33753
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/bne.S
@@ -0,0 +1,73 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# bne.S
+#-----------------------------------------------------------------------------
+#
+# Test bne instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Branch tests
+  #-------------------------------------------------------------
+
+  # Each test checks both forward and backward branches
+
+  TEST_BR2_OP_TAKEN( 2, bne,  0,  1 );
+  TEST_BR2_OP_TAKEN( 3, bne,  1,  0 );
+  TEST_BR2_OP_TAKEN( 4, bne, -1,  1 );
+  TEST_BR2_OP_TAKEN( 5, bne,  1, -1 );
+
+  TEST_BR2_OP_NOTTAKEN( 6, bne,  0,  0 );
+  TEST_BR2_OP_NOTTAKEN( 7, bne,  1,  1 );
+  TEST_BR2_OP_NOTTAKEN( 8, bne, -1, -1 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_BR2_SRC12_BYPASS( 9,  0, 0, bne, 0, 0 );
+  TEST_BR2_SRC12_BYPASS( 10, 0, 1, bne, 0, 0 );
+  TEST_BR2_SRC12_BYPASS( 11, 0, 2, bne, 0, 0 );
+  TEST_BR2_SRC12_BYPASS( 12, 1, 0, bne, 0, 0 );
+  TEST_BR2_SRC12_BYPASS( 13, 1, 1, bne, 0, 0 );
+  TEST_BR2_SRC12_BYPASS( 14, 2, 0, bne, 0, 0 );
+
+  TEST_BR2_SRC12_BYPASS( 15, 0, 0, bne, 0, 0 );
+  TEST_BR2_SRC12_BYPASS( 16, 0, 1, bne, 0, 0 );
+  TEST_BR2_SRC12_BYPASS( 17, 0, 2, bne, 0, 0 );
+  TEST_BR2_SRC12_BYPASS( 18, 1, 0, bne, 0, 0 );
+  TEST_BR2_SRC12_BYPASS( 19, 1, 1, bne, 0, 0 );
+  TEST_BR2_SRC12_BYPASS( 20, 2, 0, bne, 0, 0 );
+
+  #-------------------------------------------------------------
+  # Test delay slot instructions not executed nor bypassed
+  #-------------------------------------------------------------
+
+  TEST_CASE( 21, x1, 3, \
+    li  x1, 1; \
+    bne x1, x0, 1f; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+1:  addi x1, x1, 1; \
+    addi x1, x1, 1; \
+  )
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/div.S b/verilog/rtl/softshell/third_party/picorv32/tests/div.S
new file mode 100644
index 0000000..24dc9ff
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/div.S
@@ -0,0 +1,41 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# div.S
+#-----------------------------------------------------------------------------
+#
+# Test div instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2, div,  3,  20,   6 );
+  TEST_RR_OP( 3, div, -3, -20,   6 );
+  TEST_RR_OP( 4, div, -3,  20,  -6 );
+  TEST_RR_OP( 5, div,  3, -20,  -6 );
+
+  TEST_RR_OP( 6, div, -1<<31, -1<<31,  1 );
+  TEST_RR_OP( 7, div, -1<<31, -1<<31, -1 );
+
+  TEST_RR_OP( 8, div, -1, -1<<31, 0 );
+  TEST_RR_OP( 9, div, -1,      1, 0 );
+  TEST_RR_OP(10, div, -1,      0, 0 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/divu.S b/verilog/rtl/softshell/third_party/picorv32/tests/divu.S
new file mode 100644
index 0000000..cd348c9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/divu.S
@@ -0,0 +1,41 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# divu.S
+#-----------------------------------------------------------------------------
+#
+# Test divu instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2, divu,                   3,  20,   6 );
+  TEST_RR_OP( 3, divu,           715827879, -20,   6 );
+  TEST_RR_OP( 4, divu,                   0,  20,  -6 );
+  TEST_RR_OP( 5, divu,                   0, -20,  -6 );
+
+  TEST_RR_OP( 6, divu, -1<<31, -1<<31,  1 );
+  TEST_RR_OP( 7, divu,     0,  -1<<31, -1 );
+
+  TEST_RR_OP( 8, divu, -1, -1<<31, 0 );
+  TEST_RR_OP( 9, divu, -1,      1, 0 );
+  TEST_RR_OP(10, divu, -1,      0, 0 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/j.S b/verilog/rtl/softshell/third_party/picorv32/tests/j.S
new file mode 100644
index 0000000..259a236
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/j.S
@@ -0,0 +1,49 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# j.S
+#-----------------------------------------------------------------------------
+#
+# Test j instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Test basic
+  #-------------------------------------------------------------
+
+  li  TESTNUM, 2;
+  j test_2;
+  j fail;
+test_2:
+
+  #-------------------------------------------------------------
+  # Test delay slot instructions not executed nor bypassed
+  #-------------------------------------------------------------
+
+  TEST_CASE( 3, x1, 3, \
+    li  x1, 1; \
+    j 1f; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+1:  addi x1, x1, 1; \
+    addi x1, x1, 1; \
+  )
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/jal.S b/verilog/rtl/softshell/third_party/picorv32/tests/jal.S
new file mode 100644
index 0000000..38a1c76
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/jal.S
@@ -0,0 +1,62 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# jal.S
+#-----------------------------------------------------------------------------
+#
+# Test jal instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+.option norvc
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Test 2: Basic test
+  #-------------------------------------------------------------
+
+test_2:
+  li  TESTNUM, 2
+  li  ra, 0
+
+linkaddr_2:
+  jal target_2
+  nop
+  nop
+
+  j fail
+
+target_2:
+  la  x2, linkaddr_2
+  addi x2, x2, 4
+  bne x2, ra, fail
+
+  #-------------------------------------------------------------
+  # Test delay slot instructions not executed nor bypassed
+  #-------------------------------------------------------------
+
+  TEST_CASE( 3, x2, 3, \
+    li  x2, 1; \
+    jal 1f; \
+    addi x2, x2, 1; \
+    addi x2, x2, 1; \
+    addi x2, x2, 1; \
+    addi x2, x2, 1; \
+1:  addi x2, x2, 1; \
+    addi x2, x2, 1; \
+  )
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/jalr.S b/verilog/rtl/softshell/third_party/picorv32/tests/jalr.S
new file mode 100644
index 0000000..52117ab
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/jalr.S
@@ -0,0 +1,90 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# jalr.S
+#-----------------------------------------------------------------------------
+#
+# Test jalr instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+.option norvc
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Test 2: Basic test
+  #-------------------------------------------------------------
+
+test_2:
+  li  TESTNUM, 2
+  li  x31, 0
+  la  x2, target_2
+
+linkaddr_2:
+  jalr x19, x2, 0
+  nop
+  nop
+
+  j fail
+
+target_2:
+  la  x1, linkaddr_2
+  addi x1, x1, 4
+  bne x1, x19, fail
+
+  #-------------------------------------------------------------
+  # Test 3: Check r0 target and that r31 is not modified
+  #-------------------------------------------------------------
+
+test_3:
+  li  TESTNUM, 3
+  li  x31, 0
+  la  x3, target_3
+
+linkaddr_3:
+  jalr x0, x3, 0
+  nop
+
+  j fail
+
+target_3:
+  bne x31, x0, fail
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_JALR_SRC1_BYPASS( 4, 0, jalr );
+  TEST_JALR_SRC1_BYPASS( 5, 1, jalr );
+  TEST_JALR_SRC1_BYPASS( 6, 2, jalr );
+
+  #-------------------------------------------------------------
+  # Test delay slot instructions not executed nor bypassed
+  #-------------------------------------------------------------
+
+  TEST_CASE( 7, x1, 4, \
+    li  x1, 1; \
+    la  x2, 1f;
+    jalr x19, x2, -4; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+    addi x1, x1, 1; \
+1:  addi x1, x1, 1; \
+    addi x1, x1, 1; \
+  )
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/lb.S b/verilog/rtl/softshell/third_party/picorv32/tests/lb.S
new file mode 100644
index 0000000..eaf7902
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/lb.S
@@ -0,0 +1,92 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# lb.S
+#-----------------------------------------------------------------------------
+#
+# Test lb instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Basic tests
+  #-------------------------------------------------------------
+
+  TEST_LD_OP( 2, lb, 0xffffffff, 0,  tdat );
+  TEST_LD_OP( 3, lb, 0x00000000, 1,  tdat );
+  TEST_LD_OP( 4, lb, 0xfffffff0, 2,  tdat );
+  TEST_LD_OP( 5, lb, 0x0000000f, 3, tdat );
+
+  # Test with negative offset
+
+  TEST_LD_OP( 6, lb, 0xffffffff, -3, tdat4 );
+  TEST_LD_OP( 7, lb, 0x00000000, -2,  tdat4 );
+  TEST_LD_OP( 8, lb, 0xfffffff0, -1,  tdat4 );
+  TEST_LD_OP( 9, lb, 0x0000000f, 0,   tdat4 );
+
+  # Test with a negative base
+
+  TEST_CASE( 10, x3, 0xffffffff, \
+    la  x1, tdat; \
+    addi x1, x1, -32; \
+    lb x3, 32(x1); \
+  )
+
+  # Test with unaligned base
+
+  TEST_CASE( 11, x3, 0x00000000, \
+    la  x1, tdat; \
+    addi x1, x1, -6; \
+    lb x3, 7(x1); \
+  )
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_LD_DEST_BYPASS( 12, 0, lb, 0xfffffff0, 1, tdat2 );
+  TEST_LD_DEST_BYPASS( 13, 1, lb, 0x0000000f, 1, tdat3 );
+  TEST_LD_DEST_BYPASS( 14, 2, lb, 0x00000000, 1, tdat1 );
+
+  TEST_LD_SRC1_BYPASS( 15, 0, lb, 0xfffffff0, 1, tdat2 );
+  TEST_LD_SRC1_BYPASS( 16, 1, lb, 0x0000000f, 1, tdat3 );
+  TEST_LD_SRC1_BYPASS( 17, 2, lb, 0x00000000, 1, tdat1 );
+
+  #-------------------------------------------------------------
+  # Test write-after-write hazard
+  #-------------------------------------------------------------
+
+  TEST_CASE( 18, x2, 2, \
+    la  x3, tdat; \
+    lb  x2, 0(x3); \
+    li  x2, 2; \
+  )
+
+  TEST_CASE( 19, x2, 2, \
+    la  x3, tdat; \
+    lb  x2, 0(x3); \
+    nop; \
+    li  x2, 2; \
+  )
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+tdat:
+tdat1:  .byte 0xff
+tdat2:  .byte 0x00
+tdat3:  .byte 0xf0
+tdat4:  .byte 0x0f
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/lbu.S b/verilog/rtl/softshell/third_party/picorv32/tests/lbu.S
new file mode 100644
index 0000000..027b643
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/lbu.S
@@ -0,0 +1,92 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# lbu.S
+#-----------------------------------------------------------------------------
+#
+# Test lbu instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Basic tests
+  #-------------------------------------------------------------
+
+  TEST_LD_OP( 2, lbu, 0x000000ff, 0,  tdat );
+  TEST_LD_OP( 3, lbu, 0x00000000, 1,  tdat );
+  TEST_LD_OP( 4, lbu, 0x000000f0, 2,  tdat );
+  TEST_LD_OP( 5, lbu, 0x0000000f, 3, tdat );
+
+  # Test with negative offset
+
+  TEST_LD_OP( 6, lbu, 0x000000ff, -3, tdat4 );
+  TEST_LD_OP( 7, lbu, 0x00000000, -2,  tdat4 );
+  TEST_LD_OP( 8, lbu, 0x000000f0, -1,  tdat4 );
+  TEST_LD_OP( 9, lbu, 0x0000000f, 0,   tdat4 );
+
+  # Test with a negative base
+
+  TEST_CASE( 10, x3, 0x000000ff, \
+    la  x1, tdat; \
+    addi x1, x1, -32; \
+    lbu x3, 32(x1); \
+  )
+
+  # Test with unaligned base
+
+  TEST_CASE( 11, x3, 0x00000000, \
+    la  x1, tdat; \
+    addi x1, x1, -6; \
+    lbu x3, 7(x1); \
+  )
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_LD_DEST_BYPASS( 12, 0, lbu, 0x000000f0, 1, tdat2 );
+  TEST_LD_DEST_BYPASS( 13, 1, lbu, 0x0000000f, 1, tdat3 );
+  TEST_LD_DEST_BYPASS( 14, 2, lbu, 0x00000000, 1, tdat1 );
+
+  TEST_LD_SRC1_BYPASS( 15, 0, lbu, 0x000000f0, 1, tdat2 );
+  TEST_LD_SRC1_BYPASS( 16, 1, lbu, 0x0000000f, 1, tdat3 );
+  TEST_LD_SRC1_BYPASS( 17, 2, lbu, 0x00000000, 1, tdat1 );
+
+  #-------------------------------------------------------------
+  # Test write-after-write hazard
+  #-------------------------------------------------------------
+
+  TEST_CASE( 18, x2, 2, \
+    la  x3, tdat; \
+    lbu  x2, 0(x3); \
+    li  x2, 2; \
+  )
+
+  TEST_CASE( 19, x2, 2, \
+    la  x3, tdat; \
+    lbu  x2, 0(x3); \
+    nop; \
+    li  x2, 2; \
+  )
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+tdat:
+tdat1:  .byte 0xff
+tdat2:  .byte 0x00
+tdat3:  .byte 0xf0
+tdat4:  .byte 0x0f
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/lh.S b/verilog/rtl/softshell/third_party/picorv32/tests/lh.S
new file mode 100644
index 0000000..d8eda91
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/lh.S
@@ -0,0 +1,92 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# lh.S
+#-----------------------------------------------------------------------------
+#
+# Test lh instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Basic tests
+  #-------------------------------------------------------------
+
+  TEST_LD_OP( 2, lh, 0x000000ff, 0,  tdat );
+  TEST_LD_OP( 3, lh, 0xffffff00, 2,  tdat );
+  TEST_LD_OP( 4, lh, 0x00000ff0, 4,  tdat );
+  TEST_LD_OP( 5, lh, 0xfffff00f, 6, tdat );
+
+  # Test with negative offset
+
+  TEST_LD_OP( 6, lh, 0x000000ff, -6,  tdat4 );
+  TEST_LD_OP( 7, lh, 0xffffff00, -4,  tdat4 );
+  TEST_LD_OP( 8, lh, 0x00000ff0, -2,  tdat4 );
+  TEST_LD_OP( 9, lh, 0xfffff00f,  0, tdat4 );
+
+  # Test with a negative base
+
+  TEST_CASE( 10, x3, 0x000000ff, \
+    la  x1, tdat; \
+    addi x1, x1, -32; \
+    lh x3, 32(x1); \
+  )
+
+  # Test with unaligned base
+
+  TEST_CASE( 11, x3, 0xffffff00, \
+    la  x1, tdat; \
+    addi x1, x1, -5; \
+    lh x3, 7(x1); \
+  )
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_LD_DEST_BYPASS( 12, 0, lh, 0x00000ff0, 2, tdat2 );
+  TEST_LD_DEST_BYPASS( 13, 1, lh, 0xfffff00f, 2, tdat3 );
+  TEST_LD_DEST_BYPASS( 14, 2, lh, 0xffffff00, 2, tdat1 );
+
+  TEST_LD_SRC1_BYPASS( 15, 0, lh, 0x00000ff0, 2, tdat2 );
+  TEST_LD_SRC1_BYPASS( 16, 1, lh, 0xfffff00f, 2, tdat3 );
+  TEST_LD_SRC1_BYPASS( 17, 2, lh, 0xffffff00, 2, tdat1 );
+
+  #-------------------------------------------------------------
+  # Test write-after-write hazard
+  #-------------------------------------------------------------
+
+  TEST_CASE( 18, x2, 2, \
+    la  x3, tdat; \
+    lh  x2, 0(x3); \
+    li  x2, 2; \
+  )
+
+  TEST_CASE( 19, x2, 2, \
+    la  x3, tdat; \
+    lh  x2, 0(x3); \
+    nop; \
+    li  x2, 2; \
+  )
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+tdat:
+tdat1:  .half 0x00ff
+tdat2:  .half 0xff00
+tdat3:  .half 0x0ff0
+tdat4:  .half 0xf00f
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/lhu.S b/verilog/rtl/softshell/third_party/picorv32/tests/lhu.S
new file mode 100644
index 0000000..71daec6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/lhu.S
@@ -0,0 +1,92 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# lhu.S
+#-----------------------------------------------------------------------------
+#
+# Test lhu instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Basic tests
+  #-------------------------------------------------------------
+
+  TEST_LD_OP( 2, lhu, 0x000000ff, 0,  tdat );
+  TEST_LD_OP( 3, lhu, 0x0000ff00, 2,  tdat );
+  TEST_LD_OP( 4, lhu, 0x00000ff0, 4,  tdat );
+  TEST_LD_OP( 5, lhu, 0x0000f00f, 6, tdat );
+
+  # Test with negative offset
+
+  TEST_LD_OP( 6, lhu, 0x000000ff, -6,  tdat4 );
+  TEST_LD_OP( 7, lhu, 0x0000ff00, -4,  tdat4 );
+  TEST_LD_OP( 8, lhu, 0x00000ff0, -2,  tdat4 );
+  TEST_LD_OP( 9, lhu, 0x0000f00f,  0, tdat4 );
+
+  # Test with a negative base
+
+  TEST_CASE( 10, x3, 0x000000ff, \
+    la  x1, tdat; \
+    addi x1, x1, -32; \
+    lhu x3, 32(x1); \
+  )
+
+  # Test with unaligned base
+
+  TEST_CASE( 11, x3, 0x0000ff00, \
+    la  x1, tdat; \
+    addi x1, x1, -5; \
+    lhu x3, 7(x1); \
+  )
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_LD_DEST_BYPASS( 12, 0, lhu, 0x00000ff0, 2, tdat2 );
+  TEST_LD_DEST_BYPASS( 13, 1, lhu, 0x0000f00f, 2, tdat3 );
+  TEST_LD_DEST_BYPASS( 14, 2, lhu, 0x0000ff00, 2, tdat1 );
+
+  TEST_LD_SRC1_BYPASS( 15, 0, lhu, 0x00000ff0, 2, tdat2 );
+  TEST_LD_SRC1_BYPASS( 16, 1, lhu, 0x0000f00f, 2, tdat3 );
+  TEST_LD_SRC1_BYPASS( 17, 2, lhu, 0x0000ff00, 2, tdat1 );
+
+  #-------------------------------------------------------------
+  # Test write-after-write hazard
+  #-------------------------------------------------------------
+
+  TEST_CASE( 18, x2, 2, \
+    la  x3, tdat; \
+    lhu  x2, 0(x3); \
+    li  x2, 2; \
+  )
+
+  TEST_CASE( 19, x2, 2, \
+    la  x3, tdat; \
+    lhu  x2, 0(x3); \
+    nop; \
+    li  x2, 2; \
+  )
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+tdat:
+tdat1:  .half 0x00ff
+tdat2:  .half 0xff00
+tdat3:  .half 0x0ff0
+tdat4:  .half 0xf00f
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/lui.S b/verilog/rtl/softshell/third_party/picorv32/tests/lui.S
new file mode 100644
index 0000000..50822d1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/lui.S
@@ -0,0 +1,36 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# lui.S
+#-----------------------------------------------------------------------------
+#
+# Test lui instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Basic tests
+  #-------------------------------------------------------------
+
+  TEST_CASE( 2, x1, 0x00000000, lui x1, 0x00000 );
+  TEST_CASE( 3, x1, 0xfffff800, lui x1, 0xfffff;sra x1,x1,1);
+  TEST_CASE( 4, x1, 0x000007ff, lui x1, 0x7ffff;sra x1,x1,20);
+  TEST_CASE( 5, x1, 0xfffff800, lui x1, 0x80000;sra x1,x1,20);
+
+  TEST_CASE( 6, x0, 0, lui x0, 0x80000 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/lw.S b/verilog/rtl/softshell/third_party/picorv32/tests/lw.S
new file mode 100644
index 0000000..4a07838
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/lw.S
@@ -0,0 +1,92 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# lw.S
+#-----------------------------------------------------------------------------
+#
+# Test lw instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Basic tests
+  #-------------------------------------------------------------
+
+  TEST_LD_OP( 2, lw, 0x00ff00ff, 0,  tdat );
+  TEST_LD_OP( 3, lw, 0xff00ff00, 4,  tdat );
+  TEST_LD_OP( 4, lw, 0x0ff00ff0, 8,  tdat );
+  TEST_LD_OP( 5, lw, 0xf00ff00f, 12, tdat );
+
+  # Test with negative offset
+
+  TEST_LD_OP( 6, lw, 0x00ff00ff, -12, tdat4 );
+  TEST_LD_OP( 7, lw, 0xff00ff00, -8,  tdat4 );
+  TEST_LD_OP( 8, lw, 0x0ff00ff0, -4,  tdat4 );
+  TEST_LD_OP( 9, lw, 0xf00ff00f, 0,   tdat4 );
+
+  # Test with a negative base
+
+  TEST_CASE( 10, x3, 0x00ff00ff, \
+    la  x1, tdat; \
+    addi x1, x1, -32; \
+    lw x3, 32(x1); \
+  )
+
+  # Test with unaligned base
+
+  TEST_CASE( 11, x3, 0xff00ff00, \
+    la  x1, tdat; \
+    addi x1, x1, -3; \
+    lw x3, 7(x1); \
+  )
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_LD_DEST_BYPASS( 12, 0, lw, 0x0ff00ff0, 4, tdat2 );
+  TEST_LD_DEST_BYPASS( 13, 1, lw, 0xf00ff00f, 4, tdat3 );
+  TEST_LD_DEST_BYPASS( 14, 2, lw, 0xff00ff00, 4, tdat1 );
+
+  TEST_LD_SRC1_BYPASS( 15, 0, lw, 0x0ff00ff0, 4, tdat2 );
+  TEST_LD_SRC1_BYPASS( 16, 1, lw, 0xf00ff00f, 4, tdat3 );
+  TEST_LD_SRC1_BYPASS( 17, 2, lw, 0xff00ff00, 4, tdat1 );
+
+  #-------------------------------------------------------------
+  # Test write-after-write hazard
+  #-------------------------------------------------------------
+
+  TEST_CASE( 18, x2, 2, \
+    la  x3, tdat; \
+    lw  x2, 0(x3); \
+    li  x2, 2; \
+  )
+
+  TEST_CASE( 19, x2, 2, \
+    la  x3, tdat; \
+    lw  x2, 0(x3); \
+    nop; \
+    li  x2, 2; \
+  )
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+tdat:
+tdat1:  .word 0x00ff00ff
+tdat2:  .word 0xff00ff00
+tdat3:  .word 0x0ff00ff0
+tdat4:  .word 0xf00ff00f
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/mul.S b/verilog/rtl/softshell/third_party/picorv32/tests/mul.S
new file mode 100644
index 0000000..0368629
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/mul.S
@@ -0,0 +1,84 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# mul.S
+#-----------------------------------------------------------------------------
+#
+# Test mul instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP(32,  mul, 0x00001200, 0x00007e00, 0xb6db6db7 );
+  TEST_RR_OP(33,  mul, 0x00001240, 0x00007fc0, 0xb6db6db7 );
+
+  TEST_RR_OP( 2,  mul, 0x00000000, 0x00000000, 0x00000000 );
+  TEST_RR_OP( 3,  mul, 0x00000001, 0x00000001, 0x00000001 );
+  TEST_RR_OP( 4,  mul, 0x00000015, 0x00000003, 0x00000007 );
+
+  TEST_RR_OP( 5,  mul, 0x00000000, 0x00000000, 0xffff8000 );
+  TEST_RR_OP( 6,  mul, 0x00000000, 0x80000000, 0x00000000 );
+  TEST_RR_OP( 7,  mul, 0x00000000, 0x80000000, 0xffff8000 );
+
+  TEST_RR_OP(30,  mul, 0x0000ff7f, 0xaaaaaaab, 0x0002fe7d );
+  TEST_RR_OP(31,  mul, 0x0000ff7f, 0x0002fe7d, 0xaaaaaaab );
+
+  TEST_RR_OP(34,  mul, 0x00000000, 0xff000000, 0xff000000 );
+
+  TEST_RR_OP(35,  mul, 0x00000001, 0xffffffff, 0xffffffff );
+  TEST_RR_OP(36,  mul, 0xffffffff, 0xffffffff, 0x00000001 );
+  TEST_RR_OP(37,  mul, 0xffffffff, 0x00000001, 0xffffffff );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_RR_SRC1_EQ_DEST( 8, mul, 143, 13, 11 );
+  TEST_RR_SRC2_EQ_DEST( 9, mul, 154, 14, 11 );
+  TEST_RR_SRC12_EQ_DEST( 10, mul, 169, 13 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_RR_DEST_BYPASS( 11, 0, mul, 143, 13, 11 );
+  TEST_RR_DEST_BYPASS( 12, 1, mul, 154, 14, 11 );
+  TEST_RR_DEST_BYPASS( 13, 2, mul, 165, 15, 11 );
+
+  TEST_RR_SRC12_BYPASS( 14, 0, 0, mul, 143, 13, 11 );
+  TEST_RR_SRC12_BYPASS( 15, 0, 1, mul, 154, 14, 11 );
+  TEST_RR_SRC12_BYPASS( 16, 0, 2, mul, 165, 15, 11 );
+  TEST_RR_SRC12_BYPASS( 17, 1, 0, mul, 143, 13, 11 );
+  TEST_RR_SRC12_BYPASS( 18, 1, 1, mul, 154, 14, 11 );
+  TEST_RR_SRC12_BYPASS( 19, 2, 0, mul, 165, 15, 11 );
+
+  TEST_RR_SRC21_BYPASS( 20, 0, 0, mul, 143, 13, 11 );
+  TEST_RR_SRC21_BYPASS( 21, 0, 1, mul, 154, 14, 11 );
+  TEST_RR_SRC21_BYPASS( 22, 0, 2, mul, 165, 15, 11 );
+  TEST_RR_SRC21_BYPASS( 23, 1, 0, mul, 143, 13, 11 );
+  TEST_RR_SRC21_BYPASS( 24, 1, 1, mul, 154, 14, 11 );
+  TEST_RR_SRC21_BYPASS( 25, 2, 0, mul, 165, 15, 11 );
+
+  TEST_RR_ZEROSRC1( 26, mul, 0, 31 );
+  TEST_RR_ZEROSRC2( 27, mul, 0, 32 );
+  TEST_RR_ZEROSRC12( 28, mul, 0 );
+  TEST_RR_ZERODEST( 29, mul, 33, 34 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/mulh.S b/verilog/rtl/softshell/third_party/picorv32/tests/mulh.S
new file mode 100644
index 0000000..e583f5f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/mulh.S
@@ -0,0 +1,81 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# mulh.S
+#-----------------------------------------------------------------------------
+#
+# Test mulh instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2,  mulh, 0x00000000, 0x00000000, 0x00000000 );
+  TEST_RR_OP( 3,  mulh, 0x00000000, 0x00000001, 0x00000001 );
+  TEST_RR_OP( 4,  mulh, 0x00000000, 0x00000003, 0x00000007 );
+
+  TEST_RR_OP( 5,  mulh, 0x00000000, 0x00000000, 0xffff8000 );
+  TEST_RR_OP( 6,  mulh, 0x00000000, 0x80000000, 0x00000000 );
+  TEST_RR_OP( 7,  mulh, 0x00000000, 0x80000000, 0x00000000 );
+
+  TEST_RR_OP(30,  mulh, 0xffff0081, 0xaaaaaaab, 0x0002fe7d );
+  TEST_RR_OP(31,  mulh, 0xffff0081, 0x0002fe7d, 0xaaaaaaab );
+
+  TEST_RR_OP(32,  mulh, 0x00010000, 0xff000000, 0xff000000 );
+
+  TEST_RR_OP(33,  mulh, 0x00000000, 0xffffffff, 0xffffffff );
+  TEST_RR_OP(34,  mulh, 0xffffffff, 0xffffffff, 0x00000001 );
+  TEST_RR_OP(35,  mulh, 0xffffffff, 0x00000001, 0xffffffff );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_RR_SRC1_EQ_DEST( 8, mulh, 36608, 13<<20, 11<<20 );
+  TEST_RR_SRC2_EQ_DEST( 9, mulh, 39424, 14<<20, 11<<20 );
+  TEST_RR_SRC12_EQ_DEST( 10, mulh, 43264, 13<<20 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_RR_DEST_BYPASS( 11, 0, mulh, 36608, 13<<20, 11<<20 );
+  TEST_RR_DEST_BYPASS( 12, 1, mulh, 39424, 14<<20, 11<<20 );
+  TEST_RR_DEST_BYPASS( 13, 2, mulh, 42240, 15<<20, 11<<20 );
+
+  TEST_RR_SRC12_BYPASS( 14, 0, 0, mulh, 36608, 13<<20, 11<<20 );
+  TEST_RR_SRC12_BYPASS( 15, 0, 1, mulh, 39424, 14<<20, 11<<20 );
+  TEST_RR_SRC12_BYPASS( 16, 0, 2, mulh, 42240, 15<<20, 11<<20 );
+  TEST_RR_SRC12_BYPASS( 17, 1, 0, mulh, 36608, 13<<20, 11<<20 );
+  TEST_RR_SRC12_BYPASS( 18, 1, 1, mulh, 39424, 14<<20, 11<<20 );
+  TEST_RR_SRC12_BYPASS( 19, 2, 0, mulh, 42240, 15<<20, 11<<20 );
+
+  TEST_RR_SRC21_BYPASS( 20, 0, 0, mulh, 36608, 13<<20, 11<<20 );
+  TEST_RR_SRC21_BYPASS( 21, 0, 1, mulh, 39424, 14<<20, 11<<20 );
+  TEST_RR_SRC21_BYPASS( 22, 0, 2, mulh, 42240, 15<<20, 11<<20 );
+  TEST_RR_SRC21_BYPASS( 23, 1, 0, mulh, 36608, 13<<20, 11<<20 );
+  TEST_RR_SRC21_BYPASS( 24, 1, 1, mulh, 39424, 14<<20, 11<<20 );
+  TEST_RR_SRC21_BYPASS( 25, 2, 0, mulh, 42240, 15<<20, 11<<20 );
+
+  TEST_RR_ZEROSRC1( 26, mulh, 0, 31<<26 );
+  TEST_RR_ZEROSRC2( 27, mulh, 0, 32<<26 );
+  TEST_RR_ZEROSRC12( 28, mulh, 0 );
+  TEST_RR_ZERODEST( 29, mulh, 33<<20, 34<<20 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/mulhsu.S b/verilog/rtl/softshell/third_party/picorv32/tests/mulhsu.S
new file mode 100644
index 0000000..28b3690
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/mulhsu.S
@@ -0,0 +1,83 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# mulhsu.S
+#-----------------------------------------------------------------------------
+#
+# Test mulhsu instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2,  mulhsu, 0x00000000, 0x00000000, 0x00000000 );
+  TEST_RR_OP( 3,  mulhsu, 0x00000000, 0x00000001, 0x00000001 );
+  TEST_RR_OP( 4,  mulhsu, 0x00000000, 0x00000003, 0x00000007 );
+
+  TEST_RR_OP( 5,  mulhsu, 0x00000000, 0x00000000, 0xffff8000 );
+  TEST_RR_OP( 6,  mulhsu, 0x00000000, 0x80000000, 0x00000000 );
+  TEST_RR_OP( 7,  mulhsu, 0x80004000, 0x80000000, 0xffff8000 );
+
+  TEST_RR_OP(30,  mulhsu, 0xffff0081, 0xaaaaaaab, 0x0002fe7d );
+  TEST_RR_OP(31,  mulhsu, 0x0001fefe, 0x0002fe7d, 0xaaaaaaab );
+
+  TEST_RR_OP(32,  mulhsu, 0xff010000, 0xff000000, 0xff000000 );
+
+  TEST_RR_OP(33,  mulhsu, 0xffffffff, 0xffffffff, 0xffffffff );
+  TEST_RR_OP(34,  mulhsu, 0xffffffff, 0xffffffff, 0x00000001 );
+  TEST_RR_OP(35,  mulhsu, 0x00000000, 0x00000001, 0xffffffff );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_RR_SRC1_EQ_DEST( 8, mulhsu, 36608, 13<<20, 11<<20 );
+  TEST_RR_SRC2_EQ_DEST( 9, mulhsu, 39424, 14<<20, 11<<20 );
+  TEST_RR_SRC12_EQ_DEST( 10, mulhsu, 43264, 13<<20 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_RR_DEST_BYPASS( 11, 0, mulhsu, 36608, 13<<20, 11<<20 );
+  TEST_RR_DEST_BYPASS( 12, 1, mulhsu, 39424, 14<<20, 11<<20 );
+  TEST_RR_DEST_BYPASS( 13, 2, mulhsu, 42240, 15<<20, 11<<20 );
+
+  TEST_RR_SRC12_BYPASS( 14, 0, 0, mulhsu, 36608, 13<<20, 11<<20 );
+  TEST_RR_SRC12_BYPASS( 15, 0, 1, mulhsu, 39424, 14<<20, 11<<20 );
+  TEST_RR_SRC12_BYPASS( 16, 0, 2, mulhsu, 42240, 15<<20, 11<<20 );
+  TEST_RR_SRC12_BYPASS( 17, 1, 0, mulhsu, 36608, 13<<20, 11<<20 );
+  TEST_RR_SRC12_BYPASS( 18, 1, 1, mulhsu, 39424, 14<<20, 11<<20 );
+  TEST_RR_SRC12_BYPASS( 19, 2, 0, mulhsu, 42240, 15<<20, 11<<20 );
+
+  TEST_RR_SRC21_BYPASS( 20, 0, 0, mulhsu, 36608, 13<<20, 11<<20 );
+  TEST_RR_SRC21_BYPASS( 21, 0, 1, mulhsu, 39424, 14<<20, 11<<20 );
+  TEST_RR_SRC21_BYPASS( 22, 0, 2, mulhsu, 42240, 15<<20, 11<<20 );
+  TEST_RR_SRC21_BYPASS( 23, 1, 0, mulhsu, 36608, 13<<20, 11<<20 );
+  TEST_RR_SRC21_BYPASS( 24, 1, 1, mulhsu, 39424, 14<<20, 11<<20 );
+  TEST_RR_SRC21_BYPASS( 25, 2, 0, mulhsu, 42240, 15<<20, 11<<20 );
+
+  TEST_RR_ZEROSRC1( 26, mulhsu, 0, 31<<26 );
+  TEST_RR_ZEROSRC2( 27, mulhsu, 0, 32<<26 );
+  TEST_RR_ZEROSRC12( 28, mulhsu, 0 );
+  TEST_RR_ZERODEST( 29, mulhsu, 33<<20, 34<<20 );
+
+
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/mulhu.S b/verilog/rtl/softshell/third_party/picorv32/tests/mulhu.S
new file mode 100644
index 0000000..601dcff
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/mulhu.S
@@ -0,0 +1,82 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# mulhu.S
+#-----------------------------------------------------------------------------
+#
+# Test mulhu instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2,  mulhu, 0x00000000, 0x00000000, 0x00000000 );
+  TEST_RR_OP( 3,  mulhu, 0x00000000, 0x00000001, 0x00000001 );
+  TEST_RR_OP( 4,  mulhu, 0x00000000, 0x00000003, 0x00000007 );
+
+  TEST_RR_OP( 5,  mulhu, 0x00000000, 0x00000000, 0xffff8000 );
+  TEST_RR_OP( 6,  mulhu, 0x00000000, 0x80000000, 0x00000000 );
+  TEST_RR_OP( 7,  mulhu, 0x7fffc000, 0x80000000, 0xffff8000 );
+
+  TEST_RR_OP(30,  mulhu, 0x0001fefe, 0xaaaaaaab, 0x0002fe7d );
+  TEST_RR_OP(31,  mulhu, 0x0001fefe, 0x0002fe7d, 0xaaaaaaab );
+
+  TEST_RR_OP(32,  mulhu, 0xfe010000, 0xff000000, 0xff000000 );
+
+  TEST_RR_OP(33,  mulhu, 0xfffffffe, 0xffffffff, 0xffffffff );
+  TEST_RR_OP(34,  mulhu, 0x00000000, 0xffffffff, 0x00000001 );
+  TEST_RR_OP(35,  mulhu, 0x00000000, 0x00000001, 0xffffffff );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_RR_SRC1_EQ_DEST( 8, mulhu, 36608, 13<<20, 11<<20 );
+  TEST_RR_SRC2_EQ_DEST( 9, mulhu, 39424, 14<<20, 11<<20 );
+  TEST_RR_SRC12_EQ_DEST( 10, mulhu, 43264, 13<<20 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_RR_DEST_BYPASS( 11, 0, mulhu, 36608, 13<<20, 11<<20 );
+  TEST_RR_DEST_BYPASS( 12, 1, mulhu, 39424, 14<<20, 11<<20 );
+  TEST_RR_DEST_BYPASS( 13, 2, mulhu, 42240, 15<<20, 11<<20 );
+
+  TEST_RR_SRC12_BYPASS( 14, 0, 0, mulhu, 36608, 13<<20, 11<<20 );
+  TEST_RR_SRC12_BYPASS( 15, 0, 1, mulhu, 39424, 14<<20, 11<<20 );
+  TEST_RR_SRC12_BYPASS( 16, 0, 2, mulhu, 42240, 15<<20, 11<<20 );
+  TEST_RR_SRC12_BYPASS( 17, 1, 0, mulhu, 36608, 13<<20, 11<<20 );
+  TEST_RR_SRC12_BYPASS( 18, 1, 1, mulhu, 39424, 14<<20, 11<<20 );
+  TEST_RR_SRC12_BYPASS( 19, 2, 0, mulhu, 42240, 15<<20, 11<<20 );
+
+  TEST_RR_SRC21_BYPASS( 20, 0, 0, mulhu, 36608, 13<<20, 11<<20 );
+  TEST_RR_SRC21_BYPASS( 21, 0, 1, mulhu, 39424, 14<<20, 11<<20 );
+  TEST_RR_SRC21_BYPASS( 22, 0, 2, mulhu, 42240, 15<<20, 11<<20 );
+  TEST_RR_SRC21_BYPASS( 23, 1, 0, mulhu, 36608, 13<<20, 11<<20 );
+  TEST_RR_SRC21_BYPASS( 24, 1, 1, mulhu, 39424, 14<<20, 11<<20 );
+  TEST_RR_SRC21_BYPASS( 25, 2, 0, mulhu, 42240, 15<<20, 11<<20 );
+
+  TEST_RR_ZEROSRC1( 26, mulhu, 0, 31<<26 );
+  TEST_RR_ZEROSRC2( 27, mulhu, 0, 32<<26 );
+  TEST_RR_ZEROSRC12( 28, mulhu, 0 );
+  TEST_RR_ZERODEST( 29, mulhu, 33<<20, 34<<20 );
+
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/or.S b/verilog/rtl/softshell/third_party/picorv32/tests/or.S
new file mode 100644
index 0000000..110bcc4
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/or.S
@@ -0,0 +1,69 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# or.S
+#-----------------------------------------------------------------------------
+#
+# Test or instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Logical tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_OP( 3, or, 0xfff0fff0, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_OP( 4, or, 0x0fff0fff, 0x00ff00ff, 0x0f0f0f0f );
+  TEST_RR_OP( 5, or, 0xf0fff0ff, 0xf00ff00f, 0xf0f0f0f0 );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_RR_SRC1_EQ_DEST( 6, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC2_EQ_DEST( 7, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC12_EQ_DEST( 8, or, 0xff00ff00, 0xff00ff00 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_RR_DEST_BYPASS( 9,  0, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_DEST_BYPASS( 10, 1, or, 0xfff0fff0, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_DEST_BYPASS( 11, 2, or, 0x0fff0fff, 0x00ff00ff, 0x0f0f0f0f );
+
+  TEST_RR_SRC12_BYPASS( 12, 0, 0, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC12_BYPASS( 13, 0, 1, or, 0xfff0fff0, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_SRC12_BYPASS( 14, 0, 2, or, 0x0fff0fff, 0x00ff00ff, 0x0f0f0f0f );
+  TEST_RR_SRC12_BYPASS( 15, 1, 0, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC12_BYPASS( 16, 1, 1, or, 0xfff0fff0, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_SRC12_BYPASS( 17, 2, 0, or, 0x0fff0fff, 0x00ff00ff, 0x0f0f0f0f );
+
+  TEST_RR_SRC21_BYPASS( 18, 0, 0, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC21_BYPASS( 19, 0, 1, or, 0xfff0fff0, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_SRC21_BYPASS( 20, 0, 2, or, 0x0fff0fff, 0x00ff00ff, 0x0f0f0f0f );
+  TEST_RR_SRC21_BYPASS( 21, 1, 0, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC21_BYPASS( 22, 1, 1, or, 0xfff0fff0, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_SRC21_BYPASS( 23, 2, 0, or, 0x0fff0fff, 0x00ff00ff, 0x0f0f0f0f );
+
+  TEST_RR_ZEROSRC1( 24, or, 0xff00ff00, 0xff00ff00 );
+  TEST_RR_ZEROSRC2( 25, or, 0x00ff00ff, 0x00ff00ff );
+  TEST_RR_ZEROSRC12( 26, or, 0 );
+  TEST_RR_ZERODEST( 27, or, 0x11111111, 0x22222222 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/ori.S b/verilog/rtl/softshell/third_party/picorv32/tests/ori.S
new file mode 100644
index 0000000..a674784
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/ori.S
@@ -0,0 +1,55 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# ori.S
+#-----------------------------------------------------------------------------
+#
+# Test ori instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Logical tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_OP( 2, ori, 0xffffff0f, 0xff00ff00, 0xf0f );
+  TEST_IMM_OP( 3, ori, 0x0ff00ff0, 0x0ff00ff0, 0x0f0 );
+  TEST_IMM_OP( 4, ori, 0x00ff07ff, 0x00ff00ff, 0x70f );
+  TEST_IMM_OP( 5, ori, 0xf00ff0ff, 0xf00ff00f, 0x0f0 );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_SRC1_EQ_DEST( 6, ori, 0xff00fff0, 0xff00ff00, 0x0f0 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_DEST_BYPASS( 7,  0, ori, 0x0ff00ff0, 0x0ff00ff0, 0x0f0 );
+  TEST_IMM_DEST_BYPASS( 8,  1, ori, 0x00ff07ff, 0x00ff00ff, 0x70f );
+  TEST_IMM_DEST_BYPASS( 9,  2, ori, 0xf00ff0ff, 0xf00ff00f, 0x0f0 );
+
+  TEST_IMM_SRC1_BYPASS( 10, 0, ori, 0x0ff00ff0, 0x0ff00ff0, 0x0f0 );
+  TEST_IMM_SRC1_BYPASS( 11, 1, ori, 0xffffffff, 0x00ff00ff, 0xf0f );
+  TEST_IMM_SRC1_BYPASS( 12, 2, ori, 0xf00ff0ff, 0xf00ff00f, 0x0f0 );
+
+  TEST_IMM_ZEROSRC1( 13, ori, 0x0f0, 0x0f0 );
+  TEST_IMM_ZERODEST( 14, ori, 0x00ff00ff, 0x70f );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/rem.S b/verilog/rtl/softshell/third_party/picorv32/tests/rem.S
new file mode 100644
index 0000000..7955736
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/rem.S
@@ -0,0 +1,41 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# rem.S
+#-----------------------------------------------------------------------------
+#
+# Test rem instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2, rem,  2,  20,   6 );
+  TEST_RR_OP( 3, rem, -2, -20,   6 );
+  TEST_RR_OP( 4, rem,  2,  20,  -6 );
+  TEST_RR_OP( 5, rem, -2, -20,  -6 );
+
+  TEST_RR_OP( 6, rem,  0, -1<<31,  1 );
+  TEST_RR_OP( 7, rem,  0, -1<<31, -1 );
+
+  TEST_RR_OP( 8, rem, -1<<31, -1<<31, 0 );
+  TEST_RR_OP( 9, rem,      1,      1, 0 );
+  TEST_RR_OP(10, rem,      0,      0, 0 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/remu.S b/verilog/rtl/softshell/third_party/picorv32/tests/remu.S
new file mode 100644
index 0000000..a96cfc1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/remu.S
@@ -0,0 +1,41 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# remu.S
+#-----------------------------------------------------------------------------
+#
+# Test remu instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2, remu,   2,  20,   6 );
+  TEST_RR_OP( 3, remu,   2, -20,   6 );
+  TEST_RR_OP( 4, remu,  20,  20,  -6 );
+  TEST_RR_OP( 5, remu, -20, -20,  -6 );
+
+  TEST_RR_OP( 6, remu,      0, -1<<31,  1 );
+  TEST_RR_OP( 7, remu, -1<<31, -1<<31, -1 );
+
+  TEST_RR_OP( 8, remu, -1<<31, -1<<31, 0 );
+  TEST_RR_OP( 9, remu,      1,      1, 0 );
+  TEST_RR_OP(10, remu,      0,      0, 0 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/riscv_test.h b/verilog/rtl/softshell/third_party/picorv32/tests/riscv_test.h
new file mode 100644
index 0000000..71a4366
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/riscv_test.h
@@ -0,0 +1,64 @@
+#ifndef _ENV_PICORV32_TEST_H
+#define _ENV_PICORV32_TEST_H
+
+#ifndef TEST_FUNC_NAME
+#  define TEST_FUNC_NAME mytest
+#  define TEST_FUNC_TXT "mytest"
+#  define TEST_FUNC_RET mytest_ret
+#endif
+
+#define RVTEST_RV32U
+#define TESTNUM x28
+
+#define RVTEST_CODE_BEGIN		\
+	.text;				\
+	.global TEST_FUNC_NAME;		\
+	.global TEST_FUNC_RET;		\
+TEST_FUNC_NAME:				\
+	lui	a0,%hi(.test_name);	\
+	addi	a0,a0,%lo(.test_name);	\
+	lui	a2,0x10000000>>12;	\
+.prname_next:				\
+	lb	a1,0(a0);		\
+	beq	a1,zero,.prname_done;	\
+	sw	a1,0(a2);		\
+	addi	a0,a0,1;		\
+	jal	zero,.prname_next;	\
+.test_name:				\
+	.ascii TEST_FUNC_TXT;		\
+	.byte 0x00;			\
+	.balign 4, 0;			\
+.prname_done:				\
+	addi	a1,zero,'.';		\
+	sw	a1,0(a2);		\
+	sw	a1,0(a2);
+
+#define RVTEST_PASS			\
+	lui	a0,0x10000000>>12;	\
+	addi	a1,zero,'O';		\
+	addi	a2,zero,'K';		\
+	addi	a3,zero,'\n';		\
+	sw	a1,0(a0);		\
+	sw	a2,0(a0);		\
+	sw	a3,0(a0);		\
+	jal	zero,TEST_FUNC_RET;
+
+#define RVTEST_FAIL			\
+	lui	a0,0x10000000>>12;	\
+	addi	a1,zero,'E';		\
+	addi	a2,zero,'R';		\
+	addi	a3,zero,'O';		\
+	addi	a4,zero,'\n';		\
+	sw	a1,0(a0);		\
+	sw	a2,0(a0);		\
+	sw	a2,0(a0);		\
+	sw	a3,0(a0);		\
+	sw	a2,0(a0);		\
+	sw	a4,0(a0);		\
+	ebreak;
+
+#define RVTEST_CODE_END
+#define RVTEST_DATA_BEGIN .balign 4;
+#define RVTEST_DATA_END
+
+#endif
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/sb.S b/verilog/rtl/softshell/third_party/picorv32/tests/sb.S
new file mode 100644
index 0000000..05d1894
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/sb.S
@@ -0,0 +1,96 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# sb.S
+#-----------------------------------------------------------------------------
+#
+# Test sb instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Basic tests
+  #-------------------------------------------------------------
+
+  TEST_ST_OP( 2, lb, sb, 0xffffffaa, 0, tdat );
+  TEST_ST_OP( 3, lb, sb, 0x00000000, 1, tdat );
+  TEST_ST_OP( 4, lh, sb, 0xffffefa0, 2, tdat );
+  TEST_ST_OP( 5, lb, sb, 0x0000000a, 3, tdat );
+
+  # Test with negative offset
+
+  TEST_ST_OP( 6, lb, sb, 0xffffffaa, -3, tdat8 );
+  TEST_ST_OP( 7, lb, sb, 0x00000000, -2, tdat8 );
+  TEST_ST_OP( 8, lb, sb, 0xffffffa0, -1, tdat8 );
+  TEST_ST_OP( 9, lb, sb, 0x0000000a, 0,  tdat8 );
+
+  # Test with a negative base
+
+  TEST_CASE( 10, x3, 0x78, \
+    la  x1, tdat9; \
+    li  x2, 0x12345678; \
+    addi x4, x1, -32; \
+    sb x2, 32(x4); \
+    lb x3, 0(x1); \
+  )
+
+  # Test with unaligned base
+
+  TEST_CASE( 11, x3, 0xffffff98, \
+    la  x1, tdat9; \
+    li  x2, 0x00003098; \
+    addi x1, x1, -6; \
+    sb x2, 7(x1); \
+    la  x4, tdat10; \
+    lb x3, 0(x4); \
+  )
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_ST_SRC12_BYPASS( 12, 0, 0, lb, sb, 0xffffffdd, 0, tdat );
+  TEST_ST_SRC12_BYPASS( 13, 0, 1, lb, sb, 0xffffffcd, 1, tdat );
+  TEST_ST_SRC12_BYPASS( 14, 0, 2, lb, sb, 0xffffffcc, 2, tdat );
+  TEST_ST_SRC12_BYPASS( 15, 1, 0, lb, sb, 0xffffffbc, 3, tdat );
+  TEST_ST_SRC12_BYPASS( 16, 1, 1, lb, sb, 0xffffffbb, 4, tdat );
+  TEST_ST_SRC12_BYPASS( 17, 2, 0, lb, sb, 0xffffffab, 5, tdat );
+
+  TEST_ST_SRC21_BYPASS( 18, 0, 0, lb, sb, 0x33, 0, tdat );
+  TEST_ST_SRC21_BYPASS( 19, 0, 1, lb, sb, 0x23, 1, tdat );
+  TEST_ST_SRC21_BYPASS( 20, 0, 2, lb, sb, 0x22, 2, tdat );
+  TEST_ST_SRC21_BYPASS( 21, 1, 0, lb, sb, 0x12, 3, tdat );
+  TEST_ST_SRC21_BYPASS( 22, 1, 1, lb, sb, 0x11, 4, tdat );
+  TEST_ST_SRC21_BYPASS( 23, 2, 0, lb, sb, 0x01, 5, tdat );
+
+  li a0, 0xef
+  la a1, tdat
+  sb a0, 3(a1)
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+tdat:
+tdat1:  .byte 0xef
+tdat2:  .byte 0xef
+tdat3:  .byte 0xef
+tdat4:  .byte 0xef
+tdat5:  .byte 0xef
+tdat6:  .byte 0xef
+tdat7:  .byte 0xef
+tdat8:  .byte 0xef
+tdat9:  .byte 0xef
+tdat10: .byte 0xef
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/sh.S b/verilog/rtl/softshell/third_party/picorv32/tests/sh.S
new file mode 100644
index 0000000..387e181
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/sh.S
@@ -0,0 +1,96 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# sh.S
+#-----------------------------------------------------------------------------
+#
+# Test sh instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Basic tests
+  #-------------------------------------------------------------
+
+  TEST_ST_OP( 2, lh, sh, 0x000000aa, 0, tdat );
+  TEST_ST_OP( 3, lh, sh, 0xffffaa00, 2, tdat );
+  TEST_ST_OP( 4, lw, sh, 0xbeef0aa0, 4, tdat );
+  TEST_ST_OP( 5, lh, sh, 0xffffa00a, 6, tdat );
+
+  # Test with negative offset
+
+  TEST_ST_OP( 6, lh, sh, 0x000000aa, -6, tdat8 );
+  TEST_ST_OP( 7, lh, sh, 0xffffaa00, -4, tdat8 );
+  TEST_ST_OP( 8, lh, sh, 0x00000aa0, -2, tdat8 );
+  TEST_ST_OP( 9, lh, sh, 0xffffa00a, 0,  tdat8 );
+
+  # Test with a negative base
+
+  TEST_CASE( 10, x3, 0x5678, \
+    la  x1, tdat9; \
+    li  x2, 0x12345678; \
+    addi x4, x1, -32; \
+    sh x2, 32(x4); \
+    lh x3, 0(x1); \
+  )
+
+  # Test with unaligned base
+
+  TEST_CASE( 11, x3, 0x3098, \
+    la  x1, tdat9; \
+    li  x2, 0x00003098; \
+    addi x1, x1, -5; \
+    sh x2, 7(x1); \
+    la  x4, tdat10; \
+    lh x3, 0(x4); \
+  )
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_ST_SRC12_BYPASS( 12, 0, 0, lh, sh, 0xffffccdd, 0,  tdat );
+  TEST_ST_SRC12_BYPASS( 13, 0, 1, lh, sh, 0xffffbccd, 2,  tdat );
+  TEST_ST_SRC12_BYPASS( 14, 0, 2, lh, sh, 0xffffbbcc, 4,  tdat );
+  TEST_ST_SRC12_BYPASS( 15, 1, 0, lh, sh, 0xffffabbc, 6, tdat );
+  TEST_ST_SRC12_BYPASS( 16, 1, 1, lh, sh, 0xffffaabb, 8, tdat );
+  TEST_ST_SRC12_BYPASS( 17, 2, 0, lh, sh, 0xffffdaab, 10, tdat );
+
+  TEST_ST_SRC21_BYPASS( 18, 0, 0, lh, sh, 0x2233, 0,  tdat );
+  TEST_ST_SRC21_BYPASS( 19, 0, 1, lh, sh, 0x1223, 2,  tdat );
+  TEST_ST_SRC21_BYPASS( 20, 0, 2, lh, sh, 0x1122, 4,  tdat );
+  TEST_ST_SRC21_BYPASS( 21, 1, 0, lh, sh, 0x0112, 6, tdat );
+  TEST_ST_SRC21_BYPASS( 22, 1, 1, lh, sh, 0x0011, 8, tdat );
+  TEST_ST_SRC21_BYPASS( 23, 2, 0, lh, sh, 0x3001, 10, tdat );
+
+  li a0, 0xbeef
+  la a1, tdat
+  sh a0, 6(a1)
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+tdat:
+tdat1:  .half 0xbeef
+tdat2:  .half 0xbeef
+tdat3:  .half 0xbeef
+tdat4:  .half 0xbeef
+tdat5:  .half 0xbeef
+tdat6:  .half 0xbeef
+tdat7:  .half 0xbeef
+tdat8:  .half 0xbeef
+tdat9:  .half 0xbeef
+tdat10: .half 0xbeef
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/simple.S b/verilog/rtl/softshell/third_party/picorv32/tests/simple.S
new file mode 100644
index 0000000..92cf203
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/simple.S
@@ -0,0 +1,27 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# simple.S
+#-----------------------------------------------------------------------------
+#
+# This is the most basic self checking test. If your simulator does not
+# pass thiss then there is little chance that it will pass any of the
+# more complicated self checking tests.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+RVTEST_PASS
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/sll.S b/verilog/rtl/softshell/third_party/picorv32/tests/sll.S
new file mode 100644
index 0000000..d297ac5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/sll.S
@@ -0,0 +1,90 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# sll.S
+#-----------------------------------------------------------------------------
+#
+# Test sll instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2,  sll, 0x00000001, 0x00000001, 0  );
+  TEST_RR_OP( 3,  sll, 0x00000002, 0x00000001, 1  );
+  TEST_RR_OP( 4,  sll, 0x00000080, 0x00000001, 7  );
+  TEST_RR_OP( 5,  sll, 0x00004000, 0x00000001, 14 );
+  TEST_RR_OP( 6,  sll, 0x80000000, 0x00000001, 31 );
+
+  TEST_RR_OP( 7,  sll, 0xffffffff, 0xffffffff, 0  );
+  TEST_RR_OP( 8,  sll, 0xfffffffe, 0xffffffff, 1  );
+  TEST_RR_OP( 9,  sll, 0xffffff80, 0xffffffff, 7  );
+  TEST_RR_OP( 10, sll, 0xffffc000, 0xffffffff, 14 );
+  TEST_RR_OP( 11, sll, 0x80000000, 0xffffffff, 31 );
+
+  TEST_RR_OP( 12, sll, 0x21212121, 0x21212121, 0  );
+  TEST_RR_OP( 13, sll, 0x42424242, 0x21212121, 1  );
+  TEST_RR_OP( 14, sll, 0x90909080, 0x21212121, 7  );
+  TEST_RR_OP( 15, sll, 0x48484000, 0x21212121, 14 );
+  TEST_RR_OP( 16, sll, 0x80000000, 0x21212121, 31 );
+
+  # Verify that shifts only use bottom five bits
+
+  TEST_RR_OP( 17, sll, 0x21212121, 0x21212121, 0xffffffe0 );
+  TEST_RR_OP( 18, sll, 0x42424242, 0x21212121, 0xffffffe1 );
+  TEST_RR_OP( 19, sll, 0x90909080, 0x21212121, 0xffffffe7 );
+  TEST_RR_OP( 20, sll, 0x48484000, 0x21212121, 0xffffffee );
+  TEST_RR_OP( 21, sll, 0x00000000, 0x21212120, 0xffffffff );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_RR_SRC1_EQ_DEST( 22, sll, 0x00000080, 0x00000001, 7  );
+  TEST_RR_SRC2_EQ_DEST( 23, sll, 0x00004000, 0x00000001, 14 );
+  TEST_RR_SRC12_EQ_DEST( 24, sll, 24, 3 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_RR_DEST_BYPASS( 25, 0, sll, 0x00000080, 0x00000001, 7  );
+  TEST_RR_DEST_BYPASS( 26, 1, sll, 0x00004000, 0x00000001, 14 );
+  TEST_RR_DEST_BYPASS( 27, 2, sll, 0x80000000, 0x00000001, 31 );
+
+  TEST_RR_SRC12_BYPASS( 28, 0, 0, sll, 0x00000080, 0x00000001, 7  );
+  TEST_RR_SRC12_BYPASS( 29, 0, 1, sll, 0x00004000, 0x00000001, 14 );
+  TEST_RR_SRC12_BYPASS( 30, 0, 2, sll, 0x80000000, 0x00000001, 31 );
+  TEST_RR_SRC12_BYPASS( 31, 1, 0, sll, 0x00000080, 0x00000001, 7  );
+  TEST_RR_SRC12_BYPASS( 32, 1, 1, sll, 0x00004000, 0x00000001, 14 );
+  TEST_RR_SRC12_BYPASS( 33, 2, 0, sll, 0x80000000, 0x00000001, 31 );
+
+  TEST_RR_SRC21_BYPASS( 34, 0, 0, sll, 0x00000080, 0x00000001, 7  );
+  TEST_RR_SRC21_BYPASS( 35, 0, 1, sll, 0x00004000, 0x00000001, 14 );
+  TEST_RR_SRC21_BYPASS( 36, 0, 2, sll, 0x80000000, 0x00000001, 31 );
+  TEST_RR_SRC21_BYPASS( 37, 1, 0, sll, 0x00000080, 0x00000001, 7  );
+  TEST_RR_SRC21_BYPASS( 38, 1, 1, sll, 0x00004000, 0x00000001, 14 );
+  TEST_RR_SRC21_BYPASS( 39, 2, 0, sll, 0x80000000, 0x00000001, 31 );
+
+  TEST_RR_ZEROSRC1( 40, sll, 0, 15 );
+  TEST_RR_ZEROSRC2( 41, sll, 32, 32 );
+  TEST_RR_ZEROSRC12( 42, sll, 0 );
+  TEST_RR_ZERODEST( 43, sll, 1024, 2048 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/slli.S b/verilog/rtl/softshell/third_party/picorv32/tests/slli.S
new file mode 100644
index 0000000..a51eec9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/slli.S
@@ -0,0 +1,68 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# slli.S
+#-----------------------------------------------------------------------------
+#
+# Test slli instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_OP( 2,  slli, 0x00000001, 0x00000001, 0  );
+  TEST_IMM_OP( 3,  slli, 0x00000002, 0x00000001, 1  );
+  TEST_IMM_OP( 4,  slli, 0x00000080, 0x00000001, 7  );
+  TEST_IMM_OP( 5,  slli, 0x00004000, 0x00000001, 14 );
+  TEST_IMM_OP( 6,  slli, 0x80000000, 0x00000001, 31 );
+
+  TEST_IMM_OP( 7,  slli, 0xffffffff, 0xffffffff, 0  );
+  TEST_IMM_OP( 8,  slli, 0xfffffffe, 0xffffffff, 1  );
+  TEST_IMM_OP( 9,  slli, 0xffffff80, 0xffffffff, 7  );
+  TEST_IMM_OP( 10, slli, 0xffffc000, 0xffffffff, 14 );
+  TEST_IMM_OP( 11, slli, 0x80000000, 0xffffffff, 31 );
+
+  TEST_IMM_OP( 12, slli, 0x21212121, 0x21212121, 0  );
+  TEST_IMM_OP( 13, slli, 0x42424242, 0x21212121, 1  );
+  TEST_IMM_OP( 14, slli, 0x90909080, 0x21212121, 7  );
+  TEST_IMM_OP( 15, slli, 0x48484000, 0x21212121, 14 );
+  TEST_IMM_OP( 16, slli, 0x80000000, 0x21212121, 31 );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_SRC1_EQ_DEST( 17, slli, 0x00000080, 0x00000001, 7 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_DEST_BYPASS( 18, 0, slli, 0x00000080, 0x00000001, 7  );
+  TEST_IMM_DEST_BYPASS( 19, 1, slli, 0x00004000, 0x00000001, 14 );
+  TEST_IMM_DEST_BYPASS( 20, 2, slli, 0x80000000, 0x00000001, 31 );
+
+  TEST_IMM_SRC1_BYPASS( 21, 0, slli, 0x00000080, 0x00000001, 7  );
+  TEST_IMM_SRC1_BYPASS( 22, 1, slli, 0x00004000, 0x00000001, 14 );
+  TEST_IMM_SRC1_BYPASS( 23, 2, slli, 0x80000000, 0x00000001, 31 );
+
+  TEST_IMM_ZEROSRC1( 24, slli, 0, 31 );
+  TEST_IMM_ZERODEST( 25, slli, 33, 20 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/slt.S b/verilog/rtl/softshell/third_party/picorv32/tests/slt.S
new file mode 100644
index 0000000..3abf82b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/slt.S
@@ -0,0 +1,84 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# slt.S
+#-----------------------------------------------------------------------------
+#
+# Test slt instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2,  slt, 0, 0x00000000, 0x00000000 );
+  TEST_RR_OP( 3,  slt, 0, 0x00000001, 0x00000001 );
+  TEST_RR_OP( 4,  slt, 1, 0x00000003, 0x00000007 );
+  TEST_RR_OP( 5,  slt, 0, 0x00000007, 0x00000003 );
+
+  TEST_RR_OP( 6,  slt, 0, 0x00000000, 0xffff8000 );
+  TEST_RR_OP( 7,  slt, 1, 0x80000000, 0x00000000 );
+  TEST_RR_OP( 8,  slt, 1, 0x80000000, 0xffff8000 );
+
+  TEST_RR_OP( 9,  slt, 1, 0x00000000, 0x00007fff );
+  TEST_RR_OP( 10, slt, 0, 0x7fffffff, 0x00000000 );
+  TEST_RR_OP( 11, slt, 0, 0x7fffffff, 0x00007fff );
+
+  TEST_RR_OP( 12, slt, 1, 0x80000000, 0x00007fff );
+  TEST_RR_OP( 13, slt, 0, 0x7fffffff, 0xffff8000 );
+
+  TEST_RR_OP( 14, slt, 0, 0x00000000, 0xffffffff );
+  TEST_RR_OP( 15, slt, 1, 0xffffffff, 0x00000001 );
+  TEST_RR_OP( 16, slt, 0, 0xffffffff, 0xffffffff );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_RR_SRC1_EQ_DEST( 17, slt, 0, 14, 13 );
+  TEST_RR_SRC2_EQ_DEST( 18, slt, 1, 11, 13 );
+  TEST_RR_SRC12_EQ_DEST( 19, slt, 0, 13 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_RR_DEST_BYPASS( 20, 0, slt, 1, 11, 13 );
+  TEST_RR_DEST_BYPASS( 21, 1, slt, 0, 14, 13 );
+  TEST_RR_DEST_BYPASS( 22, 2, slt, 1, 12, 13 );
+
+  TEST_RR_SRC12_BYPASS( 23, 0, 0, slt, 0, 14, 13 );
+  TEST_RR_SRC12_BYPASS( 24, 0, 1, slt, 1, 11, 13 );
+  TEST_RR_SRC12_BYPASS( 25, 0, 2, slt, 0, 15, 13 );
+  TEST_RR_SRC12_BYPASS( 26, 1, 0, slt, 1, 10, 13 );
+  TEST_RR_SRC12_BYPASS( 27, 1, 1, slt, 0, 16, 13 );
+  TEST_RR_SRC12_BYPASS( 28, 2, 0, slt, 1,  9, 13 );
+
+  TEST_RR_SRC21_BYPASS( 29, 0, 0, slt, 0, 17, 13 );
+  TEST_RR_SRC21_BYPASS( 30, 0, 1, slt, 1,  8, 13 );
+  TEST_RR_SRC21_BYPASS( 31, 0, 2, slt, 0, 18, 13 );
+  TEST_RR_SRC21_BYPASS( 32, 1, 0, slt, 1,  7, 13 );
+  TEST_RR_SRC21_BYPASS( 33, 1, 1, slt, 0, 19, 13 );
+  TEST_RR_SRC21_BYPASS( 34, 2, 0, slt, 1,  6, 13 );
+
+  TEST_RR_ZEROSRC1( 35, slt, 0, -1 );
+  TEST_RR_ZEROSRC2( 36, slt, 1, -1 );
+  TEST_RR_ZEROSRC12( 37, slt, 0 );
+  TEST_RR_ZERODEST( 38, slt, 16, 30 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/slti.S b/verilog/rtl/softshell/third_party/picorv32/tests/slti.S
new file mode 100644
index 0000000..730cbe2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/slti.S
@@ -0,0 +1,70 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# slti.S
+#-----------------------------------------------------------------------------
+#
+# Test slti instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_OP( 2,  slti, 0, 0x00000000, 0x000 );
+  TEST_IMM_OP( 3,  slti, 0, 0x00000001, 0x001 );
+  TEST_IMM_OP( 4,  slti, 1, 0x00000003, 0x007 );
+  TEST_IMM_OP( 5,  slti, 0, 0x00000007, 0x003 );
+
+  TEST_IMM_OP( 6,  slti, 0, 0x00000000, 0x800 );
+  TEST_IMM_OP( 7,  slti, 1, 0x80000000, 0x000 );
+  TEST_IMM_OP( 8,  slti, 1, 0x80000000, 0x800 );
+
+  TEST_IMM_OP( 9,  slti, 1, 0x00000000, 0x7ff );
+  TEST_IMM_OP( 10, slti, 0, 0x7fffffff, 0x000 );
+  TEST_IMM_OP( 11, slti, 0, 0x7fffffff, 0x7ff );
+
+  TEST_IMM_OP( 12, slti, 1, 0x80000000, 0x7ff );
+  TEST_IMM_OP( 13, slti, 0, 0x7fffffff, 0x800 );
+
+  TEST_IMM_OP( 14, slti, 0, 0x00000000, 0xfff );
+  TEST_IMM_OP( 15, slti, 1, 0xffffffff, 0x001 );
+  TEST_IMM_OP( 16, slti, 0, 0xffffffff, 0xfff );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_SRC1_EQ_DEST( 17, sltiu, 1, 11, 13 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_DEST_BYPASS( 18, 0, slti, 0, 15, 10 );
+  TEST_IMM_DEST_BYPASS( 19, 1, slti, 1, 10, 16 );
+  TEST_IMM_DEST_BYPASS( 20, 2, slti, 0, 16,  9 );
+
+  TEST_IMM_SRC1_BYPASS( 21, 0, slti, 1, 11, 15 );
+  TEST_IMM_SRC1_BYPASS( 22, 1, slti, 0, 17,  8 );
+  TEST_IMM_SRC1_BYPASS( 23, 2, slti, 1, 12, 14 );
+
+  TEST_IMM_ZEROSRC1( 24, slti, 0, 0xfff );
+  TEST_IMM_ZERODEST( 25, slti, 0x00ff00ff, 0xfff );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/sra.S b/verilog/rtl/softshell/third_party/picorv32/tests/sra.S
new file mode 100644
index 0000000..8c1de36
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/sra.S
@@ -0,0 +1,90 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# sra.S
+#-----------------------------------------------------------------------------
+#
+# Test sra instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2,  sra, 0x80000000, 0x80000000, 0  );
+  TEST_RR_OP( 3,  sra, 0xc0000000, 0x80000000, 1  );
+  TEST_RR_OP( 4,  sra, 0xff000000, 0x80000000, 7  );
+  TEST_RR_OP( 5,  sra, 0xfffe0000, 0x80000000, 14 );
+  TEST_RR_OP( 6,  sra, 0xffffffff, 0x80000001, 31 );
+
+  TEST_RR_OP( 7,  sra, 0x7fffffff, 0x7fffffff, 0  );
+  TEST_RR_OP( 8,  sra, 0x3fffffff, 0x7fffffff, 1  );
+  TEST_RR_OP( 9,  sra, 0x00ffffff, 0x7fffffff, 7  );
+  TEST_RR_OP( 10, sra, 0x0001ffff, 0x7fffffff, 14 );
+  TEST_RR_OP( 11, sra, 0x00000000, 0x7fffffff, 31 );
+
+  TEST_RR_OP( 12, sra, 0x81818181, 0x81818181, 0  );
+  TEST_RR_OP( 13, sra, 0xc0c0c0c0, 0x81818181, 1  );
+  TEST_RR_OP( 14, sra, 0xff030303, 0x81818181, 7  );
+  TEST_RR_OP( 15, sra, 0xfffe0606, 0x81818181, 14 );
+  TEST_RR_OP( 16, sra, 0xffffffff, 0x81818181, 31 );
+
+  # Verify that shifts only use bottom five bits
+
+  TEST_RR_OP( 17, sra, 0x81818181, 0x81818181, 0xffffffc0 );
+  TEST_RR_OP( 18, sra, 0xc0c0c0c0, 0x81818181, 0xffffffc1 );
+  TEST_RR_OP( 19, sra, 0xff030303, 0x81818181, 0xffffffc7 );
+  TEST_RR_OP( 20, sra, 0xfffe0606, 0x81818181, 0xffffffce );
+  TEST_RR_OP( 21, sra, 0xffffffff, 0x81818181, 0xffffffff );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_RR_SRC1_EQ_DEST( 22, sra, 0xff000000, 0x80000000, 7  );
+  TEST_RR_SRC2_EQ_DEST( 23, sra, 0xfffe0000, 0x80000000, 14 );
+  TEST_RR_SRC12_EQ_DEST( 24, sra, 0, 7 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_RR_DEST_BYPASS( 25, 0, sra, 0xff000000, 0x80000000, 7  );
+  TEST_RR_DEST_BYPASS( 26, 1, sra, 0xfffe0000, 0x80000000, 14 );
+  TEST_RR_DEST_BYPASS( 27, 2, sra, 0xffffffff, 0x80000000, 31 );
+
+  TEST_RR_SRC12_BYPASS( 28, 0, 0, sra, 0xff000000, 0x80000000, 7  );
+  TEST_RR_SRC12_BYPASS( 29, 0, 1, sra, 0xfffe0000, 0x80000000, 14 );
+  TEST_RR_SRC12_BYPASS( 30, 0, 2, sra, 0xffffffff, 0x80000000, 31 );
+  TEST_RR_SRC12_BYPASS( 31, 1, 0, sra, 0xff000000, 0x80000000, 7  );
+  TEST_RR_SRC12_BYPASS( 32, 1, 1, sra, 0xfffe0000, 0x80000000, 14 );
+  TEST_RR_SRC12_BYPASS( 33, 2, 0, sra, 0xffffffff, 0x80000000, 31 );
+
+  TEST_RR_SRC21_BYPASS( 34, 0, 0, sra, 0xff000000, 0x80000000, 7  );
+  TEST_RR_SRC21_BYPASS( 35, 0, 1, sra, 0xfffe0000, 0x80000000, 14 );
+  TEST_RR_SRC21_BYPASS( 36, 0, 2, sra, 0xffffffff, 0x80000000, 31 );
+  TEST_RR_SRC21_BYPASS( 37, 1, 0, sra, 0xff000000, 0x80000000, 7  );
+  TEST_RR_SRC21_BYPASS( 38, 1, 1, sra, 0xfffe0000, 0x80000000, 14 );
+  TEST_RR_SRC21_BYPASS( 39, 2, 0, sra, 0xffffffff, 0x80000000, 31 );
+
+  TEST_RR_ZEROSRC1( 40, sra, 0, 15 );
+  TEST_RR_ZEROSRC2( 41, sra, 32, 32 );
+  TEST_RR_ZEROSRC12( 42, sra, 0 );
+  TEST_RR_ZERODEST( 43, sra, 1024, 2048 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/srai.S b/verilog/rtl/softshell/third_party/picorv32/tests/srai.S
new file mode 100644
index 0000000..4638190
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/srai.S
@@ -0,0 +1,68 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# srai.S
+#-----------------------------------------------------------------------------
+#
+# Test srai instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_OP( 2,  srai, 0x00000000, 0x00000000, 0  );
+  TEST_IMM_OP( 3,  srai, 0xc0000000, 0x80000000, 1  );
+  TEST_IMM_OP( 4,  srai, 0xff000000, 0x80000000, 7  );
+  TEST_IMM_OP( 5,  srai, 0xfffe0000, 0x80000000, 14 );
+  TEST_IMM_OP( 6,  srai, 0xffffffff, 0x80000001, 31 );
+
+  TEST_IMM_OP( 7,  srai, 0x7fffffff, 0x7fffffff, 0  );
+  TEST_IMM_OP( 8,  srai, 0x3fffffff, 0x7fffffff, 1  );
+  TEST_IMM_OP( 9,  srai, 0x00ffffff, 0x7fffffff, 7  );
+  TEST_IMM_OP( 10, srai, 0x0001ffff, 0x7fffffff, 14 );
+  TEST_IMM_OP( 11, srai, 0x00000000, 0x7fffffff, 31 );
+
+  TEST_IMM_OP( 12, srai, 0x81818181, 0x81818181, 0  );
+  TEST_IMM_OP( 13, srai, 0xc0c0c0c0, 0x81818181, 1  );
+  TEST_IMM_OP( 14, srai, 0xff030303, 0x81818181, 7  );
+  TEST_IMM_OP( 15, srai, 0xfffe0606, 0x81818181, 14 );
+  TEST_IMM_OP( 16, srai, 0xffffffff, 0x81818181, 31 );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_SRC1_EQ_DEST( 17, srai, 0xff000000, 0x80000000, 7 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_DEST_BYPASS( 18, 0, srai, 0xff000000, 0x80000000, 7  );
+  TEST_IMM_DEST_BYPASS( 19, 1, srai, 0xfffe0000, 0x80000000, 14 );
+  TEST_IMM_DEST_BYPASS( 20, 2, srai, 0xffffffff, 0x80000001, 31 );
+
+  TEST_IMM_SRC1_BYPASS( 21, 0, srai, 0xff000000, 0x80000000, 7 );
+  TEST_IMM_SRC1_BYPASS( 22, 1, srai, 0xfffe0000, 0x80000000, 14 );
+  TEST_IMM_SRC1_BYPASS( 23, 2, srai, 0xffffffff, 0x80000001, 31 );
+
+  TEST_IMM_ZEROSRC1( 24, srai, 0, 31 );
+  TEST_IMM_ZERODEST( 25, srai, 33, 20 );
+#
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/srl.S b/verilog/rtl/softshell/third_party/picorv32/tests/srl.S
new file mode 100644
index 0000000..35cc4c7
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/srl.S
@@ -0,0 +1,90 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# srl.S
+#-----------------------------------------------------------------------------
+#
+# Test srl instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2,  srl, 0xffff8000, 0xffff8000, 0  );
+  TEST_RR_OP( 3,  srl, 0x7fffc000, 0xffff8000, 1  );
+  TEST_RR_OP( 4,  srl, 0x01ffff00, 0xffff8000, 7  );
+  TEST_RR_OP( 5,  srl, 0x0003fffe, 0xffff8000, 14 );
+  TEST_RR_OP( 6,  srl, 0x0001ffff, 0xffff8001, 15 );
+
+  TEST_RR_OP( 7,  srl, 0xffffffff, 0xffffffff, 0  );
+  TEST_RR_OP( 8,  srl, 0x7fffffff, 0xffffffff, 1  );
+  TEST_RR_OP( 9,  srl, 0x01ffffff, 0xffffffff, 7  );
+  TEST_RR_OP( 10, srl, 0x0003ffff, 0xffffffff, 14 );
+  TEST_RR_OP( 11, srl, 0x00000001, 0xffffffff, 31 );
+
+  TEST_RR_OP( 12, srl, 0x21212121, 0x21212121, 0  );
+  TEST_RR_OP( 13, srl, 0x10909090, 0x21212121, 1  );
+  TEST_RR_OP( 14, srl, 0x00424242, 0x21212121, 7  );
+  TEST_RR_OP( 15, srl, 0x00008484, 0x21212121, 14 );
+  TEST_RR_OP( 16, srl, 0x00000000, 0x21212121, 31 );
+
+  # Verify that shifts only use bottom five bits
+
+  TEST_RR_OP( 17, srl, 0x21212121, 0x21212121, 0xffffffe0 );
+  TEST_RR_OP( 18, srl, 0x10909090, 0x21212121, 0xffffffe1 );
+  TEST_RR_OP( 19, srl, 0x00424242, 0x21212121, 0xffffffe7 );
+  TEST_RR_OP( 20, srl, 0x00008484, 0x21212121, 0xffffffee );
+  TEST_RR_OP( 21, srl, 0x00000000, 0x21212121, 0xffffffff );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_RR_SRC1_EQ_DEST( 22, srl, 0x7fffc000, 0xffff8000, 1  );
+  TEST_RR_SRC2_EQ_DEST( 23, srl, 0x0003fffe, 0xffff8000, 14 );
+  TEST_RR_SRC12_EQ_DEST( 24, srl, 0, 7 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_RR_DEST_BYPASS( 25, 0, srl, 0x7fffc000, 0xffff8000, 1  );
+  TEST_RR_DEST_BYPASS( 26, 1, srl, 0x0003fffe, 0xffff8000, 14 );
+  TEST_RR_DEST_BYPASS( 27, 2, srl, 0x0001ffff, 0xffff8000, 15 );
+
+  TEST_RR_SRC12_BYPASS( 28, 0, 0, srl, 0x7fffc000, 0xffff8000, 1  );
+  TEST_RR_SRC12_BYPASS( 29, 0, 1, srl, 0x01ffff00, 0xffff8000, 7 );
+  TEST_RR_SRC12_BYPASS( 30, 0, 2, srl, 0x0001ffff, 0xffff8000, 15 );
+  TEST_RR_SRC12_BYPASS( 31, 1, 0, srl, 0x7fffc000, 0xffff8000, 1  );
+  TEST_RR_SRC12_BYPASS( 32, 1, 1, srl, 0x01ffff00, 0xffff8000, 7 );
+  TEST_RR_SRC12_BYPASS( 33, 2, 0, srl, 0x0001ffff, 0xffff8000, 15 );
+
+  TEST_RR_SRC21_BYPASS( 34, 0, 0, srl, 0x7fffc000, 0xffff8000, 1  );
+  TEST_RR_SRC21_BYPASS( 35, 0, 1, srl, 0x01ffff00, 0xffff8000, 7 );
+  TEST_RR_SRC21_BYPASS( 36, 0, 2, srl, 0x0001ffff, 0xffff8000, 15 );
+  TEST_RR_SRC21_BYPASS( 37, 1, 0, srl, 0x7fffc000, 0xffff8000, 1  );
+  TEST_RR_SRC21_BYPASS( 38, 1, 1, srl, 0x01ffff00, 0xffff8000, 7 );
+  TEST_RR_SRC21_BYPASS( 39, 2, 0, srl, 0x0001ffff, 0xffff8000, 15 );
+
+  TEST_RR_ZEROSRC1( 40, srl, 0, 15 );
+  TEST_RR_ZEROSRC2( 41, srl, 32, 32 );
+  TEST_RR_ZEROSRC12( 42, srl, 0 );
+  TEST_RR_ZERODEST( 43, srl, 1024, 2048 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/srli.S b/verilog/rtl/softshell/third_party/picorv32/tests/srli.S
new file mode 100644
index 0000000..be56dc3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/srli.S
@@ -0,0 +1,69 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# srli.S
+#-----------------------------------------------------------------------------
+#
+# Test srli instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_OP( 2,  srli, 0xffff8000, 0xffff8000, 0  );
+  TEST_IMM_OP( 3,  srli, 0x7fffc000, 0xffff8000, 1  );
+  TEST_IMM_OP( 4,  srli, 0x01ffff00, 0xffff8000, 7  );
+  TEST_IMM_OP( 5,  srli, 0x0003fffe, 0xffff8000, 14 );
+  TEST_IMM_OP( 6,  srli, 0x0001ffff, 0xffff8001, 15 );
+
+  TEST_IMM_OP( 7,  srli, 0xffffffff, 0xffffffff, 0  );
+  TEST_IMM_OP( 8,  srli, 0x7fffffff, 0xffffffff, 1  );
+  TEST_IMM_OP( 9,  srli, 0x01ffffff, 0xffffffff, 7  );
+  TEST_IMM_OP( 10, srli, 0x0003ffff, 0xffffffff, 14 );
+  TEST_IMM_OP( 11, srli, 0x00000001, 0xffffffff, 31 );
+
+  TEST_IMM_OP( 12, srli, 0x21212121, 0x21212121, 0  );
+  TEST_IMM_OP( 13, srli, 0x10909090, 0x21212121, 1  );
+  TEST_IMM_OP( 14, srli, 0x00424242, 0x21212121, 7  );
+  TEST_IMM_OP( 15, srli, 0x00008484, 0x21212121, 14 );
+  TEST_IMM_OP( 16, srli, 0x00000000, 0x21212121, 31 );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_SRC1_EQ_DEST( 21, srli, 0x7fffc000, 0xffff8000, 1  );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_DEST_BYPASS( 22, 0, srl, 0x7fffc000, 0xffff8000, 1  );
+  TEST_IMM_DEST_BYPASS( 23, 1, srl, 0x0003fffe, 0xffff8000, 14 );
+  TEST_IMM_DEST_BYPASS( 24, 2, srl, 0x0001ffff, 0xffff8000, 15 );
+
+  TEST_IMM_SRC1_BYPASS( 25, 0, srl, 0x7fffc000, 0xffff8000, 1  );
+  TEST_IMM_SRC1_BYPASS( 26, 1, srl, 0x0003fffe, 0xffff8000, 14 );
+  TEST_IMM_SRC1_BYPASS( 27, 2, srl, 0x0001ffff, 0xffff8000, 15 );
+
+
+  TEST_IMM_ZEROSRC1( 28, srli, 0, 31 );
+  TEST_IMM_ZERODEST( 29, srli, 33, 20 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/sub.S b/verilog/rtl/softshell/third_party/picorv32/tests/sub.S
new file mode 100644
index 0000000..ad56e3e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/sub.S
@@ -0,0 +1,83 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# sub.S
+#-----------------------------------------------------------------------------
+#
+# Test sub instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Arithmetic tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2,  sub, 0x00000000, 0x00000000, 0x00000000 );
+  TEST_RR_OP( 3,  sub, 0x00000000, 0x00000001, 0x00000001 );
+  TEST_RR_OP( 4,  sub, 0xfffffffc, 0x00000003, 0x00000007 );
+
+  TEST_RR_OP( 5,  sub, 0x00008000, 0x00000000, 0xffff8000 );
+  TEST_RR_OP( 6,  sub, 0x80000000, 0x80000000, 0x00000000 );
+  TEST_RR_OP( 7,  sub, 0x80008000, 0x80000000, 0xffff8000 );
+
+  TEST_RR_OP( 8,  sub, 0xffff8001, 0x00000000, 0x00007fff );
+  TEST_RR_OP( 9,  sub, 0x7fffffff, 0x7fffffff, 0x00000000 );
+  TEST_RR_OP( 10, sub, 0x7fff8000, 0x7fffffff, 0x00007fff );
+
+  TEST_RR_OP( 11, sub, 0x7fff8001, 0x80000000, 0x00007fff );
+  TEST_RR_OP( 12, sub, 0x80007fff, 0x7fffffff, 0xffff8000 );
+
+  TEST_RR_OP( 13, sub, 0x00000001, 0x00000000, 0xffffffff );
+  TEST_RR_OP( 14, sub, 0xfffffffe, 0xffffffff, 0x00000001 );
+  TEST_RR_OP( 15, sub, 0x00000000, 0xffffffff, 0xffffffff );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_RR_SRC1_EQ_DEST( 16, sub, 2, 13, 11 );
+  TEST_RR_SRC2_EQ_DEST( 17, sub, 3, 14, 11 );
+  TEST_RR_SRC12_EQ_DEST( 18, sub, 0, 13 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_RR_DEST_BYPASS( 19, 0, sub, 2, 13, 11 );
+  TEST_RR_DEST_BYPASS( 20, 1, sub, 3, 14, 11 );
+  TEST_RR_DEST_BYPASS( 21, 2, sub, 4, 15, 11 );
+
+  TEST_RR_SRC12_BYPASS( 22, 0, 0, sub, 2, 13, 11 );
+  TEST_RR_SRC12_BYPASS( 23, 0, 1, sub, 3, 14, 11 );
+  TEST_RR_SRC12_BYPASS( 24, 0, 2, sub, 4, 15, 11 );
+  TEST_RR_SRC12_BYPASS( 25, 1, 0, sub, 2, 13, 11 );
+  TEST_RR_SRC12_BYPASS( 26, 1, 1, sub, 3, 14, 11 );
+  TEST_RR_SRC12_BYPASS( 27, 2, 0, sub, 4, 15, 11 );
+
+  TEST_RR_SRC21_BYPASS( 28, 0, 0, sub, 2, 13, 11 );
+  TEST_RR_SRC21_BYPASS( 29, 0, 1, sub, 3, 14, 11 );
+  TEST_RR_SRC21_BYPASS( 30, 0, 2, sub, 4, 15, 11 );
+  TEST_RR_SRC21_BYPASS( 31, 1, 0, sub, 2, 13, 11 );
+  TEST_RR_SRC21_BYPASS( 32, 1, 1, sub, 3, 14, 11 );
+  TEST_RR_SRC21_BYPASS( 33, 2, 0, sub, 4, 15, 11 );
+
+  TEST_RR_ZEROSRC1( 34, sub, 15, -15 );
+  TEST_RR_ZEROSRC2( 35, sub, 32, 32 );
+  TEST_RR_ZEROSRC12( 36, sub, 0 );
+  TEST_RR_ZERODEST( 37, sub, 16, 30 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/sw.S b/verilog/rtl/softshell/third_party/picorv32/tests/sw.S
new file mode 100644
index 0000000..fbf76cc
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/sw.S
@@ -0,0 +1,92 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# sw.S
+#-----------------------------------------------------------------------------
+#
+# Test sw instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Basic tests
+  #-------------------------------------------------------------
+
+  TEST_ST_OP( 2, lw, sw, 0x00aa00aa, 0,  tdat );
+  TEST_ST_OP( 3, lw, sw, 0xaa00aa00, 4,  tdat );
+  TEST_ST_OP( 4, lw, sw, 0x0aa00aa0, 8,  tdat );
+  TEST_ST_OP( 5, lw, sw, 0xa00aa00a, 12, tdat );
+
+  # Test with negative offset
+
+  TEST_ST_OP( 6, lw, sw, 0x00aa00aa, -12, tdat8 );
+  TEST_ST_OP( 7, lw, sw, 0xaa00aa00, -8,  tdat8 );
+  TEST_ST_OP( 8, lw, sw, 0x0aa00aa0, -4,  tdat8 );
+  TEST_ST_OP( 9, lw, sw, 0xa00aa00a, 0,   tdat8 );
+
+  # Test with a negative base
+
+  TEST_CASE( 10, x3, 0x12345678, \
+    la  x1, tdat9; \
+    li  x2, 0x12345678; \
+    addi x4, x1, -32; \
+    sw x2, 32(x4); \
+    lw x3, 0(x1); \
+  )
+
+  # Test with unaligned base
+
+  TEST_CASE( 11, x3, 0x58213098, \
+    la  x1, tdat9; \
+    li  x2, 0x58213098; \
+    addi x1, x1, -3; \
+    sw x2, 7(x1); \
+    la  x4, tdat10; \
+    lw x3, 0(x4); \
+  )
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_ST_SRC12_BYPASS( 12, 0, 0, lw, sw, 0xaabbccdd, 0,  tdat );
+  TEST_ST_SRC12_BYPASS( 13, 0, 1, lw, sw, 0xdaabbccd, 4,  tdat );
+  TEST_ST_SRC12_BYPASS( 14, 0, 2, lw, sw, 0xddaabbcc, 8,  tdat );
+  TEST_ST_SRC12_BYPASS( 15, 1, 0, lw, sw, 0xcddaabbc, 12, tdat );
+  TEST_ST_SRC12_BYPASS( 16, 1, 1, lw, sw, 0xccddaabb, 16, tdat );
+  TEST_ST_SRC12_BYPASS( 17, 2, 0, lw, sw, 0xbccddaab, 20, tdat );
+
+  TEST_ST_SRC21_BYPASS( 18, 0, 0, lw, sw, 0x00112233, 0,  tdat );
+  TEST_ST_SRC21_BYPASS( 19, 0, 1, lw, sw, 0x30011223, 4,  tdat );
+  TEST_ST_SRC21_BYPASS( 20, 0, 2, lw, sw, 0x33001122, 8,  tdat );
+  TEST_ST_SRC21_BYPASS( 21, 1, 0, lw, sw, 0x23300112, 12, tdat );
+  TEST_ST_SRC21_BYPASS( 22, 1, 1, lw, sw, 0x22330011, 16, tdat );
+  TEST_ST_SRC21_BYPASS( 23, 2, 0, lw, sw, 0x12233001, 20, tdat );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+tdat:
+tdat1:  .word 0xdeadbeef
+tdat2:  .word 0xdeadbeef
+tdat3:  .word 0xdeadbeef
+tdat4:  .word 0xdeadbeef
+tdat5:  .word 0xdeadbeef
+tdat6:  .word 0xdeadbeef
+tdat7:  .word 0xdeadbeef
+tdat8:  .word 0xdeadbeef
+tdat9:  .word 0xdeadbeef
+tdat10: .word 0xdeadbeef
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/test_macros.h b/verilog/rtl/softshell/third_party/picorv32/tests/test_macros.h
new file mode 100644
index 0000000..05ed7c8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/test_macros.h
@@ -0,0 +1,585 @@
+// See LICENSE for license details.
+
+#ifndef __TEST_MACROS_SCALAR_H
+#define __TEST_MACROS_SCALAR_H
+
+
+#-----------------------------------------------------------------------
+# Helper macros
+#-----------------------------------------------------------------------
+
+#define TEST_CASE( testnum, testreg, correctval, code... ) \
+test_ ## testnum: \
+    code; \
+    li  x29, correctval; \
+    li  TESTNUM, testnum; \
+    bne testreg, x29, fail;
+
+# We use a macro hack to simpify code generation for various numbers
+# of bubble cycles.
+
+#define TEST_INSERT_NOPS_0
+#define TEST_INSERT_NOPS_1  nop; TEST_INSERT_NOPS_0
+#define TEST_INSERT_NOPS_2  nop; TEST_INSERT_NOPS_1
+#define TEST_INSERT_NOPS_3  nop; TEST_INSERT_NOPS_2
+#define TEST_INSERT_NOPS_4  nop; TEST_INSERT_NOPS_3
+#define TEST_INSERT_NOPS_5  nop; TEST_INSERT_NOPS_4
+#define TEST_INSERT_NOPS_6  nop; TEST_INSERT_NOPS_5
+#define TEST_INSERT_NOPS_7  nop; TEST_INSERT_NOPS_6
+#define TEST_INSERT_NOPS_8  nop; TEST_INSERT_NOPS_7
+#define TEST_INSERT_NOPS_9  nop; TEST_INSERT_NOPS_8
+#define TEST_INSERT_NOPS_10 nop; TEST_INSERT_NOPS_9
+
+
+#-----------------------------------------------------------------------
+# RV64UI MACROS
+#-----------------------------------------------------------------------
+
+#-----------------------------------------------------------------------
+# Tests for instructions with immediate operand
+#-----------------------------------------------------------------------
+
+#define SEXT_IMM(x) ((x) | (-(((x) >> 11) & 1) << 11))
+
+#define TEST_IMM_OP( testnum, inst, result, val1, imm ) \
+    TEST_CASE( testnum, x3, result, \
+      li  x1, val1; \
+      inst x3, x1, SEXT_IMM(imm); \
+    )
+
+#define TEST_IMM_SRC1_EQ_DEST( testnum, inst, result, val1, imm ) \
+    TEST_CASE( testnum, x1, result, \
+      li  x1, val1; \
+      inst x1, x1, SEXT_IMM(imm); \
+    )
+
+#define TEST_IMM_DEST_BYPASS( testnum, nop_cycles, inst, result, val1, imm ) \
+    TEST_CASE( testnum, x6, result, \
+      li  x4, 0; \
+1:    li  x1, val1; \
+      inst x3, x1, SEXT_IMM(imm); \
+      TEST_INSERT_NOPS_ ## nop_cycles \
+      addi  x6, x3, 0; \
+      addi  x4, x4, 1; \
+      li  x5, 2; \
+      bne x4, x5, 1b \
+    )
+
+#define TEST_IMM_SRC1_BYPASS( testnum, nop_cycles, inst, result, val1, imm ) \
+    TEST_CASE( testnum, x3, result, \
+      li  x4, 0; \
+1:    li  x1, val1; \
+      TEST_INSERT_NOPS_ ## nop_cycles \
+      inst x3, x1, SEXT_IMM(imm); \
+      addi  x4, x4, 1; \
+      li  x5, 2; \
+      bne x4, x5, 1b \
+    )
+
+#define TEST_IMM_ZEROSRC1( testnum, inst, result, imm ) \
+    TEST_CASE( testnum, x1, result, \
+      inst x1, x0, SEXT_IMM(imm); \
+    )
+
+#define TEST_IMM_ZERODEST( testnum, inst, val1, imm ) \
+    TEST_CASE( testnum, x0, 0, \
+      li  x1, val1; \
+      inst x0, x1, SEXT_IMM(imm); \
+    )
+
+#-----------------------------------------------------------------------
+# Tests for vector config instructions
+#-----------------------------------------------------------------------
+
+#define TEST_VSETCFGIVL( testnum, nxpr, nfpr, bank, vl, result ) \
+    TEST_CASE( testnum, x1, result, \
+      li x1, (bank << 12); \
+      vsetcfg x1,nxpr,nfpr; \
+      li x1, vl; \
+      vsetvl x1,x1; \
+    )
+
+#define TEST_VVCFG( testnum, nxpr, nfpr, bank, vl, result ) \
+    TEST_CASE( testnum, x1, result, \
+      li x1, (bank << 12) | (nfpr << 6) | nxpr; \
+      vsetcfg x1; \
+      li x1, vl; \
+      vsetvl x1,x1; \
+    )
+
+#define TEST_VSETVL( testnum, nxpr, nfpr, bank, vl, result ) \
+    TEST_CASE( testnum, x1, result, \
+      li x1, (bank << 12); \
+      vsetcfg x1,nxpr,nfpr; \
+      li x1, vl; \
+      vsetvl x1, x1; \
+    )
+
+#-----------------------------------------------------------------------
+# Tests for an instruction with register operands
+#-----------------------------------------------------------------------
+
+#define TEST_R_OP( testnum, inst, result, val1 ) \
+    TEST_CASE( testnum, x3, result, \
+      li  x1, val1; \
+      inst x3, x1; \
+    )
+
+#define TEST_R_SRC1_EQ_DEST( testnum, inst, result, val1 ) \
+    TEST_CASE( testnum, x1, result, \
+      li  x1, val1; \
+      inst x1, x1; \
+    )
+
+#define TEST_R_DEST_BYPASS( testnum, nop_cycles, inst, result, val1 ) \
+    TEST_CASE( testnum, x6, result, \
+      li  x4, 0; \
+1:    li  x1, val1; \
+      inst x3, x1; \
+      TEST_INSERT_NOPS_ ## nop_cycles \
+      addi  x6, x3, 0; \
+      addi  x4, x4, 1; \
+      li  x5, 2; \
+      bne x4, x5, 1b \
+    )
+
+#-----------------------------------------------------------------------
+# Tests for an instruction with register-register operands
+#-----------------------------------------------------------------------
+
+#define TEST_RR_OP( testnum, inst, result, val1, val2 ) \
+    TEST_CASE( testnum, x3, result, \
+      li  x1, val1; \
+      li  x2, val2; \
+      inst x3, x1, x2; \
+    )
+
+#define TEST_RR_SRC1_EQ_DEST( testnum, inst, result, val1, val2 ) \
+    TEST_CASE( testnum, x1, result, \
+      li  x1, val1; \
+      li  x2, val2; \
+      inst x1, x1, x2; \
+    )
+
+#define TEST_RR_SRC2_EQ_DEST( testnum, inst, result, val1, val2 ) \
+    TEST_CASE( testnum, x2, result, \
+      li  x1, val1; \
+      li  x2, val2; \
+      inst x2, x1, x2; \
+    )
+
+#define TEST_RR_SRC12_EQ_DEST( testnum, inst, result, val1 ) \
+    TEST_CASE( testnum, x1, result, \
+      li  x1, val1; \
+      inst x1, x1, x1; \
+    )
+
+#define TEST_RR_DEST_BYPASS( testnum, nop_cycles, inst, result, val1, val2 ) \
+    TEST_CASE( testnum, x6, result, \
+      li  x4, 0; \
+1:    li  x1, val1; \
+      li  x2, val2; \
+      inst x3, x1, x2; \
+      TEST_INSERT_NOPS_ ## nop_cycles \
+      addi  x6, x3, 0; \
+      addi  x4, x4, 1; \
+      li  x5, 2; \
+      bne x4, x5, 1b \
+    )
+
+#define TEST_RR_SRC12_BYPASS( testnum, src1_nops, src2_nops, inst, result, val1, val2 ) \
+    TEST_CASE( testnum, x3, result, \
+      li  x4, 0; \
+1:    li  x1, val1; \
+      TEST_INSERT_NOPS_ ## src1_nops \
+      li  x2, val2; \
+      TEST_INSERT_NOPS_ ## src2_nops \
+      inst x3, x1, x2; \
+      addi  x4, x4, 1; \
+      li  x5, 2; \
+      bne x4, x5, 1b \
+    )
+
+#define TEST_RR_SRC21_BYPASS( testnum, src1_nops, src2_nops, inst, result, val1, val2 ) \
+    TEST_CASE( testnum, x3, result, \
+      li  x4, 0; \
+1:    li  x2, val2; \
+      TEST_INSERT_NOPS_ ## src1_nops \
+      li  x1, val1; \
+      TEST_INSERT_NOPS_ ## src2_nops \
+      inst x3, x1, x2; \
+      addi  x4, x4, 1; \
+      li  x5, 2; \
+      bne x4, x5, 1b \
+    )
+
+#define TEST_RR_ZEROSRC1( testnum, inst, result, val ) \
+    TEST_CASE( testnum, x2, result, \
+      li x1, val; \
+      inst x2, x0, x1; \
+    )
+
+#define TEST_RR_ZEROSRC2( testnum, inst, result, val ) \
+    TEST_CASE( testnum, x2, result, \
+      li x1, val; \
+      inst x2, x1, x0; \
+    )
+
+#define TEST_RR_ZEROSRC12( testnum, inst, result ) \
+    TEST_CASE( testnum, x1, result, \
+      inst x1, x0, x0; \
+    )
+
+#define TEST_RR_ZERODEST( testnum, inst, val1, val2 ) \
+    TEST_CASE( testnum, x0, 0, \
+      li x1, val1; \
+      li x2, val2; \
+      inst x0, x1, x2; \
+    )
+
+#-----------------------------------------------------------------------
+# Test memory instructions
+#-----------------------------------------------------------------------
+
+#define TEST_LD_OP( testnum, inst, result, offset, base ) \
+    TEST_CASE( testnum, x3, result, \
+      la  x1, base; \
+      inst x3, offset(x1); \
+    )
+
+#define TEST_ST_OP( testnum, load_inst, store_inst, result, offset, base ) \
+    TEST_CASE( testnum, x3, result, \
+      la  x1, base; \
+      li  x2, result; \
+      store_inst x2, offset(x1); \
+      load_inst x3, offset(x1); \
+    )
+
+#define TEST_LD_DEST_BYPASS( testnum, nop_cycles, inst, result, offset, base ) \
+test_ ## testnum: \
+    li  TESTNUM, testnum; \
+    li  x4, 0; \
+1:  la  x1, base; \
+    inst x3, offset(x1); \
+    TEST_INSERT_NOPS_ ## nop_cycles \
+    addi  x6, x3, 0; \
+    li  x29, result; \
+    bne x6, x29, fail; \
+    addi  x4, x4, 1; \
+    li  x5, 2; \
+    bne x4, x5, 1b; \
+
+#define TEST_LD_SRC1_BYPASS( testnum, nop_cycles, inst, result, offset, base ) \
+test_ ## testnum: \
+    li  TESTNUM, testnum; \
+    li  x4, 0; \
+1:  la  x1, base; \
+    TEST_INSERT_NOPS_ ## nop_cycles \
+    inst x3, offset(x1); \
+    li  x29, result; \
+    bne x3, x29, fail; \
+    addi  x4, x4, 1; \
+    li  x5, 2; \
+    bne x4, x5, 1b \
+
+#define TEST_ST_SRC12_BYPASS( testnum, src1_nops, src2_nops, load_inst, store_inst, result, offset, base ) \
+test_ ## testnum: \
+    li  TESTNUM, testnum; \
+    li  x4, 0; \
+1:  li  x1, result; \
+    TEST_INSERT_NOPS_ ## src1_nops \
+    la  x2, base; \
+    TEST_INSERT_NOPS_ ## src2_nops \
+    store_inst x1, offset(x2); \
+    load_inst x3, offset(x2); \
+    li  x29, result; \
+    bne x3, x29, fail; \
+    addi  x4, x4, 1; \
+    li  x5, 2; \
+    bne x4, x5, 1b \
+
+#define TEST_ST_SRC21_BYPASS( testnum, src1_nops, src2_nops, load_inst, store_inst, result, offset, base ) \
+test_ ## testnum: \
+    li  TESTNUM, testnum; \
+    li  x4, 0; \
+1:  la  x2, base; \
+    TEST_INSERT_NOPS_ ## src1_nops \
+    li  x1, result; \
+    TEST_INSERT_NOPS_ ## src2_nops \
+    store_inst x1, offset(x2); \
+    load_inst x3, offset(x2); \
+    li  x29, result; \
+    bne x3, x29, fail; \
+    addi  x4, x4, 1; \
+    li  x5, 2; \
+    bne x4, x5, 1b \
+
+#-----------------------------------------------------------------------
+# Test branch instructions
+#-----------------------------------------------------------------------
+
+#define TEST_BR1_OP_TAKEN( testnum, inst, val1 ) \
+test_ ## testnum: \
+    li  TESTNUM, testnum; \
+    li  x1, val1; \
+    inst x1, 2f; \
+    bne x0, TESTNUM, fail; \
+1:  bne x0, TESTNUM, 3f; \
+2:  inst x1, 1b; \
+    bne x0, TESTNUM, fail; \
+3:
+
+#define TEST_BR1_OP_NOTTAKEN( testnum, inst, val1 ) \
+test_ ## testnum: \
+    li  TESTNUM, testnum; \
+    li  x1, val1; \
+    inst x1, 1f; \
+    bne x0, TESTNUM, 2f; \
+1:  bne x0, TESTNUM, fail; \
+2:  inst x1, 1b; \
+3:
+
+#define TEST_BR1_SRC1_BYPASS( testnum, nop_cycles, inst, val1 ) \
+test_ ## testnum: \
+    li  TESTNUM, testnum; \
+    li  x4, 0; \
+1:  li  x1, val1; \
+    TEST_INSERT_NOPS_ ## nop_cycles \
+    inst x1, fail; \
+    addi  x4, x4, 1; \
+    li  x5, 2; \
+    bne x4, x5, 1b \
+
+#define TEST_BR2_OP_TAKEN( testnum, inst, val1, val2 ) \
+test_ ## testnum: \
+    li  TESTNUM, testnum; \
+    li  x1, val1; \
+    li  x2, val2; \
+    inst x1, x2, 2f; \
+    bne x0, TESTNUM, fail; \
+1:  bne x0, TESTNUM, 3f; \
+2:  inst x1, x2, 1b; \
+    bne x0, TESTNUM, fail; \
+3:
+
+#define TEST_BR2_OP_NOTTAKEN( testnum, inst, val1, val2 ) \
+test_ ## testnum: \
+    li  TESTNUM, testnum; \
+    li  x1, val1; \
+    li  x2, val2; \
+    inst x1, x2, 1f; \
+    bne x0, TESTNUM, 2f; \
+1:  bne x0, TESTNUM, fail; \
+2:  inst x1, x2, 1b; \
+3:
+
+#define TEST_BR2_SRC12_BYPASS( testnum, src1_nops, src2_nops, inst, val1, val2 ) \
+test_ ## testnum: \
+    li  TESTNUM, testnum; \
+    li  x4, 0; \
+1:  li  x1, val1; \
+    TEST_INSERT_NOPS_ ## src1_nops \
+    li  x2, val2; \
+    TEST_INSERT_NOPS_ ## src2_nops \
+    inst x1, x2, fail; \
+    addi  x4, x4, 1; \
+    li  x5, 2; \
+    bne x4, x5, 1b \
+
+#define TEST_BR2_SRC21_BYPASS( testnum, src1_nops, src2_nops, inst, val1, val2 ) \
+test_ ## testnum: \
+    li  TESTNUM, testnum; \
+    li  x4, 0; \
+1:  li  x2, val2; \
+    TEST_INSERT_NOPS_ ## src1_nops \
+    li  x1, val1; \
+    TEST_INSERT_NOPS_ ## src2_nops \
+    inst x1, x2, fail; \
+    addi  x4, x4, 1; \
+    li  x5, 2; \
+    bne x4, x5, 1b \
+
+#-----------------------------------------------------------------------
+# Test jump instructions
+#-----------------------------------------------------------------------
+
+#define TEST_JR_SRC1_BYPASS( testnum, nop_cycles, inst ) \
+test_ ## testnum: \
+    li  TESTNUM, testnum; \
+    li  x4, 0; \
+1:  la  x6, 2f; \
+    TEST_INSERT_NOPS_ ## nop_cycles \
+    inst x6; \
+    bne x0, TESTNUM, fail; \
+2:  addi  x4, x4, 1; \
+    li  x5, 2; \
+    bne x4, x5, 1b \
+
+#define TEST_JALR_SRC1_BYPASS( testnum, nop_cycles, inst ) \
+test_ ## testnum: \
+    li  TESTNUM, testnum; \
+    li  x4, 0; \
+1:  la  x6, 2f; \
+    TEST_INSERT_NOPS_ ## nop_cycles \
+    inst x19, x6, 0; \
+    bne x0, TESTNUM, fail; \
+2:  addi  x4, x4, 1; \
+    li  x5, 2; \
+    bne x4, x5, 1b \
+
+
+#-----------------------------------------------------------------------
+# RV64UF MACROS
+#-----------------------------------------------------------------------
+
+#-----------------------------------------------------------------------
+# Tests floating-point instructions
+#-----------------------------------------------------------------------
+
+#define TEST_FP_OP_S_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
+test_ ## testnum: \
+  li  TESTNUM, testnum; \
+  la  a0, test_ ## testnum ## _data ;\
+  flw f0, 0(a0); \
+  flw f1, 4(a0); \
+  flw f2, 8(a0); \
+  lw  a3, 12(a0); \
+  code; \
+  fsflags a1, x0; \
+  li a2, flags; \
+  bne a0, a3, fail; \
+  bne a1, a2, fail; \
+  j 2f; \
+  .align 2; \
+  .data; \
+  test_ ## testnum ## _data: \
+  .float val1; \
+  .float val2; \
+  .float val3; \
+  .result; \
+  .text; \
+2:
+
+#define TEST_FP_OP_D_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
+test_ ## testnum: \
+  li  TESTNUM, testnum; \
+  la  a0, test_ ## testnum ## _data ;\
+  fld f0, 0(a0); \
+  fld f1, 8(a0); \
+  fld f2, 16(a0); \
+  ld  a3, 24(a0); \
+  code; \
+  fsflags a1, x0; \
+  li a2, flags; \
+  bne a0, a3, fail; \
+  bne a1, a2, fail; \
+  j 2f; \
+  .data; \
+  .align 3; \
+  test_ ## testnum ## _data: \
+  .double val1; \
+  .double val2; \
+  .double val3; \
+  .result; \
+  .text; \
+2:
+
+#define TEST_FCVT_S_D( testnum, result, val1 ) \
+  TEST_FP_OP_D_INTERNAL( testnum, 0, double result, val1, 0.0, 0.0, \
+                    fcvt.s.d f3, f0; fcvt.d.s f3, f3; fmv.x.d a0, f3)
+
+#define TEST_FCVT_D_S( testnum, result, val1 ) \
+  TEST_FP_OP_S_INTERNAL( testnum, 0, float result, val1, 0.0, 0.0, \
+                    fcvt.d.s f3, f0; fcvt.s.d f3, f3; fmv.x.s a0, f3)
+
+#define TEST_FP_OP1_S( testnum, inst, flags, result, val1 ) \
+  TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, 0.0, 0.0, \
+                    inst f3, f0; fmv.x.s a0, f3)
+
+#define TEST_FP_OP1_D( testnum, inst, flags, result, val1 ) \
+  TEST_FP_OP_D_INTERNAL( testnum, flags, double result, val1, 0.0, 0.0, \
+                    inst f3, f0; fmv.x.d a0, f3)
+
+#define TEST_FP_OP2_S( testnum, inst, flags, result, val1, val2 ) \
+  TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, val2, 0.0, \
+                    inst f3, f0, f1; fmv.x.s a0, f3)
+
+#define TEST_FP_OP2_D( testnum, inst, flags, result, val1, val2 ) \
+  TEST_FP_OP_D_INTERNAL( testnum, flags, double result, val1, val2, 0.0, \
+                    inst f3, f0, f1; fmv.x.d a0, f3)
+
+#define TEST_FP_OP3_S( testnum, inst, flags, result, val1, val2, val3 ) \
+  TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, val2, val3, \
+                    inst f3, f0, f1, f2; fmv.x.s a0, f3)
+
+#define TEST_FP_OP3_D( testnum, inst, flags, result, val1, val2, val3 ) \
+  TEST_FP_OP_D_INTERNAL( testnum, flags, double result, val1, val2, val3, \
+                    inst f3, f0, f1, f2; fmv.x.d a0, f3)
+
+#define TEST_FP_INT_OP_S( testnum, inst, flags, result, val1, rm ) \
+  TEST_FP_OP_S_INTERNAL( testnum, flags, word result, val1, 0.0, 0.0, \
+                    inst a0, f0, rm)
+
+#define TEST_FP_INT_OP_D( testnum, inst, flags, result, val1, rm ) \
+  TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
+                    inst a0, f0, rm)
+
+#define TEST_FP_CMP_OP_S( testnum, inst, result, val1, val2 ) \
+  TEST_FP_OP_S_INTERNAL( testnum, 0, word result, val1, val2, 0.0, \
+                    inst a0, f0, f1)
+
+#define TEST_FP_CMP_OP_D( testnum, inst, result, val1, val2 ) \
+  TEST_FP_OP_D_INTERNAL( testnum, 0, dword result, val1, val2, 0.0, \
+                    inst a0, f0, f1)
+
+#define TEST_INT_FP_OP_S( testnum, inst, result, val1 ) \
+test_ ## testnum: \
+  li  TESTNUM, testnum; \
+  la  a0, test_ ## testnum ## _data ;\
+  lw  a3, 0(a0); \
+  li  a0, val1; \
+  inst f0, a0; \
+  fsflags x0; \
+  fmv.x.s a0, f0; \
+  bne a0, a3, fail; \
+  j 1f; \
+  .align 2; \
+  test_ ## testnum ## _data: \
+  .float result; \
+1:
+
+#define TEST_INT_FP_OP_D( testnum, inst, result, val1 ) \
+test_ ## testnum: \
+  li  TESTNUM, testnum; \
+  la  a0, test_ ## testnum ## _data ;\
+  ld  a3, 0(a0); \
+  li  a0, val1; \
+  inst f0, a0; \
+  fsflags x0; \
+  fmv.x.d a0, f0; \
+  bne a0, a3, fail; \
+  j 1f; \
+  .align 3; \
+  test_ ## testnum ## _data: \
+  .double result; \
+1:
+
+#-----------------------------------------------------------------------
+# Pass and fail code (assumes test num is in TESTNUM)
+#-----------------------------------------------------------------------
+
+#define TEST_PASSFAIL \
+        bne x0, TESTNUM, pass; \
+fail: \
+        RVTEST_FAIL; \
+pass: \
+        RVTEST_PASS \
+
+
+#-----------------------------------------------------------------------
+# Test data section
+#-----------------------------------------------------------------------
+
+#define TEST_DATA
+
+#endif
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/xor.S b/verilog/rtl/softshell/third_party/picorv32/tests/xor.S
new file mode 100644
index 0000000..72875fe
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/xor.S
@@ -0,0 +1,69 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# xor.S
+#-----------------------------------------------------------------------------
+#
+# Test xor instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Logical tests
+  #-------------------------------------------------------------
+
+  TEST_RR_OP( 2, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_OP( 3, xor, 0xff00ff00, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_OP( 4, xor, 0x0ff00ff0, 0x00ff00ff, 0x0f0f0f0f );
+  TEST_RR_OP( 5, xor, 0x00ff00ff, 0xf00ff00f, 0xf0f0f0f0 );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_RR_SRC1_EQ_DEST( 6, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC2_EQ_DEST( 7, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC12_EQ_DEST( 8, xor, 0x00000000, 0xff00ff00 );
+
+  #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_RR_DEST_BYPASS( 9,  0, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_DEST_BYPASS( 10, 1, xor, 0xff00ff00, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_DEST_BYPASS( 11, 2, xor, 0x0ff00ff0, 0x00ff00ff, 0x0f0f0f0f );
+
+  TEST_RR_SRC12_BYPASS( 12, 0, 0, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC12_BYPASS( 13, 0, 1, xor, 0xff00ff00, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_SRC12_BYPASS( 14, 0, 2, xor, 0x0ff00ff0, 0x00ff00ff, 0x0f0f0f0f );
+  TEST_RR_SRC12_BYPASS( 15, 1, 0, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC12_BYPASS( 16, 1, 1, xor, 0xff00ff00, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_SRC12_BYPASS( 17, 2, 0, xor, 0x0ff00ff0, 0x00ff00ff, 0x0f0f0f0f );
+
+  TEST_RR_SRC21_BYPASS( 18, 0, 0, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC21_BYPASS( 19, 0, 1, xor, 0xff00ff00, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_SRC21_BYPASS( 20, 0, 2, xor, 0x0ff00ff0, 0x00ff00ff, 0x0f0f0f0f );
+  TEST_RR_SRC21_BYPASS( 21, 1, 0, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f );
+  TEST_RR_SRC21_BYPASS( 22, 1, 1, xor, 0xff00ff00, 0x0ff00ff0, 0xf0f0f0f0 );
+  TEST_RR_SRC21_BYPASS( 23, 2, 0, xor, 0x0ff00ff0, 0x00ff00ff, 0x0f0f0f0f );
+
+  TEST_RR_ZEROSRC1( 24, xor, 0xff00ff00, 0xff00ff00 );
+  TEST_RR_ZEROSRC2( 25, xor, 0x00ff00ff, 0x00ff00ff );
+  TEST_RR_ZEROSRC12( 26, xor, 0 );
+  TEST_RR_ZERODEST( 27, xor, 0x11111111, 0x22222222 );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32/tests/xori.S b/verilog/rtl/softshell/third_party/picorv32/tests/xori.S
new file mode 100644
index 0000000..7f2207c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32/tests/xori.S
@@ -0,0 +1,55 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# xori.S
+#-----------------------------------------------------------------------------
+#
+# Test xori instruction.
+#
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV32U
+RVTEST_CODE_BEGIN
+
+  #-------------------------------------------------------------
+  # Logical tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_OP( 2, xori, 0xff00f00f, 0x00ff0f00, 0xf0f );
+  TEST_IMM_OP( 3, xori, 0x0ff00f00, 0x0ff00ff0, 0x0f0 );
+  TEST_IMM_OP( 4, xori, 0x00ff0ff0, 0x00ff08ff, 0x70f );
+  TEST_IMM_OP( 5, xori, 0xf00ff0ff, 0xf00ff00f, 0x0f0 );
+
+  #-------------------------------------------------------------
+  # Source/Destination tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_SRC1_EQ_DEST( 6, xori, 0xff00f00f, 0xff00f700, 0x70f );
+
+   #-------------------------------------------------------------
+  # Bypassing tests
+  #-------------------------------------------------------------
+
+  TEST_IMM_DEST_BYPASS( 7,  0, xori, 0x0ff00f00, 0x0ff00ff0, 0x0f0 );
+  TEST_IMM_DEST_BYPASS( 8,  1, xori, 0x00ff0ff0, 0x00ff08ff, 0x70f );
+  TEST_IMM_DEST_BYPASS( 9,  2, xori, 0xf00ff0ff, 0xf00ff00f, 0x0f0 );
+
+  TEST_IMM_SRC1_BYPASS( 10, 0, xori, 0x0ff00f00, 0x0ff00ff0, 0x0f0 );
+  TEST_IMM_SRC1_BYPASS( 11, 1, xori, 0x00ff0ff0, 0x00ff0fff, 0x00f );
+  TEST_IMM_SRC1_BYPASS( 12, 2, xori, 0xf00ff0ff, 0xf00ff00f, 0x0f0 );
+
+  TEST_IMM_ZEROSRC1( 13, xori, 0x0f0, 0x0f0 );
+  TEST_IMM_ZERODEST( 14, xori, 0x00ff00ff, 0x70f );
+
+  TEST_PASSFAIL
+
+RVTEST_CODE_END
+
+  .data
+RVTEST_DATA_BEGIN
+
+  TEST_DATA
+
+RVTEST_DATA_END
diff --git a/verilog/rtl/softshell/third_party/picorv32_wb/gpio32_wb.v b/verilog/rtl/softshell/third_party/picorv32_wb/gpio32_wb.v
new file mode 100644
index 0000000..1c51220
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32_wb/gpio32_wb.v
@@ -0,0 +1,134 @@
+// Simple 32-bit GPIO peripheral.
+//
+// Derived from gpio_wb.v from Caravel.
+
+`default_nettype none
+module gpio32_wb # (
+    parameter GPIO_DATA = 8'h 00,
+    parameter GPIO_ENA  = 8'h 04,
+    parameter GPIO_PU   = 8'h 08,
+    parameter GPIO_PD   = 8'h 0c
+) (
+    input wb_clk_i,
+    input wb_rst_i,
+
+    input [31:0] wb_dat_i,
+    input [31:0] wb_adr_i,
+    input [3:0] wb_sel_i,
+    input wb_cyc_i,
+    input wb_stb_i,
+    input wb_we_i,
+
+    output [31:0] wb_dat_o,
+    output wb_ack_o,
+
+    input [31:0]  gpio_in,
+    output [31:0] gpio_out,
+    output [31:0] gpio_oeb
+);
+
+    wire resetn;
+    wire valid;
+    wire ready;
+    wire [3:0] iomem_we;
+
+    assign resetn = ~wb_rst_i;
+    assign valid = wb_stb_i && wb_cyc_i;
+
+    assign iomem_we = wb_sel_i & {4{wb_we_i}};
+    assign wb_ack_o = ready;
+
+    gpio #(
+        .GPIO_DATA(GPIO_DATA),
+        .GPIO_ENA(GPIO_ENA),
+        .GPIO_PD(GPIO_PD),
+        .GPIO_PU(GPIO_PU)
+    ) gpio_ctrl (
+        .clk(wb_clk_i),
+        .resetn(resetn),
+
+        .iomem_addr(wb_adr_i),
+        .iomem_valid(valid),
+        .iomem_wstrb(iomem_we[0]),
+        .iomem_wdata(wb_dat_i),
+        .iomem_rdata(wb_dat_o),
+        .iomem_ready(ready),
+
+        .gpio_in(gpio_in),
+        .gpio_out(gpio_out),
+        .gpio_oeb(gpio_oeb)
+    );
+
+endmodule
+
+module gpio #(
+    parameter GPIO_DATA = 8'h 00,
+    parameter GPIO_ENA  = 8'h 04,
+    parameter GPIO_PU   = 8'h 08,
+    parameter GPIO_PD   = 8'h 0c
+) (
+    input clk,
+    input resetn,
+
+    input gpio_in_pad,
+
+    input [31:0] iomem_addr,
+    input iomem_valid,
+    input iomem_wstrb,
+    input [31:0] iomem_wdata,
+    output reg [31:0] iomem_rdata,
+    output reg iomem_ready,
+
+    input [31:0]  gpio_in,
+    output [31:0] gpio_out,
+    output [31:0] gpio_oeb
+);
+
+    reg [31:0] gpio_out;		// GPIO output data
+    reg [31:0] gpio_pu;		// GPIO pull-up enable
+    reg [31:0] gpio_pd;		// GPIO pull-down enable
+    reg [31:0] gpio_oeb;    // GPIO output enable (sense negative)
+
+    wire gpio_sel;
+    wire gpio_oeb_sel;
+    wire gpio_pu_sel;
+    wire gpio_pd_sel;
+
+    assign gpio_sel     = (iomem_addr[7:0] == GPIO_DATA);
+    assign gpio_oeb_sel = (iomem_addr[7:0] == GPIO_ENA);
+    assign gpio_pu_sel  = (iomem_addr[7:0] == GPIO_PU);
+    assign gpio_pd_sel  = (iomem_addr[7:0] == GPIO_PD);
+
+    always @(posedge clk) begin
+        if (!resetn) begin
+            gpio_out <= 32'h0;
+            gpio_oeb <= 32'hffff_ffff;
+        end else begin
+            iomem_ready <= 0;
+            if (iomem_valid && !iomem_ready) begin
+                iomem_ready <= 1'b 1;
+
+                if (gpio_sel) begin
+                    iomem_rdata <= gpio_in;
+                    if (iomem_wstrb) gpio_out <= iomem_wdata;
+
+                end else if (gpio_oeb_sel) begin
+                    iomem_rdata <= ~gpio_oeb;
+                    if (iomem_wstrb) gpio_oeb <= ~iomem_wdata;
+
+                end else if (gpio_pu_sel) begin
+                    iomem_rdata <= gpio_pu;
+                    if (iomem_wstrb) gpio_pu <= iomem_wdata;
+
+                end else if (gpio_pd_sel) begin
+                    iomem_rdata <= gpio_pd;
+                    if (iomem_wstrb) gpio_pd <= iomem_wdata;
+
+                end
+
+            end
+        end
+    end
+
+endmodule
+`default_nettype wire
diff --git a/verilog/rtl/softshell/third_party/picorv32_wb/gpio_wb.v b/verilog/rtl/softshell/third_party/picorv32_wb/gpio_wb.v
new file mode 100644
index 0000000..70bf65e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32_wb/gpio_wb.v
@@ -0,0 +1,141 @@
+`default_nettype none
+module gpio_wb # (
+    parameter BASE_ADR  = 32'h 2100_0000,
+    parameter GPIO_DATA = 8'h 00,
+    parameter GPIO_ENA  = 8'h 04,
+    parameter GPIO_PU   = 8'h 08,
+    parameter GPIO_PD   = 8'h 0c
+) (
+    input wb_clk_i,
+    input wb_rst_i,
+
+    input [31:0] wb_dat_i,
+    input [31:0] wb_adr_i,
+    input [3:0] wb_sel_i,
+    input wb_cyc_i,
+    input wb_stb_i,
+    input wb_we_i,
+
+    output [31:0] wb_dat_o,
+    output wb_ack_o,
+
+    input  gpio_in_pad,
+    output gpio,
+    output gpio_oeb,
+    output gpio_pu,
+    output gpio_pd
+);
+
+    wire resetn;
+    wire valid;
+    wire ready;
+    wire [3:0] iomem_we;
+
+    assign resetn = ~wb_rst_i;
+    assign valid = wb_stb_i && wb_cyc_i; 
+
+    assign iomem_we = wb_sel_i & {4{wb_we_i}};
+    assign wb_ack_o = ready;
+
+    gpio #(
+        .BASE_ADR(BASE_ADR),
+        .GPIO_DATA(GPIO_DATA),
+        .GPIO_ENA(GPIO_ENA),
+        .GPIO_PD(GPIO_PD),
+        .GPIO_PU(GPIO_PU)
+    ) gpio_ctrl (
+        .clk(wb_clk_i),
+        .resetn(resetn),
+
+        .gpio_in_pad(gpio_in_pad),
+
+        .iomem_addr(wb_adr_i),
+        .iomem_valid(valid),
+        .iomem_wstrb(iomem_we[0]),
+        .iomem_wdata(wb_dat_i),
+        .iomem_rdata(wb_dat_o),
+        .iomem_ready(ready),
+
+        .gpio(gpio),
+        .gpio_oeb(gpio_oeb),
+        .gpio_pu(gpio_pu),
+        .gpio_pd(gpio_pd)
+    );
+    
+endmodule
+
+module gpio #(
+    parameter BASE_ADR  = 32'h 2100_0000,
+    parameter GPIO_DATA = 8'h 00,
+    parameter GPIO_ENA  = 8'h 04,
+    parameter GPIO_PU   = 8'h 08,
+    parameter GPIO_PD   = 8'h 0c
+) (
+    input clk,
+    input resetn,
+
+    input gpio_in_pad,
+
+    input [31:0] iomem_addr,
+    input iomem_valid,
+    input iomem_wstrb,
+    input [31:0] iomem_wdata,
+    output reg [31:0] iomem_rdata,
+    output reg iomem_ready,
+
+    output gpio,
+    output gpio_oeb,
+    output gpio_pu,
+    output gpio_pd
+);
+
+    reg gpio;		// GPIO output data
+    reg gpio_pu;		// GPIO pull-up enable
+    reg gpio_pd;		// GPIO pull-down enable
+    reg gpio_oeb;    // GPIO output enable (sense negative)
+    
+    wire gpio_sel;
+    wire gpio_oeb_sel;
+    wire gpio_pu_sel;  
+    wire gpio_pd_sel;
+
+    assign gpio_sel     = (iomem_addr[7:0] == GPIO_DATA);
+    assign gpio_oeb_sel = (iomem_addr[7:0] == GPIO_ENA);
+    assign gpio_pu_sel  = (iomem_addr[7:0] == GPIO_PU);
+    assign gpio_pd_sel  = (iomem_addr[7:0] == GPIO_PD);
+
+    always @(posedge clk) begin
+        if (!resetn) begin
+            gpio <= 0;
+            gpio_oeb <= 16'hffff;
+            gpio_pu <= 0;
+            gpio_pd <= 0;
+        end else begin
+            iomem_ready <= 0;
+            if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
+                iomem_ready <= 1'b 1;
+                
+                if (gpio_sel) begin
+                    iomem_rdata <= {30'd0, gpio, gpio_in_pad};
+                    if (iomem_wstrb) gpio <= iomem_wdata[0];
+
+                end else if (gpio_oeb_sel) begin
+                    iomem_rdata <= {31'd0, gpio_oeb};
+                    if (iomem_wstrb) gpio_oeb <= iomem_wdata[0];
+
+                end else if (gpio_pu_sel) begin
+                    iomem_rdata <= {31'd0, gpio_pu};
+                    if (iomem_wstrb) gpio_pu <= iomem_wdata[0];
+
+                end else if (gpio_pd_sel) begin
+                    iomem_rdata <= {31'd0, gpio_pd};          
+                    if (iomem_wstrb) gpio_pd <= iomem_wdata[0];
+
+                end
+
+            end
+        end
+    end
+
+endmodule
+`default_nettype wire
diff --git a/verilog/rtl/softshell/third_party/picorv32_wb/la_wb.v b/verilog/rtl/softshell/third_party/picorv32_wb/la_wb.v
new file mode 100644
index 0000000..07dfc90
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32_wb/la_wb.v
@@ -0,0 +1,206 @@
+`default_nettype none
+module la_wb # (
+    parameter BASE_ADR  = 32'h 2200_0000,
+    parameter LA_DATA_0 = 8'h00,
+    parameter LA_DATA_1 = 8'h04,
+    parameter LA_DATA_2 = 8'h08,
+    parameter LA_DATA_3 = 8'h0c,
+    parameter LA_ENA_0 = 8'h10,
+    parameter LA_ENA_1 = 8'h14,
+    parameter LA_ENA_2 = 8'h18,
+    parameter LA_ENA_3 = 8'h1c
+) (
+    input wb_clk_i,
+    input wb_rst_i,
+
+    input [31:0] wb_dat_i,
+    input [31:0] wb_adr_i,
+    input [3:0] wb_sel_i,
+    input wb_cyc_i,
+    input wb_stb_i,
+    input wb_we_i,
+
+    output [31:0] wb_dat_o,
+    output wb_ack_o,
+
+    input  [127:0] la_data_in, // From MPRJ 
+    output [127:0] la_data,
+    output [127:0] la_oen
+);
+
+    wire resetn;
+    wire valid;
+    wire ready;
+    wire [3:0] iomem_we;
+
+    assign resetn = ~wb_rst_i;
+    assign valid = wb_stb_i && wb_cyc_i; 
+
+    assign iomem_we = wb_sel_i & {4{wb_we_i}};
+    assign wb_ack_o = ready;
+
+    la #(
+        .BASE_ADR(BASE_ADR),
+        .LA_DATA_0(LA_DATA_0),
+        .LA_DATA_1(LA_DATA_1),
+        .LA_DATA_2(LA_DATA_2),
+        .LA_DATA_3(LA_DATA_3),
+        .LA_ENA_0(LA_ENA_0),
+        .LA_ENA_1(LA_ENA_1),
+        .LA_ENA_2(LA_ENA_2),
+        .LA_ENA_3(LA_ENA_3)
+    ) la_ctrl (
+        .clk(wb_clk_i),
+        .resetn(resetn),
+        .iomem_addr(wb_adr_i),
+        .iomem_valid(valid),
+        .iomem_wstrb(iomem_we),
+        .iomem_wdata(wb_dat_i),
+        .iomem_rdata(wb_dat_o),
+        .iomem_ready(ready),
+        .la_data_in(la_data_in),
+        .la_data(la_data),
+        .la_oen(la_oen)
+    );
+    
+endmodule
+
+module la #(
+    parameter BASE_ADR  = 32'h 2200_0000,
+    parameter LA_DATA_0 = 8'h00,
+    parameter LA_DATA_1 = 8'h04,
+    parameter LA_DATA_2 = 8'h08,
+    parameter LA_DATA_3 = 8'h0c,
+    parameter LA_ENA_0  = 8'h10,
+    parameter LA_ENA_1  = 8'h14,
+    parameter LA_ENA_2  = 8'h18,
+    parameter LA_ENA_3  = 8'h1c
+) (
+    input clk,
+    input resetn,
+
+    input [31:0] iomem_addr,
+    input iomem_valid,
+    input [3:0] iomem_wstrb,
+    input [31:0] iomem_wdata,
+
+    output reg [31:0] iomem_rdata,
+    output reg iomem_ready,
+
+    input  [127:0] la_data_in, // From MPRJ 
+    output [127:0] la_data,    // To MPRJ
+    output [127:0] la_oen
+);
+
+    reg [31:0] la_data_0;		
+    reg [31:0] la_data_1;		
+    reg [31:0] la_data_2;		
+    reg [31:0] la_data_3; 
+
+    reg [31:0] la_ena_0;		
+    reg [31:0] la_ena_1;		
+    reg [31:0] la_ena_2;		
+    reg [31:0] la_ena_3;    
+    
+    wire [3:0] la_data_sel;
+    wire [3:0] la_ena_sel;
+
+    assign la_data = {la_data_3, la_data_2, la_data_1, la_data_0};
+    assign la_oen  = {la_ena_3, la_ena_2, la_ena_1, la_ena_0};
+
+    assign la_data_sel = {
+        (iomem_addr[7:0] == LA_DATA_3),
+        (iomem_addr[7:0] == LA_DATA_2),
+        (iomem_addr[7:0] == LA_DATA_1),
+        (iomem_addr[7:0] == LA_DATA_0)
+    };
+
+    assign la_ena_sel = {
+        (iomem_addr[7:0] == LA_ENA_3),
+        (iomem_addr[7:0] == LA_ENA_2),
+        (iomem_addr[7:0] == LA_ENA_1),
+        (iomem_addr[7:0] == LA_ENA_0)
+    };
+
+
+    always @(posedge clk) begin
+        if (!resetn) begin
+            la_data_0 <= 0;
+            la_data_1 <= 0;
+            la_data_2 <= 0;
+            la_data_3 <= 0;
+            la_ena_0  <= 32'hFFFF_FFFF;  // default is tri-state buff disabled
+            la_ena_1  <= 32'hFFFF_FFFF;
+            la_ena_2  <= 32'hFFFF_FFFF;
+            la_ena_3  <= 32'hFFFF_FFFF;
+        end else begin
+            iomem_ready <= 0;
+            if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
+                iomem_ready <= 1'b 1;
+                
+                if (la_data_sel[0]) begin
+                    iomem_rdata <= la_data_0 | (la_data_in[31:0] & la_ena_0);
+
+                    if (iomem_wstrb[0]) la_data_0[ 7: 0] <= iomem_wdata[ 7: 0];
+                    if (iomem_wstrb[1]) la_data_0[15: 8] <= iomem_wdata[15: 8];
+                    if (iomem_wstrb[2]) la_data_0[23:16] <= iomem_wdata[23:16];
+                    if (iomem_wstrb[3]) la_data_0[31:24] <= iomem_wdata[31:24];
+
+                end else if (la_data_sel[1]) begin
+                    iomem_rdata <= la_data_1 | (la_data_in[63:32] & la_ena_1);
+
+                    if (iomem_wstrb[0]) la_data_1[ 7: 0] <= iomem_wdata[ 7: 0];
+                    if (iomem_wstrb[1]) la_data_1[15: 8] <= iomem_wdata[15: 8];
+                    if (iomem_wstrb[2]) la_data_1[23:16] <= iomem_wdata[23:16];
+                    if (iomem_wstrb[3]) la_data_1[31:24] <= iomem_wdata[31:24];
+
+                end else if (la_data_sel[2]) begin
+                    iomem_rdata <= la_data_2 | (la_data_in[95:64] & la_ena_2);
+
+                    if (iomem_wstrb[0]) la_data_2[ 7: 0] <= iomem_wdata[ 7: 0];
+                    if (iomem_wstrb[1]) la_data_2[15: 8] <= iomem_wdata[15: 8];
+                    if (iomem_wstrb[2]) la_data_2[23:16] <= iomem_wdata[23:16];
+                    if (iomem_wstrb[3]) la_data_2[31:24] <= iomem_wdata[31:24];
+
+                end else if (la_data_sel[3]) begin
+                    iomem_rdata <= la_data_3 | (la_data_in[127:96] & la_ena_3);
+
+                    if (iomem_wstrb[0]) la_data_3[ 7: 0] <= iomem_wdata[ 7: 0];
+                    if (iomem_wstrb[1]) la_data_3[15: 8] <= iomem_wdata[15: 8];
+                    if (iomem_wstrb[2]) la_data_3[23:16] <= iomem_wdata[23:16];
+                    if (iomem_wstrb[3]) la_data_3[31:24] <= iomem_wdata[31:24];
+                end else if (la_ena_sel[0]) begin
+                    iomem_rdata <= la_ena_0;
+
+                    if (iomem_wstrb[0]) la_ena_0[ 7: 0] <= iomem_wdata[ 7: 0];
+                    if (iomem_wstrb[1]) la_ena_0[15: 8] <= iomem_wdata[15: 8];
+                    if (iomem_wstrb[2]) la_ena_0[23:16] <= iomem_wdata[23:16];
+                    if (iomem_wstrb[3]) la_ena_0[31:24] <= iomem_wdata[31:24];
+                end else if (la_ena_sel[1]) begin
+                    iomem_rdata <= la_ena_1;
+
+                    if (iomem_wstrb[0]) la_ena_1[ 7: 0] <= iomem_wdata[ 7: 0];
+                    if (iomem_wstrb[1]) la_ena_1[15: 8] <= iomem_wdata[15: 8];
+                    if (iomem_wstrb[2]) la_ena_1[23:16] <= iomem_wdata[23:16];
+                    if (iomem_wstrb[3]) la_ena_1[31:24] <= iomem_wdata[31:24];
+                end else if (la_ena_sel[2]) begin
+                    iomem_rdata <= la_ena_2;
+
+                    if (iomem_wstrb[0]) la_ena_2[ 7: 0] <= iomem_wdata[ 7: 0];
+                    if (iomem_wstrb[1]) la_ena_2[15: 8] <= iomem_wdata[15: 8];
+                    if (iomem_wstrb[2]) la_ena_2[23:16] <= iomem_wdata[23:16];
+                    if (iomem_wstrb[3]) la_ena_2[31:24] <= iomem_wdata[31:24];
+                end else if (la_ena_sel[3]) begin
+                    iomem_rdata <= la_ena_3;
+
+                    if (iomem_wstrb[0]) la_ena_3[ 7: 0] <= iomem_wdata[ 7: 0];
+                    if (iomem_wstrb[1]) la_ena_3[15: 8] <= iomem_wdata[15: 8];
+                    if (iomem_wstrb[2]) la_ena_3[23:16] <= iomem_wdata[23:16];
+                    if (iomem_wstrb[3]) la_ena_3[31:24] <= iomem_wdata[31:24];
+                end 
+            end
+        end
+    end
+
+endmodule
+`default_nettype wire
diff --git a/verilog/rtl/softshell/third_party/picorv32_wb/mem_ff_wb.v b/verilog/rtl/softshell/third_party/picorv32_wb/mem_ff_wb.v
new file mode 100644
index 0000000..250dc8e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32_wb/mem_ff_wb.v
@@ -0,0 +1,122 @@
+// Inferred RAM to work around limitations in Openlane.
+//
+// Wishbone interface based on mem_wb.v from Caravel.
+
+`default_nettype none
+module mem_ff_wb #(
+  parameter MEM_WORDS = 256
+)(
+  input wb_clk_i,
+  input wb_rst_i,
+
+  input [31:0] wb_adr_i,
+  input [31:0] wb_dat_i,
+  input [3:0] wb_sel_i,
+  input wb_we_i,
+  input wb_cyc_i,
+  input wb_stb_i,
+
+  output wb_ack_o,
+  output [31:0] wb_dat_o
+);
+
+  localparam ADR_WIDTH = $clog2(MEM_WORDS);
+
+  wire valid;
+  wire ram_wen;
+  wire [3:0] wen; // write enable
+
+  assign valid = wb_cyc_i & wb_stb_i;
+  assign ram_wen = wb_we_i && valid;
+
+  assign wen = wb_sel_i & {4{ram_wen}} ;
+
+  /*
+      Ack Generation
+          - write transaction: asserted upon receiving adr_i & dat_i
+          - read transaction : asserted one clock cycle after receiving the adr_i & dat_i
+  */
+
+  reg wb_ack_read;
+  reg wb_ack_o;
+
+  always @(posedge wb_clk_i) begin
+    if (wb_rst_i == 1'b 1) begin
+      wb_ack_read <= 1'b0;
+      wb_ack_o <= 1'b0;
+    end else begin
+      // wb_ack_read <= {2{valid}} & {1'b1, wb_ack_read[1]};
+      wb_ack_o    <= wb_we_i? (valid & !wb_ack_o): wb_ack_read;
+      wb_ack_read <= (valid & !wb_ack_o) & !wb_ack_read;
+    end
+  end
+
+  ff32_ram #(
+    .ADDR_WIDTH(ADR_WIDTH)
+  ) ram (
+    .clk(wb_clk_i),
+
+    .addr(wb_adr_i[ADR_WIDTH+1:2]),
+    .din(wb_dat_i),
+    .dout(wb_dat_o),
+
+    .en(valid),
+    .wmask(wen)
+  );
+endmodule
+`default_nettype wire
+
+// Single port 32-bit inferred RAM.
+module ff32_ram #(
+  parameter ADDR_WIDTH = 8
+)(
+  input clk,
+
+  input [ADDR_WIDTH-1:0] addr,
+  input [31:0] din,
+  output reg [31:0] dout,
+
+  input en,
+  input [3:0] wmask
+);
+  reg [7:0] ram0 [(1<<ADDR_WIDTH)-1:0];
+  reg [7:0] ram1 [(1<<ADDR_WIDTH)-1:0];
+  reg [7:0] ram2 [(1<<ADDR_WIDTH)-1:0];
+  reg [7:0] ram3 [(1<<ADDR_WIDTH)-1:0];
+
+`ifdef SIM
+  integer i;
+  initial begin
+    for (i = 0; i < (1<<ADDR_WIDTH); i = i + 1) begin
+      ram0[i] = 8'b0;
+      ram1[i] = 8'b0;
+      ram2[i] = 8'b0;
+      ram3[i] = 8'b0;
+    end
+  end
+`endif
+
+  // Write.
+  always @(posedge clk) begin
+    if (en) begin
+      if (wmask[0])
+        ram0[addr] <= din[7:0];
+      if (wmask[1])
+        ram1[addr] <= din[15:8];
+      if (wmask[2])
+        ram2[addr] <= din[23:16];
+      if (wmask[3])
+        ram3[addr] <= din[31:24];
+    end
+  end
+
+  // Read.
+  always @(posedge clk) begin
+    if (en) begin
+      dout[7:0] <= ram0[addr];
+      dout[15:8] <= ram1[addr];
+      dout[23:16] <= ram2[addr];
+      dout[31:24] <= ram3[addr];
+    end
+  end
+endmodule // module ff32_ram
diff --git a/verilog/rtl/softshell/third_party/picorv32_wb/mem_wb.v b/verilog/rtl/softshell/third_party/picorv32_wb/mem_wb.v
new file mode 100644
index 0000000..06fb2f0
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32_wb/mem_wb.v
@@ -0,0 +1,126 @@
+`default_nettype none
+module mem_wb (
+`ifdef USE_POWER_PINS
+    input VPWR,
+    input VGND,
+`endif
+    input wb_clk_i,
+    input wb_rst_i,
+
+    input [31:0] wb_adr_i,
+    input [31:0] wb_dat_i,
+    input [3:0] wb_sel_i,
+    input wb_we_i,
+    input wb_cyc_i,
+    input wb_stb_i,
+
+    output wb_ack_o,
+    output [31:0] wb_dat_o
+
+);
+
+    localparam ADR_WIDTH = $clog2(`MEM_WORDS);
+
+    wire valid;
+    wire ram_wen;
+    wire [3:0] wen; // write enable
+
+    assign valid = wb_cyc_i & wb_stb_i;
+    assign ram_wen = wb_we_i && valid;
+
+    assign wen = wb_sel_i & {4{ram_wen}} ;
+
+    /*
+        Ack Generation
+            - write transaction: asserted upon receiving adr_i & dat_i
+            - read transaction : asserted one clock cycle after receiving the adr_i & dat_i
+    */
+
+    reg wb_ack_read;
+    reg wb_ack_o;
+
+    always @(posedge wb_clk_i) begin
+        if (wb_rst_i == 1'b 1) begin
+            wb_ack_read <= 1'b0;
+            wb_ack_o <= 1'b0;
+        end else begin
+            // wb_ack_read <= {2{valid}} & {1'b1, wb_ack_read[1]};
+            wb_ack_o    <= wb_we_i? (valid & !wb_ack_o): wb_ack_read;
+            wb_ack_read <= (valid & !wb_ack_o) & !wb_ack_read;
+        end
+    end
+
+    soc_mem
+`ifndef USE_OPENRAM
+    #(
+        .WORDS(`MEM_WORDS),
+        .ADR_WIDTH(ADR_WIDTH)
+    )
+`endif
+     mem (
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+    `endif
+        .clk(wb_clk_i),
+        .ena(valid),
+        .wen(wen),
+        .addr(wb_adr_i[ADR_WIDTH+1:2]),
+        .wdata(wb_dat_i),
+        .rdata(wb_dat_o)
+    );
+
+endmodule
+
+module soc_mem
+#(
+`ifndef USE_OPENRAM
+    parameter integer WORDS = 256,
+`endif
+    parameter ADR_WIDTH = 8
+)
+ (
+`ifdef USE_POWER_PINS
+    input VPWR,
+    input VGND,
+`endif
+    input clk,
+    input ena,
+    input [3:0] wen,
+    input [ADR_WIDTH-1:0] addr,
+    input [31:0] wdata,
+    output[31:0] rdata
+);
+
+`ifndef USE_OPENRAM
+    DFFRAM #(.COLS(`COLS)) SRAM (
+    `ifdef USE_POWER_PINS
+        .VPWR(VPWR),
+        .VGND(VGND),
+    `endif
+        .CLK(clk),
+        .WE(wen),
+        .EN(ena),
+        .Di(wdata),
+        .Do(rdata),
+        // 8-bit address if using the default custom DFF RAM
+        .A(addr)
+    );
+`else
+
+    /* Using Port 0 Only - Size: 1KB, 256x32 bits */
+    //sram_1rw1r_32_256_8_scn4m_subm
+    sram_1rw1r_32_256_8_sky130 SRAM(
+            .clk0(clk),
+            .csb0(~ena),
+            .web0(~|wen),
+            .wmask0(wen),
+            .addr0(addr[7:0]),
+            .din0(wdata),
+            .dout0(rdata)
+      );
+
+`endif
+
+endmodule
+`default_nettype wire
diff --git a/verilog/rtl/softshell/third_party/picorv32_wb/picorv32.v b/verilog/rtl/softshell/third_party/picorv32_wb/picorv32.v
new file mode 100644
index 0000000..17969b5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32_wb/picorv32.v
@@ -0,0 +1,3046 @@
+`default_nettype none
+/*
+ *  PicoRV32 -- A Small RISC-V (RV32I) Processor Core
+ *
+ *  Copyright (C) 2015  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/* verilator lint_off WIDTH */
+/* verilator lint_off PINMISSING */
+/* verilator lint_off CASEOVERLAP */
+/* verilator lint_off CASEINCOMPLETE */
+
+`timescale 1 ns / 1 ps
+// `define DEBUGNETS
+// `define DEBUGREGS
+// `define DEBUGASM
+// `define DEBUG
+
+`ifdef DEBUG
+  `define debug(debug_command) debug_command
+`else
+  `define debug(debug_command)
+`endif
+
+`ifdef FORMAL
+  `define FORMAL_KEEP (* keep *)
+  `define assert(assert_expr) assert(assert_expr)
+`else
+  `ifdef DEBUGNETS
+    `define FORMAL_KEEP (* keep *)
+  `else
+    `define FORMAL_KEEP
+  `endif
+  `define assert(assert_expr) empty_statement
+`endif
+
+// uncomment this for register file in extra module
+// `define PICORV32_REGS picorv32_regs
+
+// this macro can be used to check if the verilog files in your
+// design are read in the correct order.
+`define PICORV32_V
+
+
+/***************************************************************
+ * picorv32
+ ***************************************************************/
+
+module picorv32 #(
+	parameter [ 0:0] ENABLE_COUNTERS = 1,
+	parameter [ 0:0] ENABLE_COUNTERS64 = 1,
+	parameter [ 0:0] ENABLE_REGS_16_31 = 1,
+	parameter [ 0:0] ENABLE_REGS_DUALPORT = 1,
+	parameter [ 0:0] LATCHED_MEM_RDATA = 0,
+	parameter [ 0:0] TWO_STAGE_SHIFT = 1,
+	parameter [ 0:0] BARREL_SHIFTER = 0,
+	parameter [ 0:0] TWO_CYCLE_COMPARE = 0,
+	parameter [ 0:0] TWO_CYCLE_ALU = 0,
+	parameter [ 0:0] COMPRESSED_ISA = 0,
+	parameter [ 0:0] CATCH_MISALIGN = 1,
+	parameter [ 0:0] CATCH_ILLINSN = 1,
+	parameter [ 0:0] ENABLE_PCPI = 0,
+	parameter [ 0:0] ENABLE_MUL = 0,
+	parameter [ 0:0] ENABLE_FAST_MUL = 0,
+	parameter [ 0:0] ENABLE_DIV = 0,
+	parameter [ 0:0] ENABLE_IRQ = 0,
+	parameter [ 0:0] ENABLE_IRQ_QREGS = 1,
+	parameter [ 0:0] ENABLE_IRQ_TIMER = 1,
+	parameter [ 0:0] ENABLE_TRACE = 0,
+	parameter [ 0:0] REGS_INIT_ZERO = 0,
+	parameter [31:0] MASKED_IRQ = 32'h 0000_0000,
+	parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff,
+	parameter [31:0] PROGADDR_RESET = 32'h 0000_0000,
+	parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010,
+	parameter [31:0] STACKADDR = 32'h ffff_ffff
+) (
+	input clk, resetn,
+	output reg trap,
+
+	output reg        mem_valid,
+	output reg        mem_instr,
+	input             mem_ready,
+
+	output reg [31:0] mem_addr,
+	output reg [31:0] mem_wdata,
+	output reg [ 3:0] mem_wstrb,
+	input      [31:0] mem_rdata,
+
+	// Look-Ahead Interface
+	output            mem_la_read,
+	output            mem_la_write,
+	output     [31:0] mem_la_addr,
+	output reg [31:0] mem_la_wdata,
+	output reg [ 3:0] mem_la_wstrb,
+
+	// Pico Co-Processor Interface (PCPI)
+	output reg        pcpi_valid,
+	output reg [31:0] pcpi_insn,
+	output     [31:0] pcpi_rs1,
+	output     [31:0] pcpi_rs2,
+	input             pcpi_wr,
+	input      [31:0] pcpi_rd,
+	input             pcpi_wait,
+	input             pcpi_ready,
+
+	// IRQ Interface
+	input      [31:0] irq,
+	output reg [31:0] eoi,
+
+`ifdef RISCV_FORMAL
+	output reg        rvfi_valid,
+	output reg [63:0] rvfi_order,
+	output reg [31:0] rvfi_insn,
+	output reg        rvfi_trap,
+	output reg        rvfi_halt,
+	output reg        rvfi_intr,
+	output reg [ 1:0] rvfi_mode,
+	output reg [ 1:0] rvfi_ixl,
+	output reg [ 4:0] rvfi_rs1_addr,
+	output reg [ 4:0] rvfi_rs2_addr,
+	output reg [31:0] rvfi_rs1_rdata,
+	output reg [31:0] rvfi_rs2_rdata,
+	output reg [ 4:0] rvfi_rd_addr,
+	output reg [31:0] rvfi_rd_wdata,
+	output reg [31:0] rvfi_pc_rdata,
+	output reg [31:0] rvfi_pc_wdata,
+	output reg [31:0] rvfi_mem_addr,
+	output reg [ 3:0] rvfi_mem_rmask,
+	output reg [ 3:0] rvfi_mem_wmask,
+	output reg [31:0] rvfi_mem_rdata,
+	output reg [31:0] rvfi_mem_wdata,
+
+	output reg [63:0] rvfi_csr_mcycle_rmask,
+	output reg [63:0] rvfi_csr_mcycle_wmask,
+	output reg [63:0] rvfi_csr_mcycle_rdata,
+	output reg [63:0] rvfi_csr_mcycle_wdata,
+
+	output reg [63:0] rvfi_csr_minstret_rmask,
+	output reg [63:0] rvfi_csr_minstret_wmask,
+	output reg [63:0] rvfi_csr_minstret_rdata,
+	output reg [63:0] rvfi_csr_minstret_wdata,
+`endif
+
+	// Trace Interface
+	output reg        trace_valid,
+	output reg [35:0] trace_data
+);
+	localparam integer irq_timer = 0;
+	localparam integer irq_ebreak = 1;
+	localparam integer irq_buserror = 2;
+
+	localparam integer irqregs_offset = ENABLE_REGS_16_31 ? 32 : 16;
+	localparam integer regfile_size = (ENABLE_REGS_16_31 ? 32 : 16) + 4*ENABLE_IRQ*ENABLE_IRQ_QREGS;
+	localparam integer regindex_bits = (ENABLE_REGS_16_31 ? 5 : 4) + ENABLE_IRQ*ENABLE_IRQ_QREGS;
+
+	localparam WITH_PCPI = ENABLE_PCPI || ENABLE_MUL || ENABLE_FAST_MUL || ENABLE_DIV;
+
+	localparam [35:0] TRACE_BRANCH = {4'b 0001, 32'b 0};
+	localparam [35:0] TRACE_ADDR   = {4'b 0010, 32'b 0};
+	localparam [35:0] TRACE_IRQ    = {4'b 1000, 32'b 0};
+
+	reg [63:0] count_cycle, count_instr;
+	reg [31:0] reg_pc, reg_next_pc, reg_op1, reg_op2, reg_out;
+	reg [4:0] reg_sh;
+
+	reg [31:0] next_insn_opcode;
+	reg [31:0] dbg_insn_opcode;
+	reg [31:0] dbg_insn_addr;
+
+	wire dbg_mem_valid = mem_valid;
+	wire dbg_mem_instr = mem_instr;
+	wire dbg_mem_ready = mem_ready;
+	wire [31:0] dbg_mem_addr  = mem_addr;
+	wire [31:0] dbg_mem_wdata = mem_wdata;
+	wire [ 3:0] dbg_mem_wstrb = mem_wstrb;
+	wire [31:0] dbg_mem_rdata = mem_rdata;
+
+	assign pcpi_rs1 = reg_op1;
+	assign pcpi_rs2 = reg_op2;
+
+	wire [31:0] next_pc;
+
+	reg irq_delay;
+	reg irq_active;
+	reg [31:0] irq_mask;
+	reg [31:0] irq_pending;
+	reg [31:0] timer;
+
+`ifndef PICORV32_REGS
+	reg [31:0] cpuregs [0:regfile_size-1];
+
+	integer i;
+	initial begin
+		if (REGS_INIT_ZERO) begin
+			for (i = 0; i < regfile_size; i = i+1)
+				cpuregs[i] = 0;
+		end
+	end
+`endif
+
+	task empty_statement;
+		// This task is used by the `assert directive in non-formal mode to
+		// avoid empty statement (which are unsupported by plain Verilog syntax).
+		begin end
+	endtask
+
+`ifdef DEBUGREGS
+	wire [31:0] dbg_reg_x0  = 0;
+	wire [31:0] dbg_reg_x1  = cpuregs[1];
+	wire [31:0] dbg_reg_x2  = cpuregs[2];
+	wire [31:0] dbg_reg_x3  = cpuregs[3];
+	wire [31:0] dbg_reg_x4  = cpuregs[4];
+	wire [31:0] dbg_reg_x5  = cpuregs[5];
+	wire [31:0] dbg_reg_x6  = cpuregs[6];
+	wire [31:0] dbg_reg_x7  = cpuregs[7];
+	wire [31:0] dbg_reg_x8  = cpuregs[8];
+	wire [31:0] dbg_reg_x9  = cpuregs[9];
+	wire [31:0] dbg_reg_x10 = cpuregs[10];
+	wire [31:0] dbg_reg_x11 = cpuregs[11];
+	wire [31:0] dbg_reg_x12 = cpuregs[12];
+	wire [31:0] dbg_reg_x13 = cpuregs[13];
+	wire [31:0] dbg_reg_x14 = cpuregs[14];
+	wire [31:0] dbg_reg_x15 = cpuregs[15];
+	wire [31:0] dbg_reg_x16 = cpuregs[16];
+	wire [31:0] dbg_reg_x17 = cpuregs[17];
+	wire [31:0] dbg_reg_x18 = cpuregs[18];
+	wire [31:0] dbg_reg_x19 = cpuregs[19];
+	wire [31:0] dbg_reg_x20 = cpuregs[20];
+	wire [31:0] dbg_reg_x21 = cpuregs[21];
+	wire [31:0] dbg_reg_x22 = cpuregs[22];
+	wire [31:0] dbg_reg_x23 = cpuregs[23];
+	wire [31:0] dbg_reg_x24 = cpuregs[24];
+	wire [31:0] dbg_reg_x25 = cpuregs[25];
+	wire [31:0] dbg_reg_x26 = cpuregs[26];
+	wire [31:0] dbg_reg_x27 = cpuregs[27];
+	wire [31:0] dbg_reg_x28 = cpuregs[28];
+	wire [31:0] dbg_reg_x29 = cpuregs[29];
+	wire [31:0] dbg_reg_x30 = cpuregs[30];
+	wire [31:0] dbg_reg_x31 = cpuregs[31];
+`endif
+
+	// Internal PCPI Cores
+
+	wire        pcpi_mul_wr;
+	wire [31:0] pcpi_mul_rd;
+	wire        pcpi_mul_wait;
+	wire        pcpi_mul_ready;
+
+	wire        pcpi_div_wr;
+	wire [31:0] pcpi_div_rd;
+	wire        pcpi_div_wait;
+	wire        pcpi_div_ready;
+
+	reg        pcpi_int_wr;
+	reg [31:0] pcpi_int_rd;
+	reg        pcpi_int_wait;
+	reg        pcpi_int_ready;
+
+	generate if (ENABLE_FAST_MUL) begin
+		picorv32_pcpi_fast_mul pcpi_mul (
+			.clk       (clk            ),
+			.resetn    (resetn         ),
+			.pcpi_valid(pcpi_valid     ),
+			.pcpi_insn (pcpi_insn      ),
+			.pcpi_rs1  (pcpi_rs1       ),
+			.pcpi_rs2  (pcpi_rs2       ),
+			.pcpi_wr   (pcpi_mul_wr    ),
+			.pcpi_rd   (pcpi_mul_rd    ),
+			.pcpi_wait (pcpi_mul_wait  ),
+			.pcpi_ready(pcpi_mul_ready )
+		);
+	end else if (ENABLE_MUL) begin
+		picorv32_pcpi_mul pcpi_mul (
+			.clk       (clk            ),
+			.resetn    (resetn         ),
+			.pcpi_valid(pcpi_valid     ),
+			.pcpi_insn (pcpi_insn      ),
+			.pcpi_rs1  (pcpi_rs1       ),
+			.pcpi_rs2  (pcpi_rs2       ),
+			.pcpi_wr   (pcpi_mul_wr    ),
+			.pcpi_rd   (pcpi_mul_rd    ),
+			.pcpi_wait (pcpi_mul_wait  ),
+			.pcpi_ready(pcpi_mul_ready )
+		);
+	end else begin
+		assign pcpi_mul_wr = 0;
+		assign pcpi_mul_rd = 32'bx;
+		assign pcpi_mul_wait = 0;
+		assign pcpi_mul_ready = 0;
+	end endgenerate
+
+	generate if (ENABLE_DIV) begin
+		picorv32_pcpi_div pcpi_div (
+			.clk       (clk            ),
+			.resetn    (resetn         ),
+			.pcpi_valid(pcpi_valid     ),
+			.pcpi_insn (pcpi_insn      ),
+			.pcpi_rs1  (pcpi_rs1       ),
+			.pcpi_rs2  (pcpi_rs2       ),
+			.pcpi_wr   (pcpi_div_wr    ),
+			.pcpi_rd   (pcpi_div_rd    ),
+			.pcpi_wait (pcpi_div_wait  ),
+			.pcpi_ready(pcpi_div_ready )
+		);
+	end else begin
+		assign pcpi_div_wr = 0;
+		assign pcpi_div_rd = 32'bx;
+		assign pcpi_div_wait = 0;
+		assign pcpi_div_ready = 0;
+	end endgenerate
+
+	always @* begin
+		pcpi_int_wr = 0;
+		pcpi_int_rd = 32'bx;
+		pcpi_int_wait  = |{ENABLE_PCPI && pcpi_wait,  (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_wait,  ENABLE_DIV && pcpi_div_wait};
+		pcpi_int_ready = |{ENABLE_PCPI && pcpi_ready, (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_ready, ENABLE_DIV && pcpi_div_ready};
+
+		(* parallel_case *)
+		case (1'b1)
+			ENABLE_PCPI && pcpi_ready: begin
+				pcpi_int_wr = ENABLE_PCPI ? pcpi_wr : 0;
+				pcpi_int_rd = ENABLE_PCPI ? pcpi_rd : 0;
+			end
+			(ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_ready: begin
+				pcpi_int_wr = pcpi_mul_wr;
+				pcpi_int_rd = pcpi_mul_rd;
+			end
+			ENABLE_DIV && pcpi_div_ready: begin
+				pcpi_int_wr = pcpi_div_wr;
+				pcpi_int_rd = pcpi_div_rd;
+			end
+		endcase
+	end
+
+
+	// Memory Interface
+
+	reg [1:0] mem_state;
+	reg [1:0] mem_wordsize;
+	reg [31:0] mem_rdata_word;
+	reg [31:0] mem_rdata_q;
+	reg mem_do_prefetch;
+	reg mem_do_rinst;
+	reg mem_do_rdata;
+	reg mem_do_wdata;
+
+	wire mem_xfer;
+	reg mem_la_secondword, mem_la_firstword_reg, last_mem_valid;
+	wire mem_la_firstword = COMPRESSED_ISA && (mem_do_prefetch || mem_do_rinst) && next_pc[1] && !mem_la_secondword;
+	wire mem_la_firstword_xfer = COMPRESSED_ISA && mem_xfer && (!last_mem_valid ? mem_la_firstword : mem_la_firstword_reg);
+
+	reg prefetched_high_word;
+	reg clear_prefetched_high_word;
+	reg [15:0] mem_16bit_buffer;
+
+	wire [31:0] mem_rdata_latched_noshuffle;
+	wire [31:0] mem_rdata_latched;
+
+	wire mem_la_use_prefetched_high_word = COMPRESSED_ISA && mem_la_firstword && prefetched_high_word && !clear_prefetched_high_word;
+	assign mem_xfer = (mem_valid && mem_ready) || (mem_la_use_prefetched_high_word && mem_do_rinst);
+
+	wire mem_busy = |{mem_do_prefetch, mem_do_rinst, mem_do_rdata, mem_do_wdata};
+	wire mem_done = resetn && ((mem_xfer && |mem_state && (mem_do_rinst || mem_do_rdata || mem_do_wdata)) || (&mem_state && mem_do_rinst)) &&
+			(!mem_la_firstword || (~&mem_rdata_latched[1:0] && mem_xfer));
+
+	assign mem_la_write = resetn && !mem_state && mem_do_wdata;
+	assign mem_la_read = resetn && ((!mem_la_use_prefetched_high_word && !mem_state && (mem_do_rinst || mem_do_prefetch || mem_do_rdata)) ||
+			(COMPRESSED_ISA && mem_xfer && (!last_mem_valid ? mem_la_firstword : mem_la_firstword_reg) && !mem_la_secondword && &mem_rdata_latched[1:0]));
+	assign mem_la_addr = (mem_do_prefetch || mem_do_rinst) ? {next_pc[31:2] + mem_la_firstword_xfer, 2'b00} : {reg_op1[31:2], 2'b00};
+
+	assign mem_rdata_latched_noshuffle = (mem_xfer || LATCHED_MEM_RDATA) ? mem_rdata : mem_rdata_q;
+
+	assign mem_rdata_latched = COMPRESSED_ISA && mem_la_use_prefetched_high_word ? {16'bx, mem_16bit_buffer} :
+			COMPRESSED_ISA && mem_la_secondword ? {mem_rdata_latched_noshuffle[15:0], mem_16bit_buffer} :
+			COMPRESSED_ISA && mem_la_firstword ? {16'bx, mem_rdata_latched_noshuffle[31:16]} : mem_rdata_latched_noshuffle;
+
+	always @(posedge clk) begin
+		if (!resetn) begin
+			mem_la_firstword_reg <= 0;
+			last_mem_valid <= 0;
+		end else begin
+			if (!last_mem_valid)
+				mem_la_firstword_reg <= mem_la_firstword;
+			last_mem_valid <= mem_valid && !mem_ready;
+		end
+	end
+
+	always @* begin
+		(* full_case *)
+		case (mem_wordsize)
+			0: begin
+				mem_la_wdata = reg_op2;
+				mem_la_wstrb = 4'b1111;
+				mem_rdata_word = mem_rdata;
+			end
+			1: begin
+				mem_la_wdata = {2{reg_op2[15:0]}};
+				mem_la_wstrb = reg_op1[1] ? 4'b1100 : 4'b0011;
+				case (reg_op1[1])
+					1'b0: mem_rdata_word = {16'b0, mem_rdata[15: 0]};
+					1'b1: mem_rdata_word = {16'b0, mem_rdata[31:16]};
+				endcase
+			end
+			2: begin
+				mem_la_wdata = {4{reg_op2[7:0]}};
+				mem_la_wstrb = 4'b0001 << reg_op1[1:0];
+				case (reg_op1[1:0])
+					2'b00: mem_rdata_word = {24'b0, mem_rdata[ 7: 0]};
+					2'b01: mem_rdata_word = {24'b0, mem_rdata[15: 8]};
+					2'b10: mem_rdata_word = {24'b0, mem_rdata[23:16]};
+					2'b11: mem_rdata_word = {24'b0, mem_rdata[31:24]};
+				endcase
+			end
+		endcase
+	end
+
+	always @(posedge clk) begin
+		if (mem_xfer) begin
+			mem_rdata_q <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata;
+			next_insn_opcode <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata;
+		end
+
+		if (COMPRESSED_ISA && mem_done && (mem_do_prefetch || mem_do_rinst)) begin
+			case (mem_rdata_latched[1:0])
+				2'b00: begin // Quadrant 0
+					case (mem_rdata_latched[15:13])
+						3'b000: begin // C.ADDI4SPN
+							mem_rdata_q[14:12] <= 3'b000;
+							mem_rdata_q[31:20] <= {2'b0, mem_rdata_latched[10:7], mem_rdata_latched[12:11], mem_rdata_latched[5], mem_rdata_latched[6], 2'b00};
+						end
+						3'b010: begin // C.LW
+							mem_rdata_q[31:20] <= {5'b0, mem_rdata_latched[5], mem_rdata_latched[12:10], mem_rdata_latched[6], 2'b00};
+							mem_rdata_q[14:12] <= 3'b 010;
+						end
+						3'b 110: begin // C.SW
+							{mem_rdata_q[31:25], mem_rdata_q[11:7]} <= {5'b0, mem_rdata_latched[5], mem_rdata_latched[12:10], mem_rdata_latched[6], 2'b00};
+							mem_rdata_q[14:12] <= 3'b 010;
+						end
+					endcase
+				end
+				2'b01: begin // Quadrant 1
+					case (mem_rdata_latched[15:13])
+						3'b 000: begin // C.ADDI
+							mem_rdata_q[14:12] <= 3'b000;
+							mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]});
+						end
+						3'b 010: begin // C.LI
+							mem_rdata_q[14:12] <= 3'b000;
+							mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]});
+						end
+						3'b 011: begin
+							if (mem_rdata_latched[11:7] == 2) begin // C.ADDI16SP
+								mem_rdata_q[14:12] <= 3'b000;
+								mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[4:3],
+										mem_rdata_latched[5], mem_rdata_latched[2], mem_rdata_latched[6], 4'b 0000});
+							end else begin // C.LUI
+								mem_rdata_q[31:12] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]});
+							end
+						end
+						3'b100: begin
+							if (mem_rdata_latched[11:10] == 2'b00) begin // C.SRLI
+								mem_rdata_q[31:25] <= 7'b0000000;
+								mem_rdata_q[14:12] <= 3'b 101;
+							end
+							if (mem_rdata_latched[11:10] == 2'b01) begin // C.SRAI
+								mem_rdata_q[31:25] <= 7'b0100000;
+								mem_rdata_q[14:12] <= 3'b 101;
+							end
+							if (mem_rdata_latched[11:10] == 2'b10) begin // C.ANDI
+								mem_rdata_q[14:12] <= 3'b111;
+								mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]});
+							end
+							if (mem_rdata_latched[12:10] == 3'b011) begin // C.SUB, C.XOR, C.OR, C.AND
+								if (mem_rdata_latched[6:5] == 2'b00) mem_rdata_q[14:12] <= 3'b000;
+								if (mem_rdata_latched[6:5] == 2'b01) mem_rdata_q[14:12] <= 3'b100;
+								if (mem_rdata_latched[6:5] == 2'b10) mem_rdata_q[14:12] <= 3'b110;
+								if (mem_rdata_latched[6:5] == 2'b11) mem_rdata_q[14:12] <= 3'b111;
+								mem_rdata_q[31:25] <= mem_rdata_latched[6:5] == 2'b00 ? 7'b0100000 : 7'b0000000;
+							end
+						end
+						3'b 110: begin // C.BEQZ
+							mem_rdata_q[14:12] <= 3'b000;
+							{ mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8] } <=
+									$signed({mem_rdata_latched[12], mem_rdata_latched[6:5], mem_rdata_latched[2],
+											mem_rdata_latched[11:10], mem_rdata_latched[4:3]});
+						end
+						3'b 111: begin // C.BNEZ
+							mem_rdata_q[14:12] <= 3'b001;
+							{ mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8] } <=
+									$signed({mem_rdata_latched[12], mem_rdata_latched[6:5], mem_rdata_latched[2],
+											mem_rdata_latched[11:10], mem_rdata_latched[4:3]});
+						end
+					endcase
+				end
+				2'b10: begin // Quadrant 2
+					case (mem_rdata_latched[15:13])
+						3'b000: begin // C.SLLI
+							mem_rdata_q[31:25] <= 7'b0000000;
+							mem_rdata_q[14:12] <= 3'b 001;
+						end
+						3'b010: begin // C.LWSP
+							mem_rdata_q[31:20] <= {4'b0, mem_rdata_latched[3:2], mem_rdata_latched[12], mem_rdata_latched[6:4], 2'b00};
+							mem_rdata_q[14:12] <= 3'b 010;
+						end
+						3'b100: begin
+							if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] == 0) begin // C.JR
+								mem_rdata_q[14:12] <= 3'b000;
+								mem_rdata_q[31:20] <= 12'b0;
+							end
+							if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] != 0) begin // C.MV
+								mem_rdata_q[14:12] <= 3'b000;
+								mem_rdata_q[31:25] <= 7'b0000000;
+							end
+							if (mem_rdata_latched[12] != 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JALR
+								mem_rdata_q[14:12] <= 3'b000;
+								mem_rdata_q[31:20] <= 12'b0;
+							end
+							if (mem_rdata_latched[12] != 0 && mem_rdata_latched[6:2] != 0) begin // C.ADD
+								mem_rdata_q[14:12] <= 3'b000;
+								mem_rdata_q[31:25] <= 7'b0000000;
+							end
+						end
+						3'b110: begin // C.SWSP
+							{mem_rdata_q[31:25], mem_rdata_q[11:7]} <= {4'b0, mem_rdata_latched[8:7], mem_rdata_latched[12:9], 2'b00};
+							mem_rdata_q[14:12] <= 3'b 010;
+						end
+					endcase
+				end
+			endcase
+		end
+	end
+
+	always @(posedge clk) begin
+		if (resetn && !trap) begin
+			if (mem_do_prefetch || mem_do_rinst || mem_do_rdata)
+				`assert(!mem_do_wdata);
+
+			if (mem_do_prefetch || mem_do_rinst)
+				`assert(!mem_do_rdata);
+
+			if (mem_do_rdata)
+				`assert(!mem_do_prefetch && !mem_do_rinst);
+
+			if (mem_do_wdata)
+				`assert(!(mem_do_prefetch || mem_do_rinst || mem_do_rdata));
+
+			if (mem_state == 2 || mem_state == 3)
+				`assert(mem_valid || mem_do_prefetch);
+		end
+	end
+
+	always @(posedge clk) begin
+		if (!resetn || trap) begin
+			if (!resetn)
+				mem_state <= 0;
+			if (!resetn || mem_ready)
+				mem_valid <= 0;
+			mem_la_secondword <= 0;
+			prefetched_high_word <= 0;
+		end else begin
+			if (mem_la_read || mem_la_write) begin
+				mem_addr <= mem_la_addr;
+				mem_wstrb <= mem_la_wstrb & {4{mem_la_write}};
+			end
+			if (mem_la_write) begin
+				mem_wdata <= mem_la_wdata;
+			end
+			case (mem_state)
+				0: begin
+					if (mem_do_prefetch || mem_do_rinst || mem_do_rdata) begin
+						mem_valid <= !mem_la_use_prefetched_high_word;
+						mem_instr <= mem_do_prefetch || mem_do_rinst;
+						mem_wstrb <= 0;
+						mem_state <= 1;
+					end
+					if (mem_do_wdata) begin
+						mem_valid <= 1;
+						mem_instr <= 0;
+						mem_state <= 2;
+					end
+				end
+				1: begin
+					`assert(mem_wstrb == 0);
+					`assert(mem_do_prefetch || mem_do_rinst || mem_do_rdata);
+					`assert(mem_valid == !mem_la_use_prefetched_high_word);
+					`assert(mem_instr == (mem_do_prefetch || mem_do_rinst));
+					if (mem_xfer) begin
+						if (COMPRESSED_ISA && mem_la_read) begin
+							mem_valid <= 1;
+							mem_la_secondword <= 1;
+							if (!mem_la_use_prefetched_high_word)
+								mem_16bit_buffer <= mem_rdata[31:16];
+						end else begin
+							mem_valid <= 0;
+							mem_la_secondword <= 0;
+							if (COMPRESSED_ISA && !mem_do_rdata) begin
+								if (~&mem_rdata[1:0] || mem_la_secondword) begin
+									mem_16bit_buffer <= mem_rdata[31:16];
+									prefetched_high_word <= 1;
+								end else begin
+									prefetched_high_word <= 0;
+								end
+							end
+							mem_state <= mem_do_rinst || mem_do_rdata ? 0 : 3;
+						end
+					end
+				end
+				2: begin
+					`assert(mem_wstrb != 0);
+					`assert(mem_do_wdata);
+					if (mem_xfer) begin
+						mem_valid <= 0;
+						mem_state <= 0;
+					end
+				end
+				3: begin
+					`assert(mem_wstrb == 0);
+					`assert(mem_do_prefetch);
+					if (mem_do_rinst) begin
+						mem_state <= 0;
+					end
+				end
+			endcase
+		end
+
+		if (clear_prefetched_high_word)
+			prefetched_high_word <= 0;
+	end
+
+
+	// Instruction Decoder
+
+	reg instr_lui, instr_auipc, instr_jal, instr_jalr;
+	reg instr_beq, instr_bne, instr_blt, instr_bge, instr_bltu, instr_bgeu;
+	reg instr_lb, instr_lh, instr_lw, instr_lbu, instr_lhu, instr_sb, instr_sh, instr_sw;
+	reg instr_addi, instr_slti, instr_sltiu, instr_xori, instr_ori, instr_andi, instr_slli, instr_srli, instr_srai;
+	reg instr_add, instr_sub, instr_sll, instr_slt, instr_sltu, instr_xor, instr_srl, instr_sra, instr_or, instr_and;
+	reg instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh, instr_ecall_ebreak;
+	reg instr_getq, instr_setq, instr_retirq, instr_maskirq, instr_waitirq, instr_timer;
+	wire instr_trap;
+
+	reg [regindex_bits-1:0] decoded_rd, decoded_rs1, decoded_rs2;
+	reg [31:0] decoded_imm, decoded_imm_j;
+	reg decoder_trigger;
+	reg decoder_trigger_q;
+	reg decoder_pseudo_trigger;
+	reg decoder_pseudo_trigger_q;
+	reg compressed_instr;
+
+	reg is_lui_auipc_jal;
+	reg is_lb_lh_lw_lbu_lhu;
+	reg is_slli_srli_srai;
+	reg is_jalr_addi_slti_sltiu_xori_ori_andi;
+	reg is_sb_sh_sw;
+	reg is_sll_srl_sra;
+	reg is_lui_auipc_jal_jalr_addi_add_sub;
+	reg is_slti_blt_slt;
+	reg is_sltiu_bltu_sltu;
+	reg is_beq_bne_blt_bge_bltu_bgeu;
+	reg is_lbu_lhu_lw;
+	reg is_alu_reg_imm;
+	reg is_alu_reg_reg;
+	reg is_compare;
+
+	assign instr_trap = (CATCH_ILLINSN || WITH_PCPI) && !{instr_lui, instr_auipc, instr_jal, instr_jalr,
+			instr_beq, instr_bne, instr_blt, instr_bge, instr_bltu, instr_bgeu,
+			instr_lb, instr_lh, instr_lw, instr_lbu, instr_lhu, instr_sb, instr_sh, instr_sw,
+			instr_addi, instr_slti, instr_sltiu, instr_xori, instr_ori, instr_andi, instr_slli, instr_srli, instr_srai,
+			instr_add, instr_sub, instr_sll, instr_slt, instr_sltu, instr_xor, instr_srl, instr_sra, instr_or, instr_and,
+			instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh,
+			instr_getq, instr_setq, instr_retirq, instr_maskirq, instr_waitirq, instr_timer};
+
+	wire is_rdcycle_rdcycleh_rdinstr_rdinstrh;
+	assign is_rdcycle_rdcycleh_rdinstr_rdinstrh = |{instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh};
+
+	reg [63:0] new_ascii_instr;
+	`FORMAL_KEEP reg [63:0] dbg_ascii_instr;
+	`FORMAL_KEEP reg [31:0] dbg_insn_imm;
+	`FORMAL_KEEP reg [4:0] dbg_insn_rs1;
+	`FORMAL_KEEP reg [4:0] dbg_insn_rs2;
+	`FORMAL_KEEP reg [4:0] dbg_insn_rd;
+	`FORMAL_KEEP reg [31:0] dbg_rs1val;
+	`FORMAL_KEEP reg [31:0] dbg_rs2val;
+	`FORMAL_KEEP reg dbg_rs1val_valid;
+	`FORMAL_KEEP reg dbg_rs2val_valid;
+
+	always @* begin
+		new_ascii_instr = "";
+
+		if (instr_lui)      new_ascii_instr = "lui";
+		if (instr_auipc)    new_ascii_instr = "auipc";
+		if (instr_jal)      new_ascii_instr = "jal";
+		if (instr_jalr)     new_ascii_instr = "jalr";
+
+		if (instr_beq)      new_ascii_instr = "beq";
+		if (instr_bne)      new_ascii_instr = "bne";
+		if (instr_blt)      new_ascii_instr = "blt";
+		if (instr_bge)      new_ascii_instr = "bge";
+		if (instr_bltu)     new_ascii_instr = "bltu";
+		if (instr_bgeu)     new_ascii_instr = "bgeu";
+
+		if (instr_lb)       new_ascii_instr = "lb";
+		if (instr_lh)       new_ascii_instr = "lh";
+		if (instr_lw)       new_ascii_instr = "lw";
+		if (instr_lbu)      new_ascii_instr = "lbu";
+		if (instr_lhu)      new_ascii_instr = "lhu";
+		if (instr_sb)       new_ascii_instr = "sb";
+		if (instr_sh)       new_ascii_instr = "sh";
+		if (instr_sw)       new_ascii_instr = "sw";
+
+		if (instr_addi)     new_ascii_instr = "addi";
+		if (instr_slti)     new_ascii_instr = "slti";
+		if (instr_sltiu)    new_ascii_instr = "sltiu";
+		if (instr_xori)     new_ascii_instr = "xori";
+		if (instr_ori)      new_ascii_instr = "ori";
+		if (instr_andi)     new_ascii_instr = "andi";
+		if (instr_slli)     new_ascii_instr = "slli";
+		if (instr_srli)     new_ascii_instr = "srli";
+		if (instr_srai)     new_ascii_instr = "srai";
+
+		if (instr_add)      new_ascii_instr = "add";
+		if (instr_sub)      new_ascii_instr = "sub";
+		if (instr_sll)      new_ascii_instr = "sll";
+		if (instr_slt)      new_ascii_instr = "slt";
+		if (instr_sltu)     new_ascii_instr = "sltu";
+		if (instr_xor)      new_ascii_instr = "xor";
+		if (instr_srl)      new_ascii_instr = "srl";
+		if (instr_sra)      new_ascii_instr = "sra";
+		if (instr_or)       new_ascii_instr = "or";
+		if (instr_and)      new_ascii_instr = "and";
+
+		if (instr_rdcycle)  new_ascii_instr = "rdcycle";
+		if (instr_rdcycleh) new_ascii_instr = "rdcycleh";
+		if (instr_rdinstr)  new_ascii_instr = "rdinstr";
+		if (instr_rdinstrh) new_ascii_instr = "rdinstrh";
+
+		if (instr_getq)     new_ascii_instr = "getq";
+		if (instr_setq)     new_ascii_instr = "setq";
+		if (instr_retirq)   new_ascii_instr = "retirq";
+		if (instr_maskirq)  new_ascii_instr = "maskirq";
+		if (instr_waitirq)  new_ascii_instr = "waitirq";
+		if (instr_timer)    new_ascii_instr = "timer";
+	end
+
+	reg [63:0] q_ascii_instr;
+	reg [31:0] q_insn_imm;
+	reg [31:0] q_insn_opcode;
+	reg [4:0] q_insn_rs1;
+	reg [4:0] q_insn_rs2;
+	reg [4:0] q_insn_rd;
+	reg dbg_next;
+
+	wire launch_next_insn;
+	reg dbg_valid_insn;
+
+	reg [63:0] cached_ascii_instr;
+	reg [31:0] cached_insn_imm;
+	reg [31:0] cached_insn_opcode;
+	reg [4:0] cached_insn_rs1;
+	reg [4:0] cached_insn_rs2;
+	reg [4:0] cached_insn_rd;
+
+	always @(posedge clk) begin
+		q_ascii_instr <= dbg_ascii_instr;
+		q_insn_imm <= dbg_insn_imm;
+		q_insn_opcode <= dbg_insn_opcode;
+		q_insn_rs1 <= dbg_insn_rs1;
+		q_insn_rs2 <= dbg_insn_rs2;
+		q_insn_rd <= dbg_insn_rd;
+		dbg_next <= launch_next_insn;
+
+		if (!resetn || trap)
+			dbg_valid_insn <= 0;
+		else if (launch_next_insn)
+			dbg_valid_insn <= 1;
+
+		if (decoder_trigger_q) begin
+			cached_ascii_instr <= new_ascii_instr;
+			cached_insn_imm <= decoded_imm;
+			if (&next_insn_opcode[1:0])
+				cached_insn_opcode <= next_insn_opcode;
+			else
+				cached_insn_opcode <= {16'b0, next_insn_opcode[15:0]};
+			cached_insn_rs1 <= decoded_rs1;
+			cached_insn_rs2 <= decoded_rs2;
+			cached_insn_rd <= decoded_rd;
+		end
+
+		if (launch_next_insn) begin
+			dbg_insn_addr <= next_pc;
+		end
+	end
+
+	always @* begin
+		dbg_ascii_instr = q_ascii_instr;
+		dbg_insn_imm = q_insn_imm;
+		dbg_insn_opcode = q_insn_opcode;
+		dbg_insn_rs1 = q_insn_rs1;
+		dbg_insn_rs2 = q_insn_rs2;
+		dbg_insn_rd = q_insn_rd;
+
+		if (dbg_next) begin
+			if (decoder_pseudo_trigger_q) begin
+				dbg_ascii_instr = cached_ascii_instr;
+				dbg_insn_imm = cached_insn_imm;
+				dbg_insn_opcode = cached_insn_opcode;
+				dbg_insn_rs1 = cached_insn_rs1;
+				dbg_insn_rs2 = cached_insn_rs2;
+				dbg_insn_rd = cached_insn_rd;
+			end else begin
+				dbg_ascii_instr = new_ascii_instr;
+				if (&next_insn_opcode[1:0])
+					dbg_insn_opcode = next_insn_opcode;
+				else
+					dbg_insn_opcode = {16'b0, next_insn_opcode[15:0]};
+				dbg_insn_imm = decoded_imm;
+				dbg_insn_rs1 = decoded_rs1;
+				dbg_insn_rs2 = decoded_rs2;
+				dbg_insn_rd = decoded_rd;
+			end
+		end
+	end
+
+`ifdef DEBUGASM
+	always @(posedge clk) begin
+		if (dbg_next) begin
+			$display("debugasm %x %x %s", dbg_insn_addr, dbg_insn_opcode, dbg_ascii_instr ? dbg_ascii_instr : "*");
+		end
+	end
+`endif
+
+`ifdef DEBUG
+	always @(posedge clk) begin
+		if (dbg_next) begin
+			if (&dbg_insn_opcode[1:0])
+				$display("DECODE: 0x%08x 0x%08x %-0s", dbg_insn_addr, dbg_insn_opcode, dbg_ascii_instr ? dbg_ascii_instr : "UNKNOWN");
+			else
+				$display("DECODE: 0x%08x     0x%04x %-0s", dbg_insn_addr, dbg_insn_opcode[15:0], dbg_ascii_instr ? dbg_ascii_instr : "UNKNOWN");
+		end
+	end
+`endif
+
+	always @(posedge clk) begin
+		is_lui_auipc_jal <= |{instr_lui, instr_auipc, instr_jal};
+		is_lui_auipc_jal_jalr_addi_add_sub <= |{instr_lui, instr_auipc, instr_jal, instr_jalr, instr_addi, instr_add, instr_sub};
+		is_slti_blt_slt <= |{instr_slti, instr_blt, instr_slt};
+		is_sltiu_bltu_sltu <= |{instr_sltiu, instr_bltu, instr_sltu};
+		is_lbu_lhu_lw <= |{instr_lbu, instr_lhu, instr_lw};
+		is_compare <= |{is_beq_bne_blt_bge_bltu_bgeu, instr_slti, instr_slt, instr_sltiu, instr_sltu};
+
+		if (mem_do_rinst && mem_done) begin
+			instr_lui     <= mem_rdata_latched[6:0] == 7'b0110111;
+			instr_auipc   <= mem_rdata_latched[6:0] == 7'b0010111;
+			instr_jal     <= mem_rdata_latched[6:0] == 7'b1101111;
+			instr_jalr    <= mem_rdata_latched[6:0] == 7'b1100111 && mem_rdata_latched[14:12] == 3'b000;
+			instr_retirq  <= mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000010 && ENABLE_IRQ;
+			instr_waitirq <= mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000100 && ENABLE_IRQ;
+
+			is_beq_bne_blt_bge_bltu_bgeu <= mem_rdata_latched[6:0] == 7'b1100011;
+			is_lb_lh_lw_lbu_lhu          <= mem_rdata_latched[6:0] == 7'b0000011;
+			is_sb_sh_sw                  <= mem_rdata_latched[6:0] == 7'b0100011;
+			is_alu_reg_imm               <= mem_rdata_latched[6:0] == 7'b0010011;
+			is_alu_reg_reg               <= mem_rdata_latched[6:0] == 7'b0110011;
+
+			{ decoded_imm_j[31:20], decoded_imm_j[10:1], decoded_imm_j[11], decoded_imm_j[19:12], decoded_imm_j[0] } <= $signed({mem_rdata_latched[31:12], 1'b0});
+
+			decoded_rd <= mem_rdata_latched[11:7];
+			decoded_rs1 <= mem_rdata_latched[19:15];
+			decoded_rs2 <= mem_rdata_latched[24:20];
+
+			if (mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000000 && ENABLE_IRQ && ENABLE_IRQ_QREGS)
+				decoded_rs1[regindex_bits-1] <= 1; // instr_getq
+
+			if (mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000010 && ENABLE_IRQ)
+				decoded_rs1 <= ENABLE_IRQ_QREGS ? irqregs_offset : 3; // instr_retirq
+
+			compressed_instr <= 0;
+			if (COMPRESSED_ISA && mem_rdata_latched[1:0] != 2'b11) begin
+				compressed_instr <= 1;
+				decoded_rd <= 0;
+				decoded_rs1 <= 0;
+				decoded_rs2 <= 0;
+
+				{ decoded_imm_j[31:11], decoded_imm_j[4], decoded_imm_j[9:8], decoded_imm_j[10], decoded_imm_j[6],
+				  decoded_imm_j[7], decoded_imm_j[3:1], decoded_imm_j[5], decoded_imm_j[0] } <= $signed({mem_rdata_latched[12:2], 1'b0});
+
+				case (mem_rdata_latched[1:0])
+					2'b00: begin // Quadrant 0
+						case (mem_rdata_latched[15:13])
+							3'b000: begin // C.ADDI4SPN
+								is_alu_reg_imm <= |mem_rdata_latched[12:5];
+								decoded_rs1 <= 2;
+								decoded_rd <= 8 + mem_rdata_latched[4:2];
+							end
+							3'b010: begin // C.LW
+								is_lb_lh_lw_lbu_lhu <= 1;
+								decoded_rs1 <= 8 + mem_rdata_latched[9:7];
+								decoded_rd <= 8 + mem_rdata_latched[4:2];
+							end
+							3'b110: begin // C.SW
+								is_sb_sh_sw <= 1;
+								decoded_rs1 <= 8 + mem_rdata_latched[9:7];
+								decoded_rs2 <= 8 + mem_rdata_latched[4:2];
+							end
+						endcase
+					end
+					2'b01: begin // Quadrant 1
+						case (mem_rdata_latched[15:13])
+							3'b000: begin // C.NOP / C.ADDI
+								is_alu_reg_imm <= 1;
+								decoded_rd <= mem_rdata_latched[11:7];
+								decoded_rs1 <= mem_rdata_latched[11:7];
+							end
+							3'b001: begin // C.JAL
+								instr_jal <= 1;
+								decoded_rd <= 1;
+							end
+							3'b 010: begin // C.LI
+								is_alu_reg_imm <= 1;
+								decoded_rd <= mem_rdata_latched[11:7];
+								decoded_rs1 <= 0;
+							end
+							3'b 011: begin
+								if (mem_rdata_latched[12] || mem_rdata_latched[6:2]) begin
+									if (mem_rdata_latched[11:7] == 2) begin // C.ADDI16SP
+										is_alu_reg_imm <= 1;
+										decoded_rd <= mem_rdata_latched[11:7];
+										decoded_rs1 <= mem_rdata_latched[11:7];
+									end else begin // C.LUI
+										instr_lui <= 1;
+										decoded_rd <= mem_rdata_latched[11:7];
+										decoded_rs1 <= 0;
+									end
+								end
+							end
+							3'b100: begin
+								if (!mem_rdata_latched[11] && !mem_rdata_latched[12]) begin // C.SRLI, C.SRAI
+									is_alu_reg_imm <= 1;
+									decoded_rd <= 8 + mem_rdata_latched[9:7];
+									decoded_rs1 <= 8 + mem_rdata_latched[9:7];
+									decoded_rs2 <= {mem_rdata_latched[12], mem_rdata_latched[6:2]};
+								end
+								if (mem_rdata_latched[11:10] == 2'b10) begin // C.ANDI
+									is_alu_reg_imm <= 1;
+									decoded_rd <= 8 + mem_rdata_latched[9:7];
+									decoded_rs1 <= 8 + mem_rdata_latched[9:7];
+								end
+								if (mem_rdata_latched[12:10] == 3'b011) begin // C.SUB, C.XOR, C.OR, C.AND
+									is_alu_reg_reg <= 1;
+									decoded_rd <= 8 + mem_rdata_latched[9:7];
+									decoded_rs1 <= 8 + mem_rdata_latched[9:7];
+									decoded_rs2 <= 8 + mem_rdata_latched[4:2];
+								end
+							end
+							3'b101: begin // C.J
+								instr_jal <= 1;
+							end
+							3'b110: begin // C.BEQZ
+								is_beq_bne_blt_bge_bltu_bgeu <= 1;
+								decoded_rs1 <= 8 + mem_rdata_latched[9:7];
+								decoded_rs2 <= 0;
+							end
+							3'b111: begin // C.BNEZ
+								is_beq_bne_blt_bge_bltu_bgeu <= 1;
+								decoded_rs1 <= 8 + mem_rdata_latched[9:7];
+								decoded_rs2 <= 0;
+							end
+						endcase
+					end
+					2'b10: begin // Quadrant 2
+						case (mem_rdata_latched[15:13])
+							3'b000: begin // C.SLLI
+								if (!mem_rdata_latched[12]) begin
+									is_alu_reg_imm <= 1;
+									decoded_rd <= mem_rdata_latched[11:7];
+									decoded_rs1 <= mem_rdata_latched[11:7];
+									decoded_rs2 <= {mem_rdata_latched[12], mem_rdata_latched[6:2]};
+								end
+							end
+							3'b010: begin // C.LWSP
+								if (mem_rdata_latched[11:7]) begin
+									is_lb_lh_lw_lbu_lhu <= 1;
+									decoded_rd <= mem_rdata_latched[11:7];
+									decoded_rs1 <= 2;
+								end
+							end
+							3'b100: begin
+								if (mem_rdata_latched[12] == 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JR
+									instr_jalr <= 1;
+									decoded_rd <= 0;
+									decoded_rs1 <= mem_rdata_latched[11:7];
+								end
+								if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] != 0) begin // C.MV
+									is_alu_reg_reg <= 1;
+									decoded_rd <= mem_rdata_latched[11:7];
+									decoded_rs1 <= 0;
+									decoded_rs2 <= mem_rdata_latched[6:2];
+								end
+								if (mem_rdata_latched[12] != 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JALR
+									instr_jalr <= 1;
+									decoded_rd <= 1;
+									decoded_rs1 <= mem_rdata_latched[11:7];
+								end
+								if (mem_rdata_latched[12] != 0 && mem_rdata_latched[6:2] != 0) begin // C.ADD
+									is_alu_reg_reg <= 1;
+									decoded_rd <= mem_rdata_latched[11:7];
+									decoded_rs1 <= mem_rdata_latched[11:7];
+									decoded_rs2 <= mem_rdata_latched[6:2];
+								end
+							end
+							3'b110: begin // C.SWSP
+								is_sb_sh_sw <= 1;
+								decoded_rs1 <= 2;
+								decoded_rs2 <= mem_rdata_latched[6:2];
+							end
+						endcase
+					end
+				endcase
+			end
+		end
+
+		if (decoder_trigger && !decoder_pseudo_trigger) begin
+			pcpi_insn <= WITH_PCPI ? mem_rdata_q : 'bx;
+
+			instr_beq   <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b000;
+			instr_bne   <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b001;
+			instr_blt   <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b100;
+			instr_bge   <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b101;
+			instr_bltu  <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b110;
+			instr_bgeu  <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b111;
+
+			instr_lb    <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b000;
+			instr_lh    <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b001;
+			instr_lw    <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b010;
+			instr_lbu   <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b100;
+			instr_lhu   <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b101;
+
+			instr_sb    <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b000;
+			instr_sh    <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b001;
+			instr_sw    <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b010;
+
+			instr_addi  <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b000;
+			instr_slti  <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b010;
+			instr_sltiu <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b011;
+			instr_xori  <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b100;
+			instr_ori   <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b110;
+			instr_andi  <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b111;
+
+			instr_slli  <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_srli  <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_srai  <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000;
+
+			instr_add   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b000 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_sub   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b000 && mem_rdata_q[31:25] == 7'b0100000;
+			instr_sll   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_slt   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b010 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_sltu  <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b011 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_xor   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b100 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_srl   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_sra   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000;
+			instr_or    <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b110 && mem_rdata_q[31:25] == 7'b0000000;
+			instr_and   <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b111 && mem_rdata_q[31:25] == 7'b0000000;
+
+			instr_rdcycle  <= ((mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000000000000010) ||
+			                   (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000000100000010)) && ENABLE_COUNTERS;
+			instr_rdcycleh <= ((mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000000000000010) ||
+			                   (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000000100000010)) && ENABLE_COUNTERS && ENABLE_COUNTERS64;
+			instr_rdinstr  <=  (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000001000000010) && ENABLE_COUNTERS;
+			instr_rdinstrh <=  (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000001000000010) && ENABLE_COUNTERS && ENABLE_COUNTERS64;
+
+			instr_ecall_ebreak <= ((mem_rdata_q[6:0] == 7'b1110011 && !mem_rdata_q[31:21] && !mem_rdata_q[19:7]) ||
+					(COMPRESSED_ISA && mem_rdata_q[15:0] == 16'h9002));
+
+			instr_getq    <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000000 && ENABLE_IRQ && ENABLE_IRQ_QREGS;
+			instr_setq    <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000001 && ENABLE_IRQ && ENABLE_IRQ_QREGS;
+			instr_maskirq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000011 && ENABLE_IRQ;
+			instr_timer   <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000101 && ENABLE_IRQ && ENABLE_IRQ_TIMER;
+
+			is_slli_srli_srai <= is_alu_reg_imm && |{
+				mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000,
+				mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000,
+				mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000
+			};
+
+			is_jalr_addi_slti_sltiu_xori_ori_andi <= instr_jalr || is_alu_reg_imm && |{
+				mem_rdata_q[14:12] == 3'b000,
+				mem_rdata_q[14:12] == 3'b010,
+				mem_rdata_q[14:12] == 3'b011,
+				mem_rdata_q[14:12] == 3'b100,
+				mem_rdata_q[14:12] == 3'b110,
+				mem_rdata_q[14:12] == 3'b111
+			};
+
+			is_sll_srl_sra <= is_alu_reg_reg && |{
+				mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000,
+				mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000,
+				mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000
+			};
+
+			is_lui_auipc_jal_jalr_addi_add_sub <= 0;
+			is_compare <= 0;
+
+			(* parallel_case *)
+			case (1'b1)
+				instr_jal:
+					decoded_imm <= decoded_imm_j;
+				|{instr_lui, instr_auipc}:
+					decoded_imm <= mem_rdata_q[31:12] << 12;
+				|{instr_jalr, is_lb_lh_lw_lbu_lhu, is_alu_reg_imm}:
+					decoded_imm <= $signed(mem_rdata_q[31:20]);
+				is_beq_bne_blt_bge_bltu_bgeu:
+					decoded_imm <= $signed({mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8], 1'b0});
+				is_sb_sh_sw:
+					decoded_imm <= $signed({mem_rdata_q[31:25], mem_rdata_q[11:7]});
+				default:
+					decoded_imm <= 1'bx;
+			endcase
+		end
+
+		if (!resetn) begin
+			is_beq_bne_blt_bge_bltu_bgeu <= 0;
+			is_compare <= 0;
+
+			instr_beq   <= 0;
+			instr_bne   <= 0;
+			instr_blt   <= 0;
+			instr_bge   <= 0;
+			instr_bltu  <= 0;
+			instr_bgeu  <= 0;
+
+			instr_addi  <= 0;
+			instr_slti  <= 0;
+			instr_sltiu <= 0;
+			instr_xori  <= 0;
+			instr_ori   <= 0;
+			instr_andi  <= 0;
+
+			instr_add   <= 0;
+			instr_sub   <= 0;
+			instr_sll   <= 0;
+			instr_slt   <= 0;
+			instr_sltu  <= 0;
+			instr_xor   <= 0;
+			instr_srl   <= 0;
+			instr_sra   <= 0;
+			instr_or    <= 0;
+			instr_and   <= 0;
+		end
+	end
+
+
+	// Main State Machine
+
+	localparam cpu_state_trap   = 8'b10000000;
+	localparam cpu_state_fetch  = 8'b01000000;
+	localparam cpu_state_ld_rs1 = 8'b00100000;
+	localparam cpu_state_ld_rs2 = 8'b00010000;
+	localparam cpu_state_exec   = 8'b00001000;
+	localparam cpu_state_shift  = 8'b00000100;
+	localparam cpu_state_stmem  = 8'b00000010;
+	localparam cpu_state_ldmem  = 8'b00000001;
+
+	reg [7:0] cpu_state;
+	reg [1:0] irq_state;
+
+	`FORMAL_KEEP reg [127:0] dbg_ascii_state;
+
+	always @* begin
+		dbg_ascii_state = "";
+		if (cpu_state == cpu_state_trap)   dbg_ascii_state = "trap";
+		if (cpu_state == cpu_state_fetch)  dbg_ascii_state = "fetch";
+		if (cpu_state == cpu_state_ld_rs1) dbg_ascii_state = "ld_rs1";
+		if (cpu_state == cpu_state_ld_rs2) dbg_ascii_state = "ld_rs2";
+		if (cpu_state == cpu_state_exec)   dbg_ascii_state = "exec";
+		if (cpu_state == cpu_state_shift)  dbg_ascii_state = "shift";
+		if (cpu_state == cpu_state_stmem)  dbg_ascii_state = "stmem";
+		if (cpu_state == cpu_state_ldmem)  dbg_ascii_state = "ldmem";
+	end
+
+	reg set_mem_do_rinst;
+	reg set_mem_do_rdata;
+	reg set_mem_do_wdata;
+
+	reg latched_store;
+	reg latched_stalu;
+	reg latched_branch;
+	reg latched_compr;
+	reg latched_trace;
+	reg latched_is_lu;
+	reg latched_is_lh;
+	reg latched_is_lb;
+	reg [regindex_bits-1:0] latched_rd;
+
+	reg [31:0] current_pc;
+	assign next_pc = latched_store && latched_branch ? reg_out & ~1 : reg_next_pc;
+
+	reg [3:0] pcpi_timeout_counter;
+	reg pcpi_timeout;
+
+	reg [31:0] next_irq_pending;
+	reg do_waitirq;
+
+	reg [31:0] alu_out, alu_out_q;
+	reg alu_out_0, alu_out_0_q;
+	reg alu_wait, alu_wait_2;
+
+	reg [31:0] alu_add_sub;
+	reg [31:0] alu_shl, alu_shr;
+	reg alu_eq, alu_ltu, alu_lts;
+
+	generate if (TWO_CYCLE_ALU) begin
+		always @(posedge clk) begin
+			alu_add_sub <= instr_sub ? reg_op1 - reg_op2 : reg_op1 + reg_op2;
+			alu_eq <= reg_op1 == reg_op2;
+			alu_lts <= $signed(reg_op1) < $signed(reg_op2);
+			alu_ltu <= reg_op1 < reg_op2;
+			alu_shl <= reg_op1 << reg_op2[4:0];
+			alu_shr <= $signed({instr_sra || instr_srai ? reg_op1[31] : 1'b0, reg_op1}) >>> reg_op2[4:0];
+		end
+	end else begin
+		always @* begin
+			alu_add_sub = instr_sub ? reg_op1 - reg_op2 : reg_op1 + reg_op2;
+			alu_eq = reg_op1 == reg_op2;
+			alu_lts = $signed(reg_op1) < $signed(reg_op2);
+			alu_ltu = reg_op1 < reg_op2;
+			alu_shl = reg_op1 << reg_op2[4:0];
+			alu_shr = $signed({instr_sra || instr_srai ? reg_op1[31] : 1'b0, reg_op1}) >>> reg_op2[4:0];
+		end
+	end endgenerate
+
+	always @* begin
+		alu_out_0 = 'bx;
+		(* parallel_case, full_case *)
+		case (1'b1)
+			instr_beq:
+				alu_out_0 = alu_eq;
+			instr_bne:
+				alu_out_0 = !alu_eq;
+			instr_bge:
+				alu_out_0 = !alu_lts;
+			instr_bgeu:
+				alu_out_0 = !alu_ltu;
+			is_slti_blt_slt && (!TWO_CYCLE_COMPARE || !{instr_beq,instr_bne,instr_bge,instr_bgeu}):
+				alu_out_0 = alu_lts;
+			is_sltiu_bltu_sltu && (!TWO_CYCLE_COMPARE || !{instr_beq,instr_bne,instr_bge,instr_bgeu}):
+				alu_out_0 = alu_ltu;
+		endcase
+
+		alu_out = 'bx;
+		(* parallel_case, full_case *)
+		case (1'b1)
+			is_lui_auipc_jal_jalr_addi_add_sub:
+				alu_out = alu_add_sub;
+			is_compare:
+				alu_out = alu_out_0;
+			instr_xori || instr_xor:
+				alu_out = reg_op1 ^ reg_op2;
+			instr_ori || instr_or:
+				alu_out = reg_op1 | reg_op2;
+			instr_andi || instr_and:
+				alu_out = reg_op1 & reg_op2;
+			BARREL_SHIFTER && (instr_sll || instr_slli):
+				alu_out = alu_shl;
+			BARREL_SHIFTER && (instr_srl || instr_srli || instr_sra || instr_srai):
+				alu_out = alu_shr;
+		endcase
+
+`ifdef RISCV_FORMAL_BLACKBOX_ALU
+		alu_out_0 = $anyseq;
+		alu_out = $anyseq;
+`endif
+	end
+
+	reg clear_prefetched_high_word_q;
+	always @(posedge clk) clear_prefetched_high_word_q <= clear_prefetched_high_word;
+
+	always @* begin
+		clear_prefetched_high_word = clear_prefetched_high_word_q;
+		if (!prefetched_high_word)
+			clear_prefetched_high_word = 0;
+		if (latched_branch || irq_state || !resetn)
+			clear_prefetched_high_word = COMPRESSED_ISA;
+	end
+
+	reg cpuregs_write;
+	reg [31:0] cpuregs_wrdata;
+	reg [31:0] cpuregs_rs1;
+	reg [31:0] cpuregs_rs2;
+	reg [regindex_bits-1:0] decoded_rs;
+
+	always @* begin
+		cpuregs_write = 0;
+		cpuregs_wrdata = 'bx;
+
+		if (cpu_state == cpu_state_fetch) begin
+			(* parallel_case *)
+			case (1'b1)
+				latched_branch: begin
+					cpuregs_wrdata = reg_pc + (latched_compr ? 2 : 4);
+					cpuregs_write = 1;
+				end
+				latched_store && !latched_branch: begin
+					cpuregs_wrdata = latched_stalu ? alu_out_q : reg_out;
+					cpuregs_write = 1;
+				end
+				ENABLE_IRQ && irq_state[0]: begin
+					cpuregs_wrdata = reg_next_pc | latched_compr;
+					cpuregs_write = 1;
+				end
+				ENABLE_IRQ && irq_state[1]: begin
+					cpuregs_wrdata = irq_pending & ~irq_mask;
+					cpuregs_write = 1;
+				end
+			endcase
+		end
+	end
+
+`ifndef PICORV32_REGS
+	always @(posedge clk) begin
+		if (resetn && cpuregs_write && latched_rd)
+`ifdef PICORV32_TESTBUG_001
+			cpuregs[latched_rd ^ 1] <= cpuregs_wrdata;
+`elsif PICORV32_TESTBUG_002
+			cpuregs[latched_rd] <= cpuregs_wrdata ^ 1;
+`else
+			cpuregs[latched_rd] <= cpuregs_wrdata;
+`endif
+	end
+
+	always @* begin
+		decoded_rs = 'bx;
+		if (ENABLE_REGS_DUALPORT) begin
+`ifndef RISCV_FORMAL_BLACKBOX_REGS
+			cpuregs_rs1 = decoded_rs1 ? cpuregs[decoded_rs1] : 0;
+			cpuregs_rs2 = decoded_rs2 ? cpuregs[decoded_rs2] : 0;
+`else
+			cpuregs_rs1 = decoded_rs1 ? $anyseq : 0;
+			cpuregs_rs2 = decoded_rs2 ? $anyseq : 0;
+`endif
+		end else begin
+			decoded_rs = (cpu_state == cpu_state_ld_rs2) ? decoded_rs2 : decoded_rs1;
+`ifndef RISCV_FORMAL_BLACKBOX_REGS
+			cpuregs_rs1 = decoded_rs ? cpuregs[decoded_rs] : 0;
+`else
+			cpuregs_rs1 = decoded_rs ? $anyseq : 0;
+`endif
+			cpuregs_rs2 = cpuregs_rs1;
+		end
+	end
+`else
+	wire[31:0] cpuregs_rdata1;
+	wire[31:0] cpuregs_rdata2;
+
+	wire [5:0] cpuregs_waddr = latched_rd;
+	wire [5:0] cpuregs_raddr1 = ENABLE_REGS_DUALPORT ? decoded_rs1 : decoded_rs;
+	wire [5:0] cpuregs_raddr2 = ENABLE_REGS_DUALPORT ? decoded_rs2 : 0;
+
+	`PICORV32_REGS cpuregs (
+		.clk(clk),
+		.wen(resetn && cpuregs_write && latched_rd),
+		.waddr(cpuregs_waddr),
+		.raddr1(cpuregs_raddr1),
+		.raddr2(cpuregs_raddr2),
+		.wdata(cpuregs_wrdata),
+		.rdata1(cpuregs_rdata1),
+		.rdata2(cpuregs_rdata2)
+	);
+
+	always @* begin
+		decoded_rs = 'bx;
+		if (ENABLE_REGS_DUALPORT) begin
+			cpuregs_rs1 = decoded_rs1 ? cpuregs_rdata1 : 0;
+			cpuregs_rs2 = decoded_rs2 ? cpuregs_rdata2 : 0;
+		end else begin
+			decoded_rs = (cpu_state == cpu_state_ld_rs2) ? decoded_rs2 : decoded_rs1;
+			cpuregs_rs1 = decoded_rs ? cpuregs_rdata1 : 0;
+			cpuregs_rs2 = cpuregs_rs1;
+		end
+	end
+`endif
+
+	assign launch_next_insn = cpu_state == cpu_state_fetch && decoder_trigger && (!ENABLE_IRQ || irq_delay || irq_active || !(irq_pending & ~irq_mask));
+
+	always @(posedge clk) begin
+		trap <= 0;
+		reg_sh <= 'bx;
+		reg_out <= 'bx;
+		set_mem_do_rinst = 0;
+		set_mem_do_rdata = 0;
+		set_mem_do_wdata = 0;
+
+		alu_out_0_q <= alu_out_0;
+		alu_out_q <= alu_out;
+
+		alu_wait <= 0;
+		alu_wait_2 <= 0;
+
+		if (launch_next_insn) begin
+			dbg_rs1val <= 'bx;
+			dbg_rs2val <= 'bx;
+			dbg_rs1val_valid <= 0;
+			dbg_rs2val_valid <= 0;
+		end
+
+		if (WITH_PCPI && CATCH_ILLINSN) begin
+			if (resetn && pcpi_valid && !pcpi_int_wait) begin
+				if (pcpi_timeout_counter)
+					pcpi_timeout_counter <= pcpi_timeout_counter - 1;
+			end else
+				pcpi_timeout_counter <= ~0;
+			pcpi_timeout <= !pcpi_timeout_counter;
+		end
+
+		if (ENABLE_COUNTERS) begin
+			count_cycle <= resetn ? count_cycle + 1 : 0;
+			if (!ENABLE_COUNTERS64) count_cycle[63:32] <= 0;
+		end else begin
+			count_cycle <= 'bx;
+			count_instr <= 'bx;
+		end
+
+		next_irq_pending = ENABLE_IRQ ? irq_pending & LATCHED_IRQ : 'bx;
+
+		if (ENABLE_IRQ && ENABLE_IRQ_TIMER && timer) begin
+			timer <= timer - 1;
+		end
+
+		decoder_trigger <= mem_do_rinst && mem_done;
+		decoder_trigger_q <= decoder_trigger;
+		decoder_pseudo_trigger <= 0;
+		decoder_pseudo_trigger_q <= decoder_pseudo_trigger;
+		do_waitirq <= 0;
+
+		trace_valid <= 0;
+
+		if (!ENABLE_TRACE)
+			trace_data <= 'bx;
+
+		if (!resetn) begin
+			reg_pc <= PROGADDR_RESET;
+			reg_next_pc <= PROGADDR_RESET;
+			if (ENABLE_COUNTERS)
+				count_instr <= 0;
+			latched_store <= 0;
+			latched_stalu <= 0;
+			latched_branch <= 0;
+			latched_trace <= 0;
+			latched_is_lu <= 0;
+			latched_is_lh <= 0;
+			latched_is_lb <= 0;
+			pcpi_valid <= 0;
+			pcpi_timeout <= 0;
+			irq_active <= 0;
+			irq_delay <= 0;
+			irq_mask <= ~0;
+			next_irq_pending = 0;
+			irq_state <= 0;
+			eoi <= 0;
+			timer <= 0;
+			if (~STACKADDR) begin
+				latched_store <= 1;
+				latched_rd <= 2;
+				reg_out <= STACKADDR;
+			end
+			cpu_state <= cpu_state_fetch;
+		end else
+		(* parallel_case, full_case *)
+		case (cpu_state)
+			cpu_state_trap: begin
+				trap <= 1;
+			end
+
+			cpu_state_fetch: begin
+				mem_do_rinst <= !decoder_trigger && !do_waitirq;
+				mem_wordsize <= 0;
+
+				current_pc = reg_next_pc;
+
+				(* parallel_case *)
+				case (1'b1)
+					latched_branch: begin
+						current_pc = latched_store ? (latched_stalu ? alu_out_q : reg_out) & ~1 : reg_next_pc;
+						`debug($display("ST_RD:  %2d 0x%08x, BRANCH 0x%08x", latched_rd, reg_pc + (latched_compr ? 2 : 4), current_pc);)
+					end
+					latched_store && !latched_branch: begin
+						`debug($display("ST_RD:  %2d 0x%08x", latched_rd, latched_stalu ? alu_out_q : reg_out);)
+					end
+					ENABLE_IRQ && irq_state[0]: begin
+						current_pc = PROGADDR_IRQ;
+						irq_active <= 1;
+						mem_do_rinst <= 1;
+					end
+					ENABLE_IRQ && irq_state[1]: begin
+						eoi <= irq_pending & ~irq_mask;
+						next_irq_pending = next_irq_pending & irq_mask;
+					end
+				endcase
+
+				if (ENABLE_TRACE && latched_trace) begin
+					latched_trace <= 0;
+					trace_valid <= 1;
+					if (latched_branch)
+						trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_BRANCH | (current_pc & 32'hfffffffe);
+					else
+						trace_data <= (irq_active ? TRACE_IRQ : 0) | (latched_stalu ? alu_out_q : reg_out);
+				end
+
+				reg_pc <= current_pc;
+				reg_next_pc <= current_pc;
+
+				latched_store <= 0;
+				latched_stalu <= 0;
+				latched_branch <= 0;
+				latched_is_lu <= 0;
+				latched_is_lh <= 0;
+				latched_is_lb <= 0;
+				latched_rd <= decoded_rd;
+				latched_compr <= compressed_instr;
+
+				if (ENABLE_IRQ && ((decoder_trigger && !irq_active && !irq_delay && |(irq_pending & ~irq_mask)) || irq_state)) begin
+					irq_state <=
+						irq_state == 2'b00 ? 2'b01 :
+						irq_state == 2'b01 ? 2'b10 : 2'b00;
+					latched_compr <= latched_compr;
+					if (ENABLE_IRQ_QREGS)
+						latched_rd <= irqregs_offset | irq_state[0];
+					else
+						latched_rd <= irq_state[0] ? 4 : 3;
+				end else
+				if (ENABLE_IRQ && (decoder_trigger || do_waitirq) && instr_waitirq) begin
+					if (irq_pending) begin
+						latched_store <= 1;
+						reg_out <= irq_pending;
+						reg_next_pc <= current_pc + (compressed_instr ? 2 : 4);
+						mem_do_rinst <= 1;
+					end else
+						do_waitirq <= 1;
+				end else
+				if (decoder_trigger) begin
+					`debug($display("-- %-0t", $time);)
+					irq_delay <= irq_active;
+					reg_next_pc <= current_pc + (compressed_instr ? 2 : 4);
+					if (ENABLE_TRACE)
+						latched_trace <= 1;
+					if (ENABLE_COUNTERS) begin
+						count_instr <= count_instr + 1;
+						if (!ENABLE_COUNTERS64) count_instr[63:32] <= 0;
+					end
+					if (instr_jal) begin
+						mem_do_rinst <= 1;
+						reg_next_pc <= current_pc + decoded_imm_j;
+						latched_branch <= 1;
+					end else begin
+						mem_do_rinst <= 0;
+						mem_do_prefetch <= !instr_jalr && !instr_retirq;
+						cpu_state <= cpu_state_ld_rs1;
+					end
+				end
+			end
+
+			cpu_state_ld_rs1: begin
+				reg_op1 <= 'bx;
+				reg_op2 <= 'bx;
+
+				(* parallel_case *)
+				case (1'b1)
+					(CATCH_ILLINSN || WITH_PCPI) && instr_trap: begin
+						if (WITH_PCPI) begin
+							`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+							reg_op1 <= cpuregs_rs1;
+							dbg_rs1val <= cpuregs_rs1;
+							dbg_rs1val_valid <= 1;
+							if (ENABLE_REGS_DUALPORT) begin
+								pcpi_valid <= 1;
+								`debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);)
+								reg_sh <= cpuregs_rs2;
+								reg_op2 <= cpuregs_rs2;
+								dbg_rs2val <= cpuregs_rs2;
+								dbg_rs2val_valid <= 1;
+								if (pcpi_int_ready) begin
+									mem_do_rinst <= 1;
+									pcpi_valid <= 0;
+									reg_out <= pcpi_int_rd;
+									latched_store <= pcpi_int_wr;
+									cpu_state <= cpu_state_fetch;
+								end else
+								if (CATCH_ILLINSN && (pcpi_timeout || instr_ecall_ebreak)) begin
+									pcpi_valid <= 0;
+									`debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);)
+									if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin
+										next_irq_pending[irq_ebreak] = 1;
+										cpu_state <= cpu_state_fetch;
+									end else
+										cpu_state <= cpu_state_trap;
+								end
+							end else begin
+								cpu_state <= cpu_state_ld_rs2;
+							end
+						end else begin
+							`debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);)
+							if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin
+								next_irq_pending[irq_ebreak] = 1;
+								cpu_state <= cpu_state_fetch;
+							end else
+								cpu_state <= cpu_state_trap;
+						end
+					end
+					ENABLE_COUNTERS && is_rdcycle_rdcycleh_rdinstr_rdinstrh: begin
+						(* parallel_case, full_case *)
+						case (1'b1)
+							instr_rdcycle:
+								reg_out <= count_cycle[31:0];
+							instr_rdcycleh && ENABLE_COUNTERS64:
+								reg_out <= count_cycle[63:32];
+							instr_rdinstr:
+								reg_out <= count_instr[31:0];
+							instr_rdinstrh && ENABLE_COUNTERS64:
+								reg_out <= count_instr[63:32];
+						endcase
+						latched_store <= 1;
+						cpu_state <= cpu_state_fetch;
+					end
+					is_lui_auipc_jal: begin
+						reg_op1 <= instr_lui ? 0 : reg_pc;
+						reg_op2 <= decoded_imm;
+						if (TWO_CYCLE_ALU)
+							alu_wait <= 1;
+						else
+							mem_do_rinst <= mem_do_prefetch;
+						cpu_state <= cpu_state_exec;
+					end
+					ENABLE_IRQ && ENABLE_IRQ_QREGS && instr_getq: begin
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						reg_out <= cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						latched_store <= 1;
+						cpu_state <= cpu_state_fetch;
+					end
+					ENABLE_IRQ && ENABLE_IRQ_QREGS && instr_setq: begin
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						reg_out <= cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						latched_rd <= latched_rd | irqregs_offset;
+						latched_store <= 1;
+						cpu_state <= cpu_state_fetch;
+					end
+					ENABLE_IRQ && instr_retirq: begin
+						eoi <= 0;
+						irq_active <= 0;
+						latched_branch <= 1;
+						latched_store <= 1;
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						reg_out <= CATCH_MISALIGN ? (cpuregs_rs1 & 32'h fffffffe) : cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						cpu_state <= cpu_state_fetch;
+					end
+					ENABLE_IRQ && instr_maskirq: begin
+						latched_store <= 1;
+						reg_out <= irq_mask;
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						irq_mask <= cpuregs_rs1 | MASKED_IRQ;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						cpu_state <= cpu_state_fetch;
+					end
+					ENABLE_IRQ && ENABLE_IRQ_TIMER && instr_timer: begin
+						latched_store <= 1;
+						reg_out <= timer;
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						timer <= cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						cpu_state <= cpu_state_fetch;
+					end
+					is_lb_lh_lw_lbu_lhu && !instr_trap: begin
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						reg_op1 <= cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						cpu_state <= cpu_state_ldmem;
+						mem_do_rinst <= 1;
+					end
+					is_slli_srli_srai && !BARREL_SHIFTER: begin
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						reg_op1 <= cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						reg_sh <= decoded_rs2;
+						cpu_state <= cpu_state_shift;
+					end
+					is_jalr_addi_slti_sltiu_xori_ori_andi, is_slli_srli_srai && BARREL_SHIFTER: begin
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						reg_op1 <= cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						reg_op2 <= is_slli_srli_srai && BARREL_SHIFTER ? decoded_rs2 : decoded_imm;
+						if (TWO_CYCLE_ALU)
+							alu_wait <= 1;
+						else
+							mem_do_rinst <= mem_do_prefetch;
+						cpu_state <= cpu_state_exec;
+					end
+					default: begin
+						`debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);)
+						reg_op1 <= cpuregs_rs1;
+						dbg_rs1val <= cpuregs_rs1;
+						dbg_rs1val_valid <= 1;
+						if (ENABLE_REGS_DUALPORT) begin
+							`debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);)
+							reg_sh <= cpuregs_rs2;
+							reg_op2 <= cpuregs_rs2;
+							dbg_rs2val <= cpuregs_rs2;
+							dbg_rs2val_valid <= 1;
+							(* parallel_case *)
+							case (1'b1)
+								is_sb_sh_sw: begin
+									cpu_state <= cpu_state_stmem;
+									mem_do_rinst <= 1;
+								end
+								is_sll_srl_sra && !BARREL_SHIFTER: begin
+									cpu_state <= cpu_state_shift;
+								end
+								default: begin
+									if (TWO_CYCLE_ALU || (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu)) begin
+										alu_wait_2 <= TWO_CYCLE_ALU && (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu);
+										alu_wait <= 1;
+									end else
+										mem_do_rinst <= mem_do_prefetch;
+									cpu_state <= cpu_state_exec;
+								end
+							endcase
+						end else
+							cpu_state <= cpu_state_ld_rs2;
+					end
+				endcase
+			end
+
+			cpu_state_ld_rs2: begin
+				`debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);)
+				reg_sh <= cpuregs_rs2;
+				reg_op2 <= cpuregs_rs2;
+				dbg_rs2val <= cpuregs_rs2;
+				dbg_rs2val_valid <= 1;
+
+				(* parallel_case *)
+				case (1'b1)
+					WITH_PCPI && instr_trap: begin
+						pcpi_valid <= 1;
+						if (pcpi_int_ready) begin
+							mem_do_rinst <= 1;
+							pcpi_valid <= 0;
+							reg_out <= pcpi_int_rd;
+							latched_store <= pcpi_int_wr;
+							cpu_state <= cpu_state_fetch;
+						end else
+						if (CATCH_ILLINSN && (pcpi_timeout || instr_ecall_ebreak)) begin
+							pcpi_valid <= 0;
+							`debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);)
+							if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin
+								next_irq_pending[irq_ebreak] = 1;
+								cpu_state <= cpu_state_fetch;
+							end else
+								cpu_state <= cpu_state_trap;
+						end
+					end
+					is_sb_sh_sw: begin
+						cpu_state <= cpu_state_stmem;
+						mem_do_rinst <= 1;
+					end
+					is_sll_srl_sra && !BARREL_SHIFTER: begin
+						cpu_state <= cpu_state_shift;
+					end
+					default: begin
+						if (TWO_CYCLE_ALU || (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu)) begin
+							alu_wait_2 <= TWO_CYCLE_ALU && (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu);
+							alu_wait <= 1;
+						end else
+							mem_do_rinst <= mem_do_prefetch;
+						cpu_state <= cpu_state_exec;
+					end
+				endcase
+			end
+
+			cpu_state_exec: begin
+				reg_out <= reg_pc + decoded_imm;
+				if ((TWO_CYCLE_ALU || TWO_CYCLE_COMPARE) && (alu_wait || alu_wait_2)) begin
+					mem_do_rinst <= mem_do_prefetch && !alu_wait_2;
+					alu_wait <= alu_wait_2;
+				end else
+				if (is_beq_bne_blt_bge_bltu_bgeu) begin
+					latched_rd <= 0;
+					latched_store <= TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0;
+					latched_branch <= TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0;
+					if (mem_done)
+						cpu_state <= cpu_state_fetch;
+					if (TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0) begin
+						decoder_trigger <= 0;
+						set_mem_do_rinst = 1;
+					end
+				end else begin
+					latched_branch <= instr_jalr;
+					latched_store <= 1;
+					latched_stalu <= 1;
+					cpu_state <= cpu_state_fetch;
+				end
+			end
+
+			cpu_state_shift: begin
+				latched_store <= 1;
+				if (reg_sh == 0) begin
+					reg_out <= reg_op1;
+					mem_do_rinst <= mem_do_prefetch;
+					cpu_state <= cpu_state_fetch;
+				end else if (TWO_STAGE_SHIFT && reg_sh >= 4) begin
+					(* parallel_case, full_case *)
+					case (1'b1)
+						instr_slli || instr_sll: reg_op1 <= reg_op1 << 4;
+						instr_srli || instr_srl: reg_op1 <= reg_op1 >> 4;
+						instr_srai || instr_sra: reg_op1 <= $signed(reg_op1) >>> 4;
+					endcase
+					reg_sh <= reg_sh - 4;
+				end else begin
+					(* parallel_case, full_case *)
+					case (1'b1)
+						instr_slli || instr_sll: reg_op1 <= reg_op1 << 1;
+						instr_srli || instr_srl: reg_op1 <= reg_op1 >> 1;
+						instr_srai || instr_sra: reg_op1 <= $signed(reg_op1) >>> 1;
+					endcase
+					reg_sh <= reg_sh - 1;
+				end
+			end
+
+			cpu_state_stmem: begin
+				if (ENABLE_TRACE)
+					reg_out <= reg_op2;
+				if (!mem_do_prefetch || mem_done) begin
+					if (!mem_do_wdata) begin
+						(* parallel_case, full_case *)
+						case (1'b1)
+							instr_sb: mem_wordsize <= 2;
+							instr_sh: mem_wordsize <= 1;
+							instr_sw: mem_wordsize <= 0;
+						endcase
+						if (ENABLE_TRACE) begin
+							trace_valid <= 1;
+							trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_ADDR | ((reg_op1 + decoded_imm) & 32'hffffffff);
+						end
+						reg_op1 <= reg_op1 + decoded_imm;
+						set_mem_do_wdata = 1;
+					end
+					if (!mem_do_prefetch && mem_done) begin
+						cpu_state <= cpu_state_fetch;
+						decoder_trigger <= 1;
+						decoder_pseudo_trigger <= 1;
+					end
+				end
+			end
+
+			cpu_state_ldmem: begin
+				latched_store <= 1;
+				if (!mem_do_prefetch || mem_done) begin
+					if (!mem_do_rdata) begin
+						(* parallel_case, full_case *)
+						case (1'b1)
+							instr_lb || instr_lbu: mem_wordsize <= 2;
+							instr_lh || instr_lhu: mem_wordsize <= 1;
+							instr_lw: mem_wordsize <= 0;
+						endcase
+						latched_is_lu <= is_lbu_lhu_lw;
+						latched_is_lh <= instr_lh;
+						latched_is_lb <= instr_lb;
+						if (ENABLE_TRACE) begin
+							trace_valid <= 1;
+							trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_ADDR | ((reg_op1 + decoded_imm) & 32'hffffffff);
+						end
+						reg_op1 <= reg_op1 + decoded_imm;
+						set_mem_do_rdata = 1;
+					end
+					if (!mem_do_prefetch && mem_done) begin
+						(* parallel_case, full_case *)
+						case (1'b1)
+							latched_is_lu: reg_out <= mem_rdata_word;
+							latched_is_lh: reg_out <= $signed(mem_rdata_word[15:0]);
+							latched_is_lb: reg_out <= $signed(mem_rdata_word[7:0]);
+						endcase
+						decoder_trigger <= 1;
+						decoder_pseudo_trigger <= 1;
+						cpu_state <= cpu_state_fetch;
+					end
+				end
+			end
+		endcase
+
+		if (ENABLE_IRQ) begin
+			next_irq_pending = next_irq_pending | irq;
+			if(ENABLE_IRQ_TIMER && timer)
+				if (timer - 1 == 0)
+					next_irq_pending[irq_timer] = 1;
+		end
+
+		if (CATCH_MISALIGN && resetn && (mem_do_rdata || mem_do_wdata)) begin
+			if (mem_wordsize == 0 && reg_op1[1:0] != 0) begin
+				`debug($display("MISALIGNED WORD: 0x%08x", reg_op1);)
+				if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin
+					next_irq_pending[irq_buserror] = 1;
+				end else
+					cpu_state <= cpu_state_trap;
+			end
+			if (mem_wordsize == 1 && reg_op1[0] != 0) begin
+				`debug($display("MISALIGNED HALFWORD: 0x%08x", reg_op1);)
+				if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin
+					next_irq_pending[irq_buserror] = 1;
+				end else
+					cpu_state <= cpu_state_trap;
+			end
+		end
+		if (CATCH_MISALIGN && resetn && mem_do_rinst && (COMPRESSED_ISA ? reg_pc[0] : |reg_pc[1:0])) begin
+			`debug($display("MISALIGNED INSTRUCTION: 0x%08x", reg_pc);)
+			if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin
+				next_irq_pending[irq_buserror] = 1;
+			end else
+				cpu_state <= cpu_state_trap;
+		end
+		if (!CATCH_ILLINSN && decoder_trigger_q && !decoder_pseudo_trigger_q && instr_ecall_ebreak) begin
+			cpu_state <= cpu_state_trap;
+		end
+
+		if (!resetn || mem_done) begin
+			mem_do_prefetch <= 0;
+			mem_do_rinst <= 0;
+			mem_do_rdata <= 0;
+			mem_do_wdata <= 0;
+		end
+
+		if (set_mem_do_rinst)
+			mem_do_rinst <= 1;
+		if (set_mem_do_rdata)
+			mem_do_rdata <= 1;
+		if (set_mem_do_wdata)
+			mem_do_wdata <= 1;
+
+		irq_pending <= next_irq_pending & ~MASKED_IRQ;
+
+		if (!CATCH_MISALIGN) begin
+			if (COMPRESSED_ISA) begin
+				reg_pc[0] <= 0;
+				reg_next_pc[0] <= 0;
+			end else begin
+				reg_pc[1:0] <= 0;
+				reg_next_pc[1:0] <= 0;
+			end
+		end
+		current_pc = 'bx;
+	end
+
+`ifdef RISCV_FORMAL
+	reg dbg_irq_call;
+	reg dbg_irq_enter;
+	reg [31:0] dbg_irq_ret;
+	always @(posedge clk) begin
+		rvfi_valid <= resetn && (launch_next_insn || trap) && dbg_valid_insn;
+		rvfi_order <= resetn ? rvfi_order + rvfi_valid : 0;
+
+		rvfi_insn <= dbg_insn_opcode;
+		rvfi_rs1_addr <= dbg_rs1val_valid ? dbg_insn_rs1 : 0;
+		rvfi_rs2_addr <= dbg_rs2val_valid ? dbg_insn_rs2 : 0;
+		rvfi_pc_rdata <= dbg_insn_addr;
+		rvfi_rs1_rdata <= dbg_rs1val_valid ? dbg_rs1val : 0;
+		rvfi_rs2_rdata <= dbg_rs2val_valid ? dbg_rs2val : 0;
+		rvfi_trap <= trap;
+		rvfi_halt <= trap;
+		rvfi_intr <= dbg_irq_enter;
+		rvfi_mode <= 3;
+		rvfi_ixl <= 1;
+
+		if (!resetn) begin
+			dbg_irq_call <= 0;
+			dbg_irq_enter <= 0;
+		end else
+		if (rvfi_valid) begin
+			dbg_irq_call <= 0;
+			dbg_irq_enter <= dbg_irq_call;
+		end else
+		if (irq_state == 1) begin
+			dbg_irq_call <= 1;
+			dbg_irq_ret <= next_pc;
+		end
+
+		if (!resetn) begin
+			rvfi_rd_addr <= 0;
+			rvfi_rd_wdata <= 0;
+		end else
+		if (cpuregs_write && !irq_state) begin
+`ifdef PICORV32_TESTBUG_003
+			rvfi_rd_addr <= latched_rd ^ 1;
+`else
+			rvfi_rd_addr <= latched_rd;
+`endif
+`ifdef PICORV32_TESTBUG_004
+			rvfi_rd_wdata <= latched_rd ? cpuregs_wrdata ^ 1 : 0;
+`else
+			rvfi_rd_wdata <= latched_rd ? cpuregs_wrdata : 0;
+`endif
+		end else
+		if (rvfi_valid) begin
+			rvfi_rd_addr <= 0;
+			rvfi_rd_wdata <= 0;
+		end
+
+		casez (dbg_insn_opcode)
+			32'b 0000000_?????_000??_???_?????_0001011: begin // getq
+				rvfi_rs1_addr <= 0;
+				rvfi_rs1_rdata <= 0;
+			end
+			32'b 0000001_?????_?????_???_000??_0001011: begin // setq
+				rvfi_rd_addr <= 0;
+				rvfi_rd_wdata <= 0;
+			end
+			32'b 0000010_?????_00000_???_00000_0001011: begin // retirq
+				rvfi_rs1_addr <= 0;
+				rvfi_rs1_rdata <= 0;
+			end
+		endcase
+
+		if (!dbg_irq_call) begin
+			if (dbg_mem_instr) begin
+				rvfi_mem_addr <= 0;
+				rvfi_mem_rmask <= 0;
+				rvfi_mem_wmask <= 0;
+				rvfi_mem_rdata <= 0;
+				rvfi_mem_wdata <= 0;
+			end else
+			if (dbg_mem_valid && dbg_mem_ready) begin
+				rvfi_mem_addr <= dbg_mem_addr;
+				rvfi_mem_rmask <= dbg_mem_wstrb ? 0 : ~0;
+				rvfi_mem_wmask <= dbg_mem_wstrb;
+				rvfi_mem_rdata <= dbg_mem_rdata;
+				rvfi_mem_wdata <= dbg_mem_wdata;
+			end
+		end
+	end
+
+	always @* begin
+`ifdef PICORV32_TESTBUG_005
+		rvfi_pc_wdata = (dbg_irq_call ? dbg_irq_ret : dbg_insn_addr) ^ 4;
+`else
+		rvfi_pc_wdata = dbg_irq_call ? dbg_irq_ret : dbg_insn_addr;
+`endif
+
+		rvfi_csr_mcycle_rmask = 0;
+		rvfi_csr_mcycle_wmask = 0;
+		rvfi_csr_mcycle_rdata = 0;
+		rvfi_csr_mcycle_wdata = 0;
+
+		rvfi_csr_minstret_rmask = 0;
+		rvfi_csr_minstret_wmask = 0;
+		rvfi_csr_minstret_rdata = 0;
+		rvfi_csr_minstret_wdata = 0;
+
+		if (rvfi_valid && rvfi_insn[6:0] == 7'b 1110011 && rvfi_insn[13:12] == 3'b010) begin
+			if (rvfi_insn[31:20] == 12'h C00) begin
+				rvfi_csr_mcycle_rmask = 64'h 0000_0000_FFFF_FFFF;
+				rvfi_csr_mcycle_rdata = {32'h 0000_0000, rvfi_rd_wdata};
+			end
+			if (rvfi_insn[31:20] == 12'h C80) begin
+				rvfi_csr_mcycle_rmask = 64'h FFFF_FFFF_0000_0000;
+				rvfi_csr_mcycle_rdata = {rvfi_rd_wdata, 32'h 0000_0000};
+			end
+			if (rvfi_insn[31:20] == 12'h C02) begin
+				rvfi_csr_minstret_rmask = 64'h 0000_0000_FFFF_FFFF;
+				rvfi_csr_minstret_rdata = {32'h 0000_0000, rvfi_rd_wdata};
+			end
+			if (rvfi_insn[31:20] == 12'h C82) begin
+				rvfi_csr_minstret_rmask = 64'h FFFF_FFFF_0000_0000;
+				rvfi_csr_minstret_rdata = {rvfi_rd_wdata, 32'h 0000_0000};
+			end
+		end
+	end
+`endif
+
+	// Formal Verification
+`ifdef FORMAL
+	reg [3:0] last_mem_nowait;
+	always @(posedge clk)
+		last_mem_nowait <= {last_mem_nowait, mem_ready || !mem_valid};
+
+	// stall the memory interface for max 4 cycles
+	restrict property (|last_mem_nowait || mem_ready || !mem_valid);
+
+	// resetn low in first cycle, after that resetn high
+	restrict property (resetn != $initstate);
+
+	// this just makes it much easier to read traces. uncomment as needed.
+	// assume property (mem_valid || !mem_ready);
+
+	reg ok;
+	always @* begin
+		if (resetn) begin
+			// instruction fetches are read-only
+			if (mem_valid && mem_instr)
+				assert (mem_wstrb == 0);
+
+			// cpu_state must be valid
+			ok = 0;
+			if (cpu_state == cpu_state_trap)   ok = 1;
+			if (cpu_state == cpu_state_fetch)  ok = 1;
+			if (cpu_state == cpu_state_ld_rs1) ok = 1;
+			if (cpu_state == cpu_state_ld_rs2) ok = !ENABLE_REGS_DUALPORT;
+			if (cpu_state == cpu_state_exec)   ok = 1;
+			if (cpu_state == cpu_state_shift)  ok = 1;
+			if (cpu_state == cpu_state_stmem)  ok = 1;
+			if (cpu_state == cpu_state_ldmem)  ok = 1;
+			assert (ok);
+		end
+	end
+
+	reg last_mem_la_read = 0;
+	reg last_mem_la_write = 0;
+	reg [31:0] last_mem_la_addr;
+	reg [31:0] last_mem_la_wdata;
+	reg [3:0] last_mem_la_wstrb = 0;
+
+	always @(posedge clk) begin
+		last_mem_la_read <= mem_la_read;
+		last_mem_la_write <= mem_la_write;
+		last_mem_la_addr <= mem_la_addr;
+		last_mem_la_wdata <= mem_la_wdata;
+		last_mem_la_wstrb <= mem_la_wstrb;
+
+		if (last_mem_la_read) begin
+			assert(mem_valid);
+			assert(mem_addr == last_mem_la_addr);
+			assert(mem_wstrb == 0);
+		end
+		if (last_mem_la_write) begin
+			assert(mem_valid);
+			assert(mem_addr == last_mem_la_addr);
+			assert(mem_wdata == last_mem_la_wdata);
+			assert(mem_wstrb == last_mem_la_wstrb);
+		end
+		if (mem_la_read || mem_la_write) begin
+			assert(!mem_valid || mem_ready);
+		end
+	end
+`endif
+endmodule
+
+// This is a simple example implementation of PICORV32_REGS.
+// Use the PICORV32_REGS mechanism if you want to use custom
+// memory resources to implement the processor register file.
+// Note that your implementation must match the requirements of
+// the PicoRV32 configuration. (e.g. QREGS, etc)
+module picorv32_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:30];
+
+	always @(posedge clk)
+		if (wen) regs[~waddr[4:0]] <= wdata;
+
+	assign rdata1 = regs[~raddr1[4:0]];
+	assign rdata2 = regs[~raddr2[4:0]];
+endmodule
+
+
+/***************************************************************
+ * picorv32_pcpi_mul
+ ***************************************************************/
+
+module picorv32_pcpi_mul #(
+	parameter STEPS_AT_ONCE = 1,
+	parameter CARRY_CHAIN = 4
+) (
+	input clk, resetn,
+
+	input             pcpi_valid,
+	input      [31:0] pcpi_insn,
+	input      [31:0] pcpi_rs1,
+	input      [31:0] pcpi_rs2,
+	output reg        pcpi_wr,
+	output reg [31:0] pcpi_rd,
+	output reg        pcpi_wait,
+	output reg        pcpi_ready
+);
+	reg instr_mul, instr_mulh, instr_mulhsu, instr_mulhu;
+	wire instr_any_mul = |{instr_mul, instr_mulh, instr_mulhsu, instr_mulhu};
+	wire instr_any_mulh = |{instr_mulh, instr_mulhsu, instr_mulhu};
+	wire instr_rs1_signed = |{instr_mulh, instr_mulhsu};
+	wire instr_rs2_signed = |{instr_mulh};
+
+	reg pcpi_wait_q;
+	wire mul_start = pcpi_wait && !pcpi_wait_q;
+
+	always @(posedge clk) begin
+		instr_mul <= 0;
+		instr_mulh <= 0;
+		instr_mulhsu <= 0;
+		instr_mulhu <= 0;
+
+		if (resetn && pcpi_valid && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001) begin
+			case (pcpi_insn[14:12])
+				3'b000: instr_mul <= 1;
+				3'b001: instr_mulh <= 1;
+				3'b010: instr_mulhsu <= 1;
+				3'b011: instr_mulhu <= 1;
+			endcase
+		end
+
+		pcpi_wait <= instr_any_mul;
+		pcpi_wait_q <= pcpi_wait;
+	end
+
+	reg [63:0] rs1, rs2, rd, rdx;
+	reg [63:0] next_rs1, next_rs2, this_rs2;
+	reg [63:0] next_rd, next_rdx, next_rdt;
+	reg [6:0] mul_counter;
+	reg mul_waiting;
+	reg mul_finish;
+	integer i, j;
+
+	// carry save accumulator
+	always @* begin
+		next_rd = rd;
+		next_rdx = rdx;
+		next_rs1 = rs1;
+		next_rs2 = rs2;
+
+		for (i = 0; i < STEPS_AT_ONCE; i=i+1) begin
+			this_rs2 = next_rs1[0] ? next_rs2 : 0;
+			if (CARRY_CHAIN == 0) begin
+				next_rdt = next_rd ^ next_rdx ^ this_rs2;
+				next_rdx = ((next_rd & next_rdx) | (next_rd & this_rs2) | (next_rdx & this_rs2)) << 1;
+				next_rd = next_rdt;
+			end else begin
+				next_rdt = 0;
+				for (j = 0; j < 64; j = j + CARRY_CHAIN)
+					{next_rdt[j+CARRY_CHAIN-1], next_rd[j +: CARRY_CHAIN]} =
+							next_rd[j +: CARRY_CHAIN] + next_rdx[j +: CARRY_CHAIN] + this_rs2[j +: CARRY_CHAIN];
+				next_rdx = next_rdt << 1;
+			end
+			next_rs1 = next_rs1 >> 1;
+			next_rs2 = next_rs2 << 1;
+		end
+	end
+
+	always @(posedge clk) begin
+		mul_finish <= 0;
+		if (!resetn) begin
+			mul_waiting <= 1;
+			mul_counter <= 0;
+		end else
+		if (mul_waiting) begin
+			if (instr_rs1_signed)
+				rs1 <= $signed(pcpi_rs1);
+			else
+				rs1 <= $unsigned(pcpi_rs1);
+
+			if (instr_rs2_signed)
+				rs2 <= $signed(pcpi_rs2);
+			else
+				rs2 <= $unsigned(pcpi_rs2);
+
+			rd <= 0;
+			rdx <= 0;
+			mul_counter <= (instr_any_mulh ? 63 - STEPS_AT_ONCE : 31 - STEPS_AT_ONCE);
+			mul_waiting <= !mul_start;
+		end else begin
+			rd <= next_rd;
+			rdx <= next_rdx;
+			rs1 <= next_rs1;
+			rs2 <= next_rs2;
+
+			mul_counter <= mul_counter - STEPS_AT_ONCE;
+			if (mul_counter[6]) begin
+				mul_finish <= 1;
+				mul_waiting <= 1;
+			end
+		end
+	end
+
+	always @(posedge clk) begin
+		pcpi_wr <= 0;
+		pcpi_ready <= 0;
+		if (mul_finish && resetn) begin
+			pcpi_wr <= 1;
+			pcpi_ready <= 1;
+			pcpi_rd <= instr_any_mulh ? rd >> 32 : rd;
+		end
+	end
+endmodule
+
+module picorv32_pcpi_fast_mul #(
+	parameter EXTRA_MUL_FFS = 0,
+	parameter EXTRA_INSN_FFS = 0,
+	parameter MUL_CLKGATE = 0
+) (
+	input clk, resetn,
+
+	input             pcpi_valid,
+	input      [31:0] pcpi_insn,
+	input      [31:0] pcpi_rs1,
+	input      [31:0] pcpi_rs2,
+	output            pcpi_wr,
+	output     [31:0] pcpi_rd,
+	output            pcpi_wait,
+	output            pcpi_ready
+);
+	reg instr_mul, instr_mulh, instr_mulhsu, instr_mulhu;
+	wire instr_any_mul = |{instr_mul, instr_mulh, instr_mulhsu, instr_mulhu};
+	wire instr_any_mulh = |{instr_mulh, instr_mulhsu, instr_mulhu};
+	wire instr_rs1_signed = |{instr_mulh, instr_mulhsu};
+	wire instr_rs2_signed = |{instr_mulh};
+
+	reg shift_out;
+	reg [3:0] active;
+	reg [32:0] rs1, rs2, rs1_q, rs2_q;
+	reg [63:0] rd, rd_q;
+
+	wire pcpi_insn_valid = pcpi_valid && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001;
+	reg pcpi_insn_valid_q;
+
+	always @* begin
+		instr_mul = 0;
+		instr_mulh = 0;
+		instr_mulhsu = 0;
+		instr_mulhu = 0;
+
+		if (resetn && (EXTRA_INSN_FFS ? pcpi_insn_valid_q : pcpi_insn_valid)) begin
+			case (pcpi_insn[14:12])
+				3'b000: instr_mul = 1;
+				3'b001: instr_mulh = 1;
+				3'b010: instr_mulhsu = 1;
+				3'b011: instr_mulhu = 1;
+			endcase
+		end
+	end
+
+	always @(posedge clk) begin
+		pcpi_insn_valid_q <= pcpi_insn_valid;
+		if (!MUL_CLKGATE || active[0]) begin
+			rs1_q <= rs1;
+			rs2_q <= rs2;
+		end
+		if (!MUL_CLKGATE || active[1]) begin
+			rd <= $signed(EXTRA_MUL_FFS ? rs1_q : rs1) * $signed(EXTRA_MUL_FFS ? rs2_q : rs2);
+		end
+		if (!MUL_CLKGATE || active[2]) begin
+			rd_q <= rd;
+		end
+	end
+
+	always @(posedge clk) begin
+		if (instr_any_mul && !(EXTRA_MUL_FFS ? active[3:0] : active[1:0])) begin
+			if (instr_rs1_signed)
+				rs1 <= $signed(pcpi_rs1);
+			else
+				rs1 <= $unsigned(pcpi_rs1);
+
+			if (instr_rs2_signed)
+				rs2 <= $signed(pcpi_rs2);
+			else
+				rs2 <= $unsigned(pcpi_rs2);
+			active[0] <= 1;
+		end else begin
+			active[0] <= 0;
+		end
+
+		active[3:1] <= active;
+		shift_out <= instr_any_mulh;
+
+		if (!resetn)
+			active <= 0;
+	end
+
+	assign pcpi_wr = active[EXTRA_MUL_FFS ? 3 : 1];
+	assign pcpi_wait = 0;
+	assign pcpi_ready = active[EXTRA_MUL_FFS ? 3 : 1];
+`ifdef RISCV_FORMAL_ALTOPS
+	assign pcpi_rd =
+			instr_mul    ? (pcpi_rs1 + pcpi_rs2) ^ 32'h5876063e :
+			instr_mulh   ? (pcpi_rs1 + pcpi_rs2) ^ 32'hf6583fb7 :
+			instr_mulhsu ? (pcpi_rs1 - pcpi_rs2) ^ 32'hecfbe137 :
+			instr_mulhu  ? (pcpi_rs1 + pcpi_rs2) ^ 32'h949ce5e8 : 1'bx;
+`else
+	assign pcpi_rd = shift_out ? (EXTRA_MUL_FFS ? rd_q : rd) >> 32 : (EXTRA_MUL_FFS ? rd_q : rd);
+`endif
+endmodule
+
+
+/***************************************************************
+ * picorv32_pcpi_div
+ ***************************************************************/
+
+module picorv32_pcpi_div (
+	input clk, resetn,
+
+	input             pcpi_valid,
+	input      [31:0] pcpi_insn,
+	input      [31:0] pcpi_rs1,
+	input      [31:0] pcpi_rs2,
+	output reg        pcpi_wr,
+	output reg [31:0] pcpi_rd,
+	output reg        pcpi_wait,
+	output reg        pcpi_ready
+);
+	reg instr_div, instr_divu, instr_rem, instr_remu;
+	wire instr_any_div_rem = |{instr_div, instr_divu, instr_rem, instr_remu};
+
+	reg pcpi_wait_q;
+	wire start = pcpi_wait && !pcpi_wait_q;
+
+	always @(posedge clk) begin
+		instr_div <= 0;
+		instr_divu <= 0;
+		instr_rem <= 0;
+		instr_remu <= 0;
+
+		if (resetn && pcpi_valid && !pcpi_ready && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001) begin
+			case (pcpi_insn[14:12])
+				3'b100: instr_div <= 1;
+				3'b101: instr_divu <= 1;
+				3'b110: instr_rem <= 1;
+				3'b111: instr_remu <= 1;
+			endcase
+		end
+
+		pcpi_wait <= instr_any_div_rem && resetn;
+		pcpi_wait_q <= pcpi_wait && resetn;
+	end
+
+	reg [31:0] dividend;
+	reg [62:0] divisor;
+	reg [31:0] quotient;
+	reg [31:0] quotient_msk;
+	reg running;
+	reg outsign;
+
+	always @(posedge clk) begin
+		pcpi_ready <= 0;
+		pcpi_wr <= 0;
+		pcpi_rd <= 'bx;
+
+		if (!resetn) begin
+			running <= 0;
+		end else
+		if (start) begin
+			running <= 1;
+			dividend <= (instr_div || instr_rem) && pcpi_rs1[31] ? -pcpi_rs1 : pcpi_rs1;
+			divisor <= ((instr_div || instr_rem) && pcpi_rs2[31] ? -pcpi_rs2 : pcpi_rs2) << 31;
+			outsign <= (instr_div && (pcpi_rs1[31] != pcpi_rs2[31]) && |pcpi_rs2) || (instr_rem && pcpi_rs1[31]);
+			quotient <= 0;
+			quotient_msk <= 1 << 31;
+		end else
+		if (!quotient_msk && running) begin
+			running <= 0;
+			pcpi_ready <= 1;
+			pcpi_wr <= 1;
+`ifdef RISCV_FORMAL_ALTOPS
+			case (1)
+				instr_div:  pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h7f8529ec;
+				instr_divu: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h10e8fd70;
+				instr_rem:  pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h8da68fa5;
+				instr_remu: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h3138d0e1;
+			endcase
+`else
+			if (instr_div || instr_divu)
+				pcpi_rd <= outsign ? -quotient : quotient;
+			else
+				pcpi_rd <= outsign ? -dividend : dividend;
+`endif
+		end else begin
+			if (divisor <= dividend) begin
+				dividend <= dividend - divisor;
+				quotient <= quotient | quotient_msk;
+			end
+			divisor <= divisor >> 1;
+`ifdef RISCV_FORMAL_ALTOPS
+			quotient_msk <= quotient_msk >> 5;
+`else
+			quotient_msk <= quotient_msk >> 1;
+`endif
+		end
+	end
+endmodule
+
+
+/***************************************************************
+ * picorv32_axi
+ ***************************************************************/
+
+module picorv32_axi #(
+	parameter [ 0:0] ENABLE_COUNTERS = 1,
+	parameter [ 0:0] ENABLE_COUNTERS64 = 1,
+	parameter [ 0:0] ENABLE_REGS_16_31 = 1,
+	parameter [ 0:0] ENABLE_REGS_DUALPORT = 1,
+	parameter [ 0:0] TWO_STAGE_SHIFT = 1,
+	parameter [ 0:0] BARREL_SHIFTER = 0,
+	parameter [ 0:0] TWO_CYCLE_COMPARE = 0,
+	parameter [ 0:0] TWO_CYCLE_ALU = 0,
+	parameter [ 0:0] COMPRESSED_ISA = 0,
+	parameter [ 0:0] CATCH_MISALIGN = 1,
+	parameter [ 0:0] CATCH_ILLINSN = 1,
+	parameter [ 0:0] ENABLE_PCPI = 0,
+	parameter [ 0:0] ENABLE_MUL = 0,
+	parameter [ 0:0] ENABLE_FAST_MUL = 0,
+	parameter [ 0:0] ENABLE_DIV = 0,
+	parameter [ 0:0] ENABLE_IRQ = 0,
+	parameter [ 0:0] ENABLE_IRQ_QREGS = 1,
+	parameter [ 0:0] ENABLE_IRQ_TIMER = 1,
+	parameter [ 0:0] ENABLE_TRACE = 0,
+	parameter [ 0:0] REGS_INIT_ZERO = 0,
+	parameter [31:0] MASKED_IRQ = 32'h 0000_0000,
+	parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff,
+	parameter [31:0] PROGADDR_RESET = 32'h 0000_0000,
+	parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010,
+	parameter [31:0] STACKADDR = 32'h ffff_ffff
+) (
+	input clk, resetn,
+	output trap,
+
+	// AXI4-lite master memory interface
+
+	output        mem_axi_awvalid,
+	input         mem_axi_awready,
+	output [31:0] mem_axi_awaddr,
+	output [ 2:0] mem_axi_awprot,
+
+	output        mem_axi_wvalid,
+	input         mem_axi_wready,
+	output [31:0] mem_axi_wdata,
+	output [ 3:0] mem_axi_wstrb,
+
+	input         mem_axi_bvalid,
+	output        mem_axi_bready,
+
+	output        mem_axi_arvalid,
+	input         mem_axi_arready,
+	output [31:0] mem_axi_araddr,
+	output [ 2:0] mem_axi_arprot,
+
+	input         mem_axi_rvalid,
+	output        mem_axi_rready,
+	input  [31:0] mem_axi_rdata,
+
+	// Pico Co-Processor Interface (PCPI)
+	output        pcpi_valid,
+	output [31:0] pcpi_insn,
+	output [31:0] pcpi_rs1,
+	output [31:0] pcpi_rs2,
+	input         pcpi_wr,
+	input  [31:0] pcpi_rd,
+	input         pcpi_wait,
+	input         pcpi_ready,
+
+	// IRQ interface
+	input  [31:0] irq,
+	output [31:0] eoi,
+
+`ifdef RISCV_FORMAL
+	output        rvfi_valid,
+	output [63:0] rvfi_order,
+	output [31:0] rvfi_insn,
+	output        rvfi_trap,
+	output        rvfi_halt,
+	output        rvfi_intr,
+	output [ 4:0] rvfi_rs1_addr,
+	output [ 4:0] rvfi_rs2_addr,
+	output [31:0] rvfi_rs1_rdata,
+	output [31:0] rvfi_rs2_rdata,
+	output [ 4:0] rvfi_rd_addr,
+	output [31:0] rvfi_rd_wdata,
+	output [31:0] rvfi_pc_rdata,
+	output [31:0] rvfi_pc_wdata,
+	output [31:0] rvfi_mem_addr,
+	output [ 3:0] rvfi_mem_rmask,
+	output [ 3:0] rvfi_mem_wmask,
+	output [31:0] rvfi_mem_rdata,
+	output [31:0] rvfi_mem_wdata,
+`endif
+
+	// Trace Interface
+	output        trace_valid,
+	output [35:0] trace_data
+);
+	wire        mem_valid;
+	wire [31:0] mem_addr;
+	wire [31:0] mem_wdata;
+	wire [ 3:0] mem_wstrb;
+	wire        mem_instr;
+	wire        mem_ready;
+	wire [31:0] mem_rdata;
+
+	picorv32_axi_adapter axi_adapter (
+		.clk            (clk            ),
+		.resetn         (resetn         ),
+		.mem_axi_awvalid(mem_axi_awvalid),
+		.mem_axi_awready(mem_axi_awready),
+		.mem_axi_awaddr (mem_axi_awaddr ),
+		.mem_axi_awprot (mem_axi_awprot ),
+		.mem_axi_wvalid (mem_axi_wvalid ),
+		.mem_axi_wready (mem_axi_wready ),
+		.mem_axi_wdata  (mem_axi_wdata  ),
+		.mem_axi_wstrb  (mem_axi_wstrb  ),
+		.mem_axi_bvalid (mem_axi_bvalid ),
+		.mem_axi_bready (mem_axi_bready ),
+		.mem_axi_arvalid(mem_axi_arvalid),
+		.mem_axi_arready(mem_axi_arready),
+		.mem_axi_araddr (mem_axi_araddr ),
+		.mem_axi_arprot (mem_axi_arprot ),
+		.mem_axi_rvalid (mem_axi_rvalid ),
+		.mem_axi_rready (mem_axi_rready ),
+		.mem_axi_rdata  (mem_axi_rdata  ),
+		.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      )
+	);
+
+	picorv32 #(
+		.ENABLE_COUNTERS     (ENABLE_COUNTERS     ),
+		.ENABLE_COUNTERS64   (ENABLE_COUNTERS64   ),
+		.ENABLE_REGS_16_31   (ENABLE_REGS_16_31   ),
+		.ENABLE_REGS_DUALPORT(ENABLE_REGS_DUALPORT),
+		.TWO_STAGE_SHIFT     (TWO_STAGE_SHIFT     ),
+		.BARREL_SHIFTER      (BARREL_SHIFTER      ),
+		.TWO_CYCLE_COMPARE   (TWO_CYCLE_COMPARE   ),
+		.TWO_CYCLE_ALU       (TWO_CYCLE_ALU       ),
+		.COMPRESSED_ISA      (COMPRESSED_ISA      ),
+		.CATCH_MISALIGN      (CATCH_MISALIGN      ),
+		.CATCH_ILLINSN       (CATCH_ILLINSN       ),
+		.ENABLE_PCPI         (ENABLE_PCPI         ),
+		.ENABLE_MUL          (ENABLE_MUL          ),
+		.ENABLE_FAST_MUL     (ENABLE_FAST_MUL     ),
+		.ENABLE_DIV          (ENABLE_DIV          ),
+		.ENABLE_IRQ          (ENABLE_IRQ          ),
+		.ENABLE_IRQ_QREGS    (ENABLE_IRQ_QREGS    ),
+		.ENABLE_IRQ_TIMER    (ENABLE_IRQ_TIMER    ),
+		.ENABLE_TRACE        (ENABLE_TRACE        ),
+		.REGS_INIT_ZERO      (REGS_INIT_ZERO      ),
+		.MASKED_IRQ          (MASKED_IRQ          ),
+		.LATCHED_IRQ         (LATCHED_IRQ         ),
+		.PROGADDR_RESET      (PROGADDR_RESET      ),
+		.PROGADDR_IRQ        (PROGADDR_IRQ        ),
+		.STACKADDR           (STACKADDR           )
+	) picorv32_core (
+		.clk      (clk   ),
+		.resetn   (resetn),
+		.trap     (trap  ),
+
+		.mem_valid(mem_valid),
+		.mem_addr (mem_addr ),
+		.mem_wdata(mem_wdata),
+		.mem_wstrb(mem_wstrb),
+		.mem_instr(mem_instr),
+		.mem_ready(mem_ready),
+		.mem_rdata(mem_rdata),
+
+		.pcpi_valid(pcpi_valid),
+		.pcpi_insn (pcpi_insn ),
+		.pcpi_rs1  (pcpi_rs1  ),
+		.pcpi_rs2  (pcpi_rs2  ),
+		.pcpi_wr   (pcpi_wr   ),
+		.pcpi_rd   (pcpi_rd   ),
+		.pcpi_wait (pcpi_wait ),
+		.pcpi_ready(pcpi_ready),
+
+		.irq(irq),
+		.eoi(eoi),
+
+`ifdef RISCV_FORMAL
+		.rvfi_valid    (rvfi_valid    ),
+		.rvfi_order    (rvfi_order    ),
+		.rvfi_insn     (rvfi_insn     ),
+		.rvfi_trap     (rvfi_trap     ),
+		.rvfi_halt     (rvfi_halt     ),
+		.rvfi_intr     (rvfi_intr     ),
+		.rvfi_rs1_addr (rvfi_rs1_addr ),
+		.rvfi_rs2_addr (rvfi_rs2_addr ),
+		.rvfi_rs1_rdata(rvfi_rs1_rdata),
+		.rvfi_rs2_rdata(rvfi_rs2_rdata),
+		.rvfi_rd_addr  (rvfi_rd_addr  ),
+		.rvfi_rd_wdata (rvfi_rd_wdata ),
+		.rvfi_pc_rdata (rvfi_pc_rdata ),
+		.rvfi_pc_wdata (rvfi_pc_wdata ),
+		.rvfi_mem_addr (rvfi_mem_addr ),
+		.rvfi_mem_rmask(rvfi_mem_rmask),
+		.rvfi_mem_wmask(rvfi_mem_wmask),
+		.rvfi_mem_rdata(rvfi_mem_rdata),
+		.rvfi_mem_wdata(rvfi_mem_wdata),
+`endif
+
+		.trace_valid(trace_valid),
+		.trace_data (trace_data)
+	);
+endmodule
+
+
+/***************************************************************
+ * picorv32_axi_adapter
+ ***************************************************************/
+
+module picorv32_axi_adapter (
+	input clk, resetn,
+
+	// AXI4-lite master memory interface
+
+	output        mem_axi_awvalid,
+	input         mem_axi_awready,
+	output [31:0] mem_axi_awaddr,
+	output [ 2:0] mem_axi_awprot,
+
+	output        mem_axi_wvalid,
+	input         mem_axi_wready,
+	output [31:0] mem_axi_wdata,
+	output [ 3:0] mem_axi_wstrb,
+
+	input         mem_axi_bvalid,
+	output        mem_axi_bready,
+
+	output        mem_axi_arvalid,
+	input         mem_axi_arready,
+	output [31:0] mem_axi_araddr,
+	output [ 2:0] mem_axi_arprot,
+
+	input         mem_axi_rvalid,
+	output        mem_axi_rready,
+	input  [31:0] mem_axi_rdata,
+
+	// Native PicoRV32 memory interface
+
+	input         mem_valid,
+	input         mem_instr,
+	output        mem_ready,
+	input  [31:0] mem_addr,
+	input  [31:0] mem_wdata,
+	input  [ 3:0] mem_wstrb,
+	output [31:0] mem_rdata
+);
+	reg ack_awvalid;
+	reg ack_arvalid;
+	reg ack_wvalid;
+	reg xfer_done;
+
+	assign mem_axi_awvalid = mem_valid && |mem_wstrb && !ack_awvalid;
+	assign mem_axi_awaddr = mem_addr;
+	assign mem_axi_awprot = 0;
+
+	assign mem_axi_arvalid = mem_valid && !mem_wstrb && !ack_arvalid;
+	assign mem_axi_araddr = mem_addr;
+	assign mem_axi_arprot = mem_instr ? 3'b100 : 3'b000;
+
+	assign mem_axi_wvalid = mem_valid && |mem_wstrb && !ack_wvalid;
+	assign mem_axi_wdata = mem_wdata;
+	assign mem_axi_wstrb = mem_wstrb;
+
+	assign mem_ready = mem_axi_bvalid || mem_axi_rvalid;
+	assign mem_axi_bready = mem_valid && |mem_wstrb;
+	assign mem_axi_rready = mem_valid && !mem_wstrb;
+	assign mem_rdata = mem_axi_rdata;
+
+	always @(posedge clk) begin
+		if (!resetn) begin
+			ack_awvalid <= 0;
+		end else begin
+			xfer_done <= mem_valid && mem_ready;
+			if (mem_axi_awready && mem_axi_awvalid)
+				ack_awvalid <= 1;
+			if (mem_axi_arready && mem_axi_arvalid)
+				ack_arvalid <= 1;
+			if (mem_axi_wready && mem_axi_wvalid)
+				ack_wvalid <= 1;
+			if (xfer_done || !mem_valid) begin
+				ack_awvalid <= 0;
+				ack_arvalid <= 0;
+				ack_wvalid <= 0;
+			end
+		end
+	end
+endmodule
+
+
+/***************************************************************
+ * picorv32_wb
+ ***************************************************************/
+
+module picorv32_wb #(
+	parameter [ 0:0] ENABLE_COUNTERS = 1,
+	parameter [ 0:0] ENABLE_COUNTERS64 = 1,
+	parameter [ 0:0] ENABLE_REGS_16_31 = 1,
+	parameter [ 0:0] ENABLE_REGS_DUALPORT = 1,
+	parameter [ 0:0] TWO_STAGE_SHIFT = 1,
+	parameter [ 0:0] BARREL_SHIFTER = 0,
+	parameter [ 0:0] TWO_CYCLE_COMPARE = 0,
+	parameter [ 0:0] TWO_CYCLE_ALU = 0,
+	parameter [ 0:0] COMPRESSED_ISA = 0,
+	parameter [ 0:0] CATCH_MISALIGN = 1,
+	parameter [ 0:0] CATCH_ILLINSN = 1,
+	parameter [ 0:0] ENABLE_PCPI = 0,
+	parameter [ 0:0] ENABLE_MUL = 0,
+	parameter [ 0:0] ENABLE_FAST_MUL = 0,
+	parameter [ 0:0] ENABLE_DIV = 0,
+	parameter [ 0:0] ENABLE_IRQ = 0,
+	parameter [ 0:0] ENABLE_IRQ_QREGS = 1,
+	parameter [ 0:0] ENABLE_IRQ_TIMER = 1,
+	parameter [ 0:0] ENABLE_TRACE = 0,
+	parameter [ 0:0] REGS_INIT_ZERO = 0,
+	parameter [31:0] MASKED_IRQ = 32'h 0000_0000,
+	parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff,
+	parameter [31:0] PROGADDR_RESET = 32'h 0000_0000,
+	parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010,
+	parameter [31:0] STACKADDR = 32'h ffff_ffff
+) (
+	output trap,
+
+	// Wishbone interfaces
+	input wb_rst_i,
+	input wb_clk_i,
+
+	output reg [31:0] wbm_adr_o,
+	output reg [31:0] wbm_dat_o,
+	input [31:0] wbm_dat_i,
+	output reg wbm_we_o,
+	output reg [3:0] wbm_sel_o,
+	output reg wbm_stb_o,
+	input wbm_ack_i,
+	output reg wbm_cyc_o,
+
+	// Pico Co-Processor Interface (PCPI)
+	output        pcpi_valid,
+	output [31:0] pcpi_insn,
+	output [31:0] pcpi_rs1,
+	output [31:0] pcpi_rs2,
+	input         pcpi_wr,
+	input  [31:0] pcpi_rd,
+	input         pcpi_wait,
+	input         pcpi_ready,
+
+	// IRQ interface
+	input  [31:0] irq,
+	output [31:0] eoi,
+
+`ifdef RISCV_FORMAL
+	output        rvfi_valid,
+	output [63:0] rvfi_order,
+	output [31:0] rvfi_insn,
+	output        rvfi_trap,
+	output        rvfi_halt,
+	output        rvfi_intr,
+	output [ 4:0] rvfi_rs1_addr,
+	output [ 4:0] rvfi_rs2_addr,
+	output [31:0] rvfi_rs1_rdata,
+	output [31:0] rvfi_rs2_rdata,
+	output [ 4:0] rvfi_rd_addr,
+	output [31:0] rvfi_rd_wdata,
+	output [31:0] rvfi_pc_rdata,
+	output [31:0] rvfi_pc_wdata,
+	output [31:0] rvfi_mem_addr,
+	output [ 3:0] rvfi_mem_rmask,
+	output [ 3:0] rvfi_mem_wmask,
+	output [31:0] rvfi_mem_rdata,
+	output [31:0] rvfi_mem_wdata,
+`endif
+
+	// Trace Interface
+	output        trace_valid,
+	output [35:0] trace_data,
+
+	output mem_instr
+);
+	wire        mem_valid;
+	wire [31:0] mem_addr;
+	wire [31:0] mem_wdata;
+	wire [ 3:0] mem_wstrb;
+	reg         mem_ready;
+	reg [31:0] mem_rdata;
+
+	wire clk;
+	wire resetn;
+
+	assign clk = wb_clk_i;
+	assign resetn = ~wb_rst_i;
+
+	picorv32 #(
+		.ENABLE_COUNTERS     (ENABLE_COUNTERS     ),
+		.ENABLE_COUNTERS64   (ENABLE_COUNTERS64   ),
+		.ENABLE_REGS_16_31   (ENABLE_REGS_16_31   ),
+		.ENABLE_REGS_DUALPORT(ENABLE_REGS_DUALPORT),
+		.TWO_STAGE_SHIFT     (TWO_STAGE_SHIFT     ),
+		.BARREL_SHIFTER      (BARREL_SHIFTER      ),
+		.TWO_CYCLE_COMPARE   (TWO_CYCLE_COMPARE   ),
+		.TWO_CYCLE_ALU       (TWO_CYCLE_ALU       ),
+		.COMPRESSED_ISA      (COMPRESSED_ISA      ),
+		.CATCH_MISALIGN      (CATCH_MISALIGN      ),
+		.CATCH_ILLINSN       (CATCH_ILLINSN       ),
+		.ENABLE_PCPI         (ENABLE_PCPI         ),
+		.ENABLE_MUL          (ENABLE_MUL          ),
+		.ENABLE_FAST_MUL     (ENABLE_FAST_MUL     ),
+		.ENABLE_DIV          (ENABLE_DIV          ),
+		.ENABLE_IRQ          (ENABLE_IRQ          ),
+		.ENABLE_IRQ_QREGS    (ENABLE_IRQ_QREGS    ),
+		.ENABLE_IRQ_TIMER    (ENABLE_IRQ_TIMER    ),
+		.ENABLE_TRACE        (ENABLE_TRACE        ),
+		.REGS_INIT_ZERO      (REGS_INIT_ZERO      ),
+		.MASKED_IRQ          (MASKED_IRQ          ),
+		.LATCHED_IRQ         (LATCHED_IRQ         ),
+		.PROGADDR_RESET      (PROGADDR_RESET      ),
+		.PROGADDR_IRQ        (PROGADDR_IRQ        ),
+		.STACKADDR           (STACKADDR           )
+	) picorv32_core (
+		.clk      (clk   ),
+		.resetn   (resetn),
+		.trap     (trap  ),
+
+		.mem_valid(mem_valid),
+		.mem_addr (mem_addr ),
+		.mem_wdata(mem_wdata),
+		.mem_wstrb(mem_wstrb),
+		.mem_instr(mem_instr),
+		.mem_ready(mem_ready),
+		.mem_rdata(mem_rdata),
+
+		.pcpi_valid(pcpi_valid),
+		.pcpi_insn (pcpi_insn ),
+		.pcpi_rs1  (pcpi_rs1  ),
+		.pcpi_rs2  (pcpi_rs2  ),
+		.pcpi_wr   (pcpi_wr   ),
+		.pcpi_rd   (pcpi_rd   ),
+		.pcpi_wait (pcpi_wait ),
+		.pcpi_ready(pcpi_ready),
+
+		.irq(irq),
+		.eoi(eoi),
+
+`ifdef RISCV_FORMAL
+		.rvfi_valid    (rvfi_valid    ),
+		.rvfi_order    (rvfi_order    ),
+		.rvfi_insn     (rvfi_insn     ),
+		.rvfi_trap     (rvfi_trap     ),
+		.rvfi_halt     (rvfi_halt     ),
+		.rvfi_intr     (rvfi_intr     ),
+		.rvfi_rs1_addr (rvfi_rs1_addr ),
+		.rvfi_rs2_addr (rvfi_rs2_addr ),
+		.rvfi_rs1_rdata(rvfi_rs1_rdata),
+		.rvfi_rs2_rdata(rvfi_rs2_rdata),
+		.rvfi_rd_addr  (rvfi_rd_addr  ),
+		.rvfi_rd_wdata (rvfi_rd_wdata ),
+		.rvfi_pc_rdata (rvfi_pc_rdata ),
+		.rvfi_pc_wdata (rvfi_pc_wdata ),
+		.rvfi_mem_addr (rvfi_mem_addr ),
+		.rvfi_mem_rmask(rvfi_mem_rmask),
+		.rvfi_mem_wmask(rvfi_mem_wmask),
+		.rvfi_mem_rdata(rvfi_mem_rdata),
+		.rvfi_mem_wdata(rvfi_mem_wdata),
+`endif
+
+		.trace_valid(trace_valid),
+		.trace_data (trace_data)
+	);
+	// Wishbone Controller
+	localparam IDLE = 2'b00;
+	localparam WBSTART = 2'b01;
+	localparam WBEND = 2'b10;
+
+	reg [1:0] state;
+
+	wire we;
+	assign we = (mem_wstrb[0] | mem_wstrb[1] | mem_wstrb[2] | mem_wstrb[3]);
+
+	always @(posedge wb_clk_i) begin
+		if (wb_rst_i) begin
+			wbm_adr_o <= 0;
+			wbm_dat_o <= 0;
+			wbm_we_o <= 0;
+			wbm_sel_o <= 0;
+			wbm_stb_o <= 0;
+			wbm_cyc_o <= 0;
+			state <= IDLE;
+		end else begin
+			case (state)
+				IDLE: begin
+					if (mem_valid) begin
+						wbm_adr_o <= mem_addr;
+						wbm_dat_o <= mem_wdata;
+						wbm_we_o <= we;
+						wbm_sel_o <= mem_wstrb;
+
+						wbm_stb_o <= 1'b1;
+						wbm_cyc_o <= 1'b1;
+						state <= WBSTART;
+					end else begin
+						mem_ready <= 1'b0;
+
+						wbm_stb_o <= 1'b0;
+						wbm_cyc_o <= 1'b0;
+						wbm_we_o <= 1'b0;
+					end
+				end
+				WBSTART:begin
+					if (wbm_ack_i) begin
+						mem_rdata <= wbm_dat_i;
+						mem_ready <= 1'b1;
+
+						state <= WBEND;
+
+						wbm_stb_o <= 1'b0;
+						wbm_cyc_o <= 1'b0;
+						wbm_we_o <= 1'b0;
+					end
+				end
+				WBEND: begin
+					mem_ready <= 1'b0;
+
+					state <= IDLE;
+				end
+				default:
+					state <= IDLE;
+			endcase
+		end
+	end
+endmodule
+`default_nettype wire
diff --git a/verilog/rtl/softshell/third_party/picorv32_wb/simpleuart.v b/verilog/rtl/softshell/third_party/picorv32_wb/simpleuart.v
new file mode 100644
index 0000000..4fe9f0c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32_wb/simpleuart.v
@@ -0,0 +1,223 @@
+`default_nettype none
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+module simpleuart_wb # (
+    parameter BASE_ADR = 32'h 2000_0000,
+    parameter CLK_DIV = 8'h00,
+    parameter DATA = 8'h04,
+    parameter CONFIG = 8'h08
+) (
+    input wb_clk_i,
+    input wb_rst_i,
+
+    input [31:0] wb_adr_i,      // (verify): input address was originaly 22 bits , why ? (max number of words ?)
+    input [31:0] wb_dat_i,
+    input [3:0]  wb_sel_i,
+    input wb_we_i,
+    input wb_cyc_i,
+    input wb_stb_i,
+
+    output wb_ack_o,
+    output [31:0] wb_dat_o,
+
+    output uart_enabled,
+    output ser_tx,
+    input  ser_rx
+
+);
+    wire [31:0] simpleuart_reg_div_do;
+    wire [31:0] simpleuart_reg_dat_do;
+    wire [31:0] simpleuart_reg_cfg_do;
+    wire reg_dat_wait;
+
+    wire resetn = ~wb_rst_i;
+    wire valid = wb_stb_i && wb_cyc_i; 
+    wire simpleuart_reg_div_sel = valid && (wb_adr_i == (BASE_ADR | CLK_DIV));
+    wire simpleuart_reg_dat_sel = valid && (wb_adr_i == (BASE_ADR | DATA));
+    wire simpleuart_reg_cfg_sel = valid && (wb_adr_i == (BASE_ADR | CONFIG));
+
+    wire [3:0] reg_div_we = simpleuart_reg_div_sel ? (wb_sel_i & {4{wb_we_i}}): 4'b 0000; 
+    wire reg_dat_we = simpleuart_reg_dat_sel ? (wb_sel_i[0] & wb_we_i): 1'b 0;      // simpleuart_reg_dat_sel ? mem_wstrb[0] : 1'b 0
+    wire reg_cfg_we = simpleuart_reg_cfg_sel ? (wb_sel_i[0] & wb_we_i): 1'b 0; 
+
+    wire [31:0] mem_wdata = wb_dat_i;
+    wire reg_dat_re = simpleuart_reg_dat_sel && !wb_sel_i && ~wb_we_i; // read_enable
+
+    assign wb_dat_o = simpleuart_reg_div_sel ? simpleuart_reg_div_do:
+		      simpleuart_reg_cfg_sel ? simpleuart_reg_cfg_do:
+					       simpleuart_reg_dat_do;
+    assign wb_ack_o = (simpleuart_reg_div_sel || simpleuart_reg_dat_sel
+			|| simpleuart_reg_cfg_sel) && (!reg_dat_wait);
+    
+    simpleuart simpleuart (
+        .clk    (wb_clk_i),
+        .resetn (resetn),
+
+        .ser_tx      (ser_tx),
+        .ser_rx      (ser_rx),
+	.enabled     (uart_enabled),
+
+        .reg_div_we  (reg_div_we), 
+        .reg_div_di  (mem_wdata),
+        .reg_div_do  (simpleuart_reg_div_do),
+
+        .reg_cfg_we  (reg_cfg_we), 
+        .reg_cfg_di  (mem_wdata),
+        .reg_cfg_do  (simpleuart_reg_cfg_do),
+
+        .reg_dat_we  (reg_dat_we),
+        .reg_dat_re  (reg_dat_re),
+        .reg_dat_di  (mem_wdata),
+        .reg_dat_do  (simpleuart_reg_dat_do),
+        .reg_dat_wait(reg_dat_wait)
+    );
+
+endmodule
+
+module simpleuart (
+    input clk,
+    input resetn,
+
+    output enabled,
+    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_cfg_we,         
+    input  [31:0] reg_cfg_di,         
+    output [31:0] reg_cfg_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        enabled;
+
+    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;
+
+    wire reg_ena_do;
+
+    assign reg_div_do = cfg_divider;
+    assign reg_ena_do = {31'd0, enabled};
+
+    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 <= 1;
+	    enabled <= 1'b0;
+        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];
+            if (reg_cfg_we) enabled <= reg_div_di[0];
+        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 && enabled)
+                        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 && enabled)
+            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
+`default_nettype wire
diff --git a/verilog/rtl/softshell/third_party/picorv32_wb/spimemio.v b/verilog/rtl/softshell/third_party/picorv32_wb/spimemio.v
new file mode 100644
index 0000000..dc37126
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32_wb/spimemio.v
@@ -0,0 +1,743 @@
+`default_nettype none
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+module spimemio_wb (
+    input wb_clk_i,
+    input wb_rst_i,
+
+    input [31:0] wb_adr_i, 
+    input [31:0] wb_dat_i,
+    input [3:0] wb_sel_i,
+    input wb_we_i,
+    input wb_cyc_i,
+
+    input wb_flash_stb_i,
+    input wb_cfg_stb_i,
+
+    output wb_flash_ack_o,
+    output wb_cfg_ack_o,
+
+    output [31:0] wb_flash_dat_o,
+    output [31:0] wb_cfg_dat_o,
+
+    input  pass_thru,
+    input  pass_thru_csb,
+    input  pass_thru_sck,
+    input  pass_thru_sdi,
+    output pass_thru_sdo,
+
+    output flash_csb,
+    output flash_clk,
+
+    output flash_csb_oeb,
+    output flash_clk_oeb,
+
+    output flash_io0_oeb,
+    output flash_io1_oeb,
+    output flash_io2_oeb,
+    output flash_io3_oeb,
+
+    output flash_csb_ieb,
+    output flash_clk_ieb,
+
+    output flash_io0_ieb,
+    output flash_io1_ieb,
+    output flash_io2_ieb,
+    output flash_io3_ieb,
+
+    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
+
+);
+    wire spimem_ready;
+    wire [23:0] mem_addr;
+    wire [31:0] spimem_rdata;
+    wire [31:0] spimemio_cfgreg_do;
+    wire [3:0] cfgreg_we;
+    wire spimemio_cfgreg_sel;
+    wire valid;
+    wire resetn;
+
+    assign resetn = ~wb_rst_i;
+    assign valid = wb_cyc_i && wb_flash_stb_i;    
+    assign wb_flash_ack_o = spimem_ready;
+    assign wb_cfg_ack_o = spimemio_cfgreg_sel;
+
+    assign mem_addr = wb_adr_i[23:0];
+    assign spimemio_cfgreg_sel = wb_cyc_i && wb_cfg_stb_i;
+
+    assign cfgreg_we = spimemio_cfgreg_sel ? wb_sel_i & {4{wb_we_i}} : 4'b 0000;
+    assign wb_flash_dat_o = spimem_rdata;
+    assign wb_cfg_dat_o = spimemio_cfgreg_do;
+
+    spimemio spimemio (
+        .clk    (wb_clk_i),
+        .resetn (resetn),
+        .valid  (valid),
+        .ready  (spimem_ready),
+        .addr   (mem_addr),
+        .rdata  (spimem_rdata),
+
+        .flash_csb    (flash_csb),
+        .flash_clk    (flash_clk),
+
+        .flash_csb_oeb (flash_csb_oeb),
+        .flash_clk_oeb (flash_clk_oeb),
+
+        .flash_io0_oeb (flash_io0_oeb),
+        .flash_io1_oeb (flash_io1_oeb),
+        .flash_io2_oeb (flash_io2_oeb),
+        .flash_io3_oeb (flash_io3_oeb),
+
+        .flash_csb_ieb (flash_csb_ieb),
+        .flash_clk_ieb (flash_clk_ieb),
+
+        .flash_io0_ieb (flash_io0_ieb),
+        .flash_io1_ieb (flash_io1_ieb),
+        .flash_io2_ieb (flash_io2_ieb),
+        .flash_io3_ieb (flash_io3_ieb),
+
+        .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(cfgreg_we),
+        .cfgreg_di(wb_dat_i),
+        .cfgreg_do(spimemio_cfgreg_do),
+
+	.pass_thru(pass_thru),
+	.pass_thru_csb(pass_thru_csb),
+	.pass_thru_sck(pass_thru_sck),
+	.pass_thru_sdi(pass_thru_sdi),
+	.pass_thru_sdo(pass_thru_sdo)
+    );
+
+endmodule
+
+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_csb_oeb,
+    output flash_clk_oeb,
+
+    output flash_io0_oeb,
+    output flash_io1_oeb,
+    output flash_io2_oeb,
+    output flash_io3_oeb,
+
+    output flash_csb_ieb,
+    output flash_clk_ieb,
+
+    output flash_io0_ieb,
+    output flash_io1_ieb,
+    output flash_io2_ieb,
+    output flash_io3_ieb,
+
+    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,
+
+    input  pass_thru,
+    input  pass_thru_csb,
+    input  pass_thru_sck,
+    input  pass_thru_sdi,
+    output pass_thru_sdo
+);
+    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_oeb, ~flash_io2_oeb, ~flash_io1_oeb, ~flash_io0_oeb};
+    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
+
+    wire pass_thru;
+    wire pass_thru_csb;
+    wire pass_thru_sck;
+    wire pass_thru_sdi;
+    wire pass_thru_sdo;
+
+    assign flash_csb = (pass_thru) ? pass_thru_csb : (config_en ? xfer_csb : config_csb);
+    assign flash_clk = (pass_thru) ? pass_thru_sck : (config_en ? xfer_clk : config_clk);
+
+    assign flash_csb_oeb = (pass_thru) ? 1'b0 : (~resetn ? 1'b1 : 1'b0);
+    assign flash_clk_oeb = (pass_thru) ? 1'b0 : (~resetn ? 1'b1 : 1'b0);
+
+    assign flash_io0_oeb = pass_thru ? 1'b0 : ~resetn ? 1'b1 : (config_en ? ~xfer_io0_oe : ~config_oe[0]);
+    assign flash_io1_oeb = (pass_thru | ~resetn) ? 1'b1 : (config_en ? ~xfer_io1_oe : ~config_oe[1]);
+    assign flash_io2_oeb = (pass_thru | ~resetn) ? 1'b1 : (config_en ? ~xfer_io2_oe : ~config_oe[2]);
+    assign flash_io3_oeb = (pass_thru | ~resetn) ? 1'b1 : (config_en ? ~xfer_io3_oe : ~config_oe[3]);
+    assign flash_csb_ieb = 1'b1;	/* Always disabled */
+    assign flash_clk_ieb = 1'b1;	/* Always disabled */
+
+    assign flash_io0_ieb = (pass_thru | ~resetn) ? 1'b1 : (config_en ? xfer_io0_oe : config_oe[0]);
+    assign flash_io1_ieb = pass_thru ? 1'b0 : ~resetn ? 1'b1 : (config_en ? xfer_io1_oe : config_oe[1]);
+    assign flash_io2_ieb = (pass_thru | ~resetn) ? 1'b1 : (config_en ? xfer_io2_oe : config_oe[2]);
+    assign flash_io3_ieb = (pass_thru | ~resetn) ? 1'b1 : (config_en ? xfer_io3_oe : config_oe[3]);
+
+    assign flash_io0_do = pass_thru ? pass_thru_sdi : (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];
+    assign pass_thru_sdo = pass_thru ? flash_io1_di : 1'b0;
+
+    wire xfer_dspi = din_ddr && !din_qspi;
+    wire xfer_ddr = din_ddr && din_qspi;
+
+    spimemio_xfer xfer (
+        .clk          (clk         ),
+        .resetn       (resetn 	   ),
+        .xfer_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, xfer_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 && xfer_resetn && next_fetch;
+
+    assign dout_valid = (xfer_ddr_q ? fetch && !last_fetch : next_fetch && !fetch) && xfer_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 || !xfer_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
+
+`default_nettype wire
diff --git a/verilog/rtl/softshell/third_party/picorv32_wb/storage_bridge_wb.v b/verilog/rtl/softshell/third_party/picorv32_wb/storage_bridge_wb.v
new file mode 100644
index 0000000..bf70052
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32_wb/storage_bridge_wb.v
@@ -0,0 +1,97 @@
+`default_nettype none
+module storage_bridge_wb (
+    // MGMT_AREA R/W WB Interface
+    input wb_clk_i,
+    input wb_rst_i,
+
+    input [31:0] wb_adr_i,
+    input [31:0] wb_dat_i,
+    input [3:0]  wb_sel_i,
+    input wb_we_i,
+    input wb_cyc_i,
+    input [1:0] wb_stb_i,
+    output reg [1:0] wb_ack_o,
+    output reg [31:0] wb_rw_dat_o,
+
+    // MGMT_AREA RO WB Interface   
+    output [31:0] wb_ro_dat_o,
+
+    // MGMT Area native memory interface
+    output [`RAM_BLOCKS-1:0] mgmt_ena, 
+    output [(`RAM_BLOCKS*4)-1:0] mgmt_wen_mask,
+    output [`RAM_BLOCKS-1:0] mgmt_wen,
+    output [7:0] mgmt_addr,
+    output [31:0] mgmt_wdata,
+    input  [(`RAM_BLOCKS*32)-1:0] mgmt_rdata,
+
+    // MGMT_AREA RO Interface 
+    output mgmt_ena_ro,
+    output [7:0] mgmt_addr_ro,
+    input  [31:0] mgmt_rdata_ro
+);
+    parameter [(`RAM_BLOCKS*24)-1:0] RW_BLOCKS_ADR = {
+        {24'h 10_0000},
+        {24'h 00_0000}
+    };
+
+    parameter [23:0] RO_BLOCKS_ADR = {
+        {24'h 20_0000}
+    };
+
+    parameter ADR_MASK = 24'h FF_0000;
+
+    wire [1:0] valid;
+    wire [1:0] wen;
+    wire [7:0] wen_mask;
+
+    assign valid = {2{wb_cyc_i}} & wb_stb_i;
+    assign wen   = wb_we_i & valid;    
+    assign wen_mask = wb_sel_i & {{4{wen[1]}}, {4{wen[0]}}};
+
+    // Ack generation
+    reg [1:0] wb_ack_read;
+
+    always @(posedge wb_clk_i) begin
+        if (wb_rst_i == 1'b 1) begin
+            wb_ack_read <= 2'b0;
+            wb_ack_o <= 2'b0;
+        end else begin
+            wb_ack_o <= wb_we_i? (valid & ~wb_ack_o): wb_ack_read;
+            wb_ack_read <= (valid & ~wb_ack_o) & ~wb_ack_read;
+        end
+    end
+    
+    // Address decoding
+    wire [`RAM_BLOCKS-1: 0] rw_sel;
+    wire ro_sel;
+
+    genvar iS;
+    generate
+        for (iS = 0; iS < `RAM_BLOCKS; iS = iS + 1) begin
+            assign rw_sel[iS] = 
+                ((wb_adr_i[23:0] & ADR_MASK) == RW_BLOCKS_ADR[(iS+1)*24-1:iS*24]);
+        end
+    endgenerate
+
+    // Management R/W interface
+    assign mgmt_ena = valid[0] ? ~rw_sel : {`RAM_BLOCKS{1'b1}}; 
+    assign mgmt_wen = ~{`RAM_BLOCKS{wen[0]}};
+    assign mgmt_wen_mask = {`RAM_BLOCKS{wen_mask[3:0]}};
+    assign mgmt_addr  = wb_adr_i[9:2];
+    assign mgmt_wdata = wb_dat_i[31:0];
+
+    integer i;
+    always @(*) begin
+        wb_rw_dat_o = {32{1'b0}};
+        for (i=0; i<(`RAM_BLOCKS*32); i=i+1)
+            wb_rw_dat_o[i%32] = wb_rw_dat_o[i%32] | (rw_sel[i/32] & mgmt_rdata[i]);
+    end
+
+    // RO Interface
+    assign ro_sel = ((wb_adr_i[23:0] & ADR_MASK) == RO_BLOCKS_ADR);
+    assign mgmt_ena_ro = valid[1] ? ~ro_sel : 1'b1; 
+    assign mgmt_addr_ro = wb_adr_i[9:2];
+    assign wb_ro_dat_o = mgmt_rdata_ro;
+
+endmodule
+`default_nettype wire
diff --git a/verilog/rtl/softshell/third_party/picorv32_wb/wb_intercon.v b/verilog/rtl/softshell/third_party/picorv32_wb/wb_intercon.v
new file mode 100644
index 0000000..6c3ab52
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/picorv32_wb/wb_intercon.v
@@ -0,0 +1,59 @@
+`default_nettype none
+module wb_intercon #(
+    parameter DW = 32,          // Data Width
+    parameter AW = 32,          // Address Width
+    parameter NS = 6           // Number of Slaves
+) (
+    // Master Interface
+    input [AW-1:0] wbm_adr_i,
+    input wbm_stb_i,
+
+    output reg [DW-1:0] wbm_dat_o,
+    output wbm_ack_o,
+
+    // Slave Interface
+    input [NS*DW-1:0] wbs_dat_i,
+    input [NS-1:0] wbs_ack_i,
+    output [NS-1:0] wbs_stb_o
+);
+    parameter [NS*AW-1:0] ADR_MASK = {      // Page & Sub-page bits
+        {8'hFF, {24{1'b0}} },
+        {8'hFF, {24{1'b0}} },
+        {8'hFF, {24{1'b0}} },
+        {8'hFF, {24{1'b0}} },
+        {8'hFF, {24{1'b0}} },
+        {8'hFF, {24{1'b0}} }
+    };
+    parameter [NS*AW-1:0] SLAVE_ADR = {
+        { 32'h2800_0000 },    // Flash Configuration Register
+        { 32'h2200_0000 },    // System Control
+        { 32'h2100_0000 },    // GPIOs
+        { 32'h2000_0000 },    // UART 
+        { 32'h1000_0000 },    // Flash 
+        { 32'h0000_0000 }     // RAM
+    };
+    
+    wire [NS-1: 0] slave_sel;
+
+    // Address decoder
+    genvar iS;
+    generate
+        for (iS = 0; iS < NS; iS = iS + 1) begin
+            assign slave_sel[iS] = 
+                ((wbm_adr_i & ADR_MASK[(iS+1)*AW-1:iS*AW]) == SLAVE_ADR[(iS+1)*AW-1:iS*AW]);
+        end
+    endgenerate
+
+    // Data-out Assignment
+    assign wbm_ack_o = |(wbs_ack_i & slave_sel);
+    assign wbs_stb_o =  {NS{wbm_stb_i}} & slave_sel;
+
+    integer i;
+    always @(*) begin
+        wbm_dat_o = {DW{1'b0}};
+        for (i=0; i<(NS*DW); i=i+1)
+            wbm_dat_o[i%DW] = wbm_dat_o[i%DW] | (slave_sel[i/DW] & wbs_dat_i[i]);
+    end
+ 
+endmodule
+`default_nettype wire
diff --git a/verilog/rtl/softshell/third_party/rocc-software/xcustom.h b/verilog/rtl/softshell/third_party/rocc-software/xcustom.h
new file mode 100644
index 0000000..6f398fd
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/rocc-software/xcustom.h
@@ -0,0 +1,170 @@
+// Copyright 2018--2020 IBM
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ROCC_SOFTWARE_SRC_XCUSTOM_H_
+#define ROCC_SOFTWARE_SRC_XCUSTOM_H_
+
+#define STR1(x) #x
+#ifndef STR
+#define STR(x) STR1(x)
+#endif
+
+#define CAT_(A, B) A##B
+#define CAT(A, B) CAT_(A, B)
+
+/** Assembly macro for creating "raw" Rocket Custom Coproessor (RoCC)
+  * assembly language instructions that will return data in rd. These
+  * are to be used only in assembly language programs (not C/C++).
+  *
+  * Example:
+  *
+  * Consider the following macro consisting of a CUSTOM_0 instruction
+  * with func7 "42" that is doing some operation of "a0 = op(a1, a2)":
+  *
+  *     ROCC_INSTRUCTION_RAW_R_R_R(0, a0, a1, a2, 42)
+  *
+  * This will produce the following pseudo assembly language
+  * instruction:
+  *
+  *     .insn r CUSTOM_0, 7, 42, a0, a1, a2
+  *
+  * @param x the custom instruction number: 0, 1, 2, or 3
+  * @param rd the destination register, e.g., a0 or x10
+  * @param rs1 the first source register, e.g., a0 or x10
+  * @param rs2 the second source register, e.g., a0 or x10
+  * @param func7 the value of the func7 field
+  * @return a raw .insn RoCC instruction
+  */
+#define ROCC_INSTRUCTION_RAW_R_R_R(x, rd, rs1, rs2, func7) \
+  .insn r CAT(CUSTOM_, x), 7, func7, rd, rs1, rs2
+
+/** Assembly macro for creating "raw" Rocket Custom Coproessor (RoCC)
+  * assembly language instructions that will *NOT* return data in rd.
+  * These are to be used only in assembly language programs (not
+  * C/C++).
+  *
+  * Example:
+  *
+  * Consider the following macro consisting of a CUSTOM_1 instruction
+  * with func7 "42" that is doing some operation of "op(a1, a2)". *NO*
+  * data is returned:
+  *
+  *     ROCC_INSTRUCTION_RAW_0_R_R(1, a1, a2, 42)
+  *
+  * This will produce the following pseudo assembly language
+  * instruction:
+  *
+  *     .insn r CUSTOM_1, 3, 42, x0, a1, a2
+  *
+  * @param x the custom instruction number: 0, 1, 2, or 3
+  * @param rs1 the first source register, e.g., a0 or x10
+  * @param rs2 the second source register, e.g., a0 or x10
+  * @param func7 the value of the func7 field
+  * @return a raw .insn RoCC instruction
+  */
+#define ROCC_INSTRUCTION_RAW_0_R_R(x, rs1, rs2, func7) \
+  .insn r CAT(CUSTOM_, x), 3, func7, x0, rs1, rs2
+
+/** C/C++ inline assembly macro for creating Rocket Custom Coprocessor
+  * (RoCC) instructions that return data in rd. These are to be used
+  * only in C/C++ programs (not bare assembly).
+  *
+  * This is equivalent to ROCC_INSTRUCTION_R_R_R. See it's
+  * documentation.
+  */
+#define ROCC_INSTRUCTION(x, rd, rs1, rs2, func7) \
+  ROCC_INSTRUCTION_R_R_R(x, rd, rs1, rs2, func7)
+
+/** C/C++ inline assembly macro for creating Rocket Custom Coprocessor
+  * (RoCC) instructions that return data in C variable rd. 
+  * These are to be used only in C/C++ programs (not bare assembly).
+  *
+  * Example:
+  *
+  * Consider the following macro consisting of a CUSTOM_2 instruction
+  * with func7 "42" that is doing some operation of "a0 = op(a1, a2)"
+  * (where a0, a1, and a2 are variables defined in C):
+  *
+  *     ROCC_INSTRUCTION(2, a0, a1, a2, 42)
+  *
+  * This will produce the following inline assembly:
+  *
+  *     asm volatile(
+  *         ".insn r CUSTOM_2, 0x7, 42, %0, %1, %2"
+  *         : "=r"(rd)
+  *         : "r"(rs1), "r"(rs2));
+  *
+  * @param x the custom instruction number: 0, 1, 2, or 3
+  * @param rd the C variable to capture as destination operand
+  * @param rs1 the C variable to capture for first source register
+  * @param rs2 the C variable to capture for second source register
+  * @param func7 the value of the func7 field
+  * @return an inline assembly RoCC instruction
+  */
+#define ROCC_INSTRUCTION_R_R_R(x, rd, rs1, rs2, func7)                               \
+  {                                                                                  \
+    asm volatile(                                                                    \
+        ".insn r " STR(CAT(CUSTOM_, x)) ", " STR(0x7) ", " STR(func7) ", %0, %1, %2" \
+        : "=r"(rd)                                                                   \
+        : "r"(rs1), "r"(rs2));                                                       \
+  }
+
+/** C/C++ inline assembly macro for creating Rocket Custom Coprocessor
+  * (RoCC) instructions that return data in C variable rd.
+  * These are to be used only in C/C++ programs (not bare assembly).
+  *
+  * Example:
+  *
+  * Consider the following macro consisting of a CUSTOM_3 instruction
+  * with func7 "42" that is doing some operation of "a0 = op(a1, a2)"
+  * (where a0, a1, and a2 are variables defined in C):
+  *
+  *     ROCC_INSTRUCTION(3, a0, a1, a2, 42)
+  *
+  * This will produce the following inline assembly:
+  *
+  *     asm volatile(
+  *         ".insn r CUSTOM_3, 0x7, 42, %0, %1, %2"
+  *         :: "r"(rs1), "r"(rs2));
+  *
+  * @param x the custom instruction number: 0, 1, 2, or 3
+  * @param rs1 the C variable to capture for first source register
+  * @param rs2 the C variable to capture for second source register
+  * @param funct7 the value of the funct7 f
+  * @return an inline assembly RoCC instruction
+  */
+#define ROCC_INSTRUCTION_0_R_R(x, rs1, rs2, func7)                                   \
+  {                                                                                  \
+    asm volatile(                                                                    \
+        ".insn r " STR(CAT(CUSTOM_, x)) ", " STR(0x3) ", " STR(func7) ", x0, %0, %1" \
+        :                                                                            \
+        : "r"(rs1), "r"(rs2));                                                       \
+  }
+
+// [TODO] fix these to align with the above approach
+// Macro to pass rs2_ as an immediate
+/*
+#define ROCC_INSTRUCTION_R_R_I(XCUSTOM_, rd_, rs1_, rs2_, funct_) \
+  asm volatile (XCUSTOM_" %[rd], %[rs1], %[rs2], %[funct]"        \
+                : [rd] "=r" (rd_)                                 \
+                : [rs1] "r" (rs1_), [rs2] "i" (rs2_), [funct] "i" (funct_))
+
+// Macro to pass rs1_ and rs2_ as immediates
+#define ROCC_INSTRUCTION_R_I_I(XCUSTOM_, rd_, rs1_, rs2_, funct_) \
+  asm volatile (XCUSTOM_" %[rd], %[rs1], %[rs2], %[funct]"        \
+                : [rd] "=r" (rd_)                                 \
+                : [rs1] "i" (rs1_), [rs2] "i" (rs2_), [funct] "i" (funct_))
+*/
+
+#endif  // ROCC_SOFTWARE_SRC_XCUSTOM_H_
diff --git a/verilog/rtl/softshell/third_party/sky130/models/sram_1rw1r_32_256_8_sky130.v b/verilog/rtl/softshell/third_party/sky130/models/sram_1rw1r_32_256_8_sky130.v
new file mode 100644
index 0000000..afbfa12
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/sky130/models/sram_1rw1r_32_256_8_sky130.v
@@ -0,0 +1,118 @@
+`default_nettype none
+// OpenRAM SRAM model
+// Words: 256
+// Word size: 32
+// Write size: 8
+
+module sram_1rw1r_32_256_8_sky130(
+`ifdef USE_POWER_PINS
+	vdd,
+	gnd,
+`endif
+// Port 0: RW
+    clk0,csb0,web0,wmask0,addr0,din0,dout0,
+// Port 1: R
+    clk1,csb1,addr1,dout1
+  );
+
+  parameter NUM_WMASKS = 4 ;
+  parameter DATA_WIDTH = 32 ;
+  parameter ADDR_WIDTH = 8 ;
+  parameter RAM_DEPTH = 1 << ADDR_WIDTH;
+  // FIXME: This delay is arbitrary.
+  parameter DELAY = 3 ;
+
+`ifdef USE_POWER_PINS
+  inout vdd;
+  inout gnd;
+`endif
+  input  clk0; // clock
+  input   csb0; // active low chip select
+  input  web0; // active low write control
+  input [NUM_WMASKS-1:0]   wmask0; // write mask
+  input [ADDR_WIDTH-1:0]  addr0;
+  input [DATA_WIDTH-1:0]  din0;
+  output [DATA_WIDTH-1:0] dout0;
+  input  clk1; // clock
+  input   csb1; // active low chip select
+  input [ADDR_WIDTH-1:0]  addr1;
+  output [DATA_WIDTH-1:0] dout1;
+
+  reg  csb0_reg;
+  reg  web0_reg;
+  reg [NUM_WMASKS-1:0]   wmask0_reg;
+  reg [ADDR_WIDTH-1:0]  addr0_reg;
+  reg [DATA_WIDTH-1:0]  din0_reg;
+  reg [DATA_WIDTH-1:0]  dout0;
+
+  // All inputs are registers
+  always @(posedge clk0)
+  begin
+    csb0_reg = csb0;
+    web0_reg = web0;
+    wmask0_reg = wmask0;
+    addr0_reg = addr0;
+    din0_reg = din0;
+    dout0 = 32'bx;
+`ifdef DBG
+    if ( !csb0_reg && web0_reg ) 
+      $display($time," Reading %m addr0=%b dout0=%b",addr0_reg,mem[addr0_reg]);
+    if ( !csb0_reg && !web0_reg )
+      $display($time," Writing %m addr0=%b din0=%b wmask0=%b",addr0_reg,din0_reg,wmask0_reg);
+`endif 
+   end
+
+  reg  csb1_reg;
+  reg [ADDR_WIDTH-1:0]  addr1_reg;
+  reg [DATA_WIDTH-1:0]  dout1;
+
+  // All inputs are registers
+  always @(posedge clk1)
+  begin
+    csb1_reg = csb1;
+    addr1_reg = addr1;
+`ifdef DBG
+    if (!csb0 && !web0 && !csb1 && (addr0 == addr1))
+         $display($time," WARNING: Writing and reading addr0=%b and addr1=%b simultaneously!",addr0,addr1);
+    dout1 = 32'bx;
+    if ( !csb1_reg ) 
+      $display($time," Reading %m addr1=%b dout1=%b",addr1_reg,mem[addr1_reg]);
+`endif  
+   end
+
+reg [DATA_WIDTH-1:0]    mem [0:RAM_DEPTH-1];
+
+  // Memory Write Block Port 0
+  // Write Operation : When web0 = 0, csb0 = 0
+  always @ (negedge clk0)
+  begin : MEM_WRITE0
+    if ( !csb0_reg && !web0_reg ) begin
+        if (wmask0_reg[0])
+                mem[addr0_reg][7:0] = din0_reg[7:0];
+        if (wmask0_reg[1])
+                mem[addr0_reg][15:8] = din0_reg[15:8];
+        if (wmask0_reg[2])
+                mem[addr0_reg][23:16] = din0_reg[23:16];
+        if (wmask0_reg[3])
+                mem[addr0_reg][31:24] = din0_reg[31:24];
+    end
+  end
+
+  // Memory Read Block Port 0
+  // Read Operation : When web0 = 1, csb0 = 0
+  always @ (negedge clk0)
+  begin : MEM_READ0
+    if (!csb0_reg && web0_reg)
+       dout0 <= #(DELAY) mem[addr0_reg];
+  end
+
+  // Memory Read Block Port 1
+  // Read Operation : When web1 = 1, csb1 = 0
+  always @ (negedge clk1)
+  begin : MEM_READ1
+    if (!csb1_reg)
+       dout1 <= #(DELAY) mem[addr1_reg];
+  end
+
+endmodule
+`default_nettype wire
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/.gitignore b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/.gitignore
new file mode 100644
index 0000000..494c202
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/.gitignore
@@ -0,0 +1,6 @@
+*.json
+pll.v
+*.asc
+*.rpt
+*.bin
+
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/LICENSE b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/Makefile b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/Makefile
new file mode 100644
index 0000000..1566cb3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/Makefile
@@ -0,0 +1,67 @@
+##
+## Make and program TinyFPGA BX
+##
+
+BASENAME = usbserial
+TARGETNAME = $(BASENAME)_tbx
+PROJTOP = $(TARGETNAME)
+
+RTL_USB_DIR = usb
+
+SOURCES = \
+	$(RTL_USB_DIR)/edge_detect.v \
+	$(RTL_USB_DIR)/serial.v \
+	$(RTL_USB_DIR)/usb_fs_in_arb.v \
+	$(RTL_USB_DIR)/usb_fs_in_pe.v \
+	$(RTL_USB_DIR)/usb_fs_out_arb.v \
+	$(RTL_USB_DIR)/usb_fs_out_pe.v \
+	$(RTL_USB_DIR)/usb_fs_pe.v \
+	$(RTL_USB_DIR)/usb_fs_rx.v \
+	$(RTL_USB_DIR)/usb_fs_tx_mux.v \
+	$(RTL_USB_DIR)/usb_fs_tx.v \
+	$(RTL_USB_DIR)/usb_reset_det.v \
+	$(RTL_USB_DIR)/usb_serial_ctrl_ep.v \
+	$(RTL_USB_DIR)/usb_uart_bridge_ep.v \
+	$(RTL_USB_DIR)/usb_uart_core.v \
+	$(RTL_USB_DIR)/usb_uart_i40.v \
+ 	pll.v
+
+SRC = $(PROJTOP).v $(SOURCES)
+
+PIN_DEF = pins.pcf
+
+DEVICE = lp8k
+PACKAGE = cm81
+
+CLK_MHZ = 48
+
+all: $(PROJTOP).rpt $(PROJTOP).bin
+
+pll.v:
+	icepll -i 16 -o $(CLK_MHZ) -m -f $@
+
+synth: $(PROJTOP).json
+
+$(PROJTOP).json: $(SRC)
+	yosys -q -p 'synth_ice40 -top $(PROJTOP) -json $@' $^
+
+%.asc: $(PIN_DEF) %.json
+	nextpnr-ice40 --$(DEVICE) --freq $(CLK_MHZ) --opt-timing --package $(PACKAGE) --pcf $(PIN_DEF) --json $*.json --asc $@
+
+gui: $(PIN_DEF) $(PROJTOP).json
+	nextpnr-ice40 --$(DEVICE) --package $(PACKAGE) --pcf $(PIN_DEF) --json $(PROJTOP).json --asc $(PROJTOP).asc --gui
+
+%.bin: %.asc
+	icepack $< $@
+
+%.rpt: %.asc
+	icetime -d $(DEVICE) -mtr $@ $<
+
+prog: $(PROJTOP).bin
+	tinyprog -p $<
+
+clean:
+	rm -f $(PROJTOP).json $(PROJTOP).asc $(PROJTOP).rpt $(PROJTOP).bin pll.v
+
+.SECONDARY:
+.PHONY: all synth prog clean gui
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/README.md b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/README.md
new file mode 100644
index 0000000..4d17013
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/README.md
@@ -0,0 +1,347 @@
+# TinyFPGA BX USB Serial
+
+![](usb_ser_ice40_detail.png)
+
+## Origins
+
+Luke Valenty's USB module, as adapted by Lawrie Griffiths and others.  Luke's code was created with the purpose of providing a "bit banged" USB port to SPI bridge for his (awesome) TinyFPGA boards.
+
+The original is here - https://github.com/tinyfpga/TinyFPGA-Bootloader
+
+Lawrie Griffiths dug into the dark innards of this code and did the bulk of the work to change it to being a USB - SERIAL bridge, looking to the user like a serial port, rather than an SPI master.  He also created some great examples.  His work is here - https://github.com/lawrie/tiny_usb_examples
+
+However there were a couple of problems:
+- arachne-pnr would give spotty results, sometimes not working at all.  This is easy to understand when considering that arachne-pnr *does not place in such a way as to minimize timings!*  NextNPR is a must.
+- the original code has a few places where it violates Verilog rules (mostly fixed by smunaut and submitted as a pull request https://github.com/tinyfpga/TinyFPGA-Bootloader/pull/21)
+
+## This Project
+
+This project makes the above changes, and fixes one or two other small issues.  Importantly, it also replaces the front end to the code with a pipeline interface, which is what makes this project more fork-y and less pull-request-y with respect to Lawrie's repo.
+
+The key to the streaming pipeline interface is that there are three ports: `data`, `valid`, and `ready`.  A sender will place new data on the `data` port and raise the `valid` flag.  If a receiver is ready to receive, it will raise the `ready` flag.  So in any connection there will be two signals generated by the sender (`data` and `valid`) and one by the receiver `ready`.  And here's the key part *if `valid` and `ready` are both raised at the same time the data is considered to be transfered*.   This interface can clunk along - the sender raising valid now and then, and provided the `ready` signal is raised, data will flow, but pretty amazingly, this interface can really rock - if there is data to be had at every clock cycle, just leave `valid` and `ready` on and one word of data will flow *at each clock*.
+
+This works pretty well and has been tested at full speed using some Python code.
+
+The USB code alone (with virtually no other functionality at all) uses 14% of the device's LUT's.  Here's the NextPNR output:
+
+```
+Info: Device utilisation:
+Info: 	         ICESTORM_LC:  1093/ 7680    14%
+Info: 	        ICESTORM_RAM:     2/   32     6%
+Info: 	               SB_IO:     9/  256     3%
+Info: 	               SB_GB:     8/    8   100%
+Info: 	        ICESTORM_PLL:     1/    2    50%
+Info: 	         SB_WARMBOOT:     0/    1     0%
+```
+
+This code is passing timing.
+
+```
+Info: Max frequency for clock 'clk_48mhz_$glb_clk': 51.60 MHz (PASS at 48.00 MHz)
+```
+
+This is quite notable, since other adaptations of the Valenty code are forced to run most of the code in a much slower clock domain to pass timing.
+
+Here's how the code is placed in the iCE40
+
+![](usb_ser_ice40.png)
+
+
+**An Aside - Xilinx 7**
+
+Since this is fully generic verilog code, there is no special work to do to make the code work in other architectures beyond instantiating the correct IO primitives.  Delightfully, this codebase also works on Xilinx parts.
+
+The file `usb_uart_x7.v` is the wrapper that does the IO primitive work for Xilinx 7 code, so the primitives don't clutter the higher code.
+
+With a little ad-hoc hardware (an [Adafruit USB mini breakout board](https://www.adafruit.com/product/1764), 68 ohm resistors connecting D+ and D- to FPGA IO, and a 1.5k pull up on the D+) a second port was added to a [Digilent Cmod A7 board](https://store.digilentinc.com/cmod-a7-breadboardable-artix-7-fpga-module/).
+
+![](dual_usb_cmoda7_hw.jpg)
+
+And connecting the soft usb to the onboard serial port results in a simple USB-USB bridge.
+
+![](dual_usb_cmoda7_term.png)
+
+In contrast to the appearance of a 14% occupied iCE40, here's a 2% occupied Xilinx Artix 7 (20k LUTSs) running the simple SERIAL - Valenty USB bridge.
+
+![](dual_usb_cmoda7_pnr.png)
+
+The wrapper code is included here and can easily be included in Xilinx 7 code that need a soft USB port, but the files for the above example are part of another to be soon released project.  The present experiment was performed in Xilinx's Titanic dev environment, [Vivado](https://www.xilinx.com/products/design-tools/vivado.html), but it might work in the open source [Project Xray](https://symbiflow.readthedocs.io/projects/prjxray/en/latest/).
+
+**Another Aside - ECP 5**
+
+Some experimentation with the ECP5 Evaluation Board reveals that it too will run this code.  In the shot below, we see the new working USB port on the standard Eval board's Pmod connector.  A second, hand wired Pmod connector is visible behind although not in use.
+
+The file `usb_uart_ecp5.v` is the wrapper that connects the ECP5 bidirectional IO primitive into the code.
+
+![](ecp5_usb_serial.jpeg)
+
+The Eval board has one of those ubiquitous FTDI FT2232H chips for programming and IO, but the second channel is wired for I2C out of the box.  To activate the UART side (which requires a UART on the FPGA!) a couple of modifications need to be made to the board.
+
+First The FTDI has to be told that the protocol it should run on the B channel is UART. This means getting into FT Prog (Windows only, annoyingly) and setting the hardware setting to UART. This has the effect that when the chip powers up, it knows it should present as a UART (not a FIFO which is the default, and unsupported by the hardware).
+
+Then connect the pads at each of R34 and R35 to connect the FTDI with the ECP5. They are shown as Do Not Insert 0 ohm resistors on the schematic.  These lines are connected as I2C to several places by default, but only one connection is populated, FPGA lines (E6 D7). If they are left as inputs (high impedance) they don't disturb anything.
+
+With R34 and R35 nicely bridged the FTDI.TX -> FPGA.RX line works, which is easily verified by piping the whole incoming char to the 8-leds. Also easy to see if you have baud rate issues here.
+
+Finally, the FTDI when in UART mode wants to make a third line (FTDI pin 40) an RTS signal. That signal which is connected to the FTDI receiver (pin39) via a 0 ohm resistor kills all (FPGA TX -> FTDI RX) traffic. Removing R24 solves this.
+
+It would be fun to see how many USB ports could be added to this board.
+
+**Interface**
+
+The interface to the code looks like the following:
+
+``` verilog
+usb_uart u_u (
+  .clk_48mhz  (clk_48mhz),
+  .reset      (reset),
+
+  // pins
+  .pin_usb_p( pin_usb_p ),
+  .pin_usb_n( pin_usb_n ),
+
+  // uart pipeline in
+  .uart_in_data( uart_in_data ),
+  .uart_in_valid( uart_in_valid ),
+  .uart_in_ready( uart_in_ready ),
+
+  // uart pipeline out
+  .uart_out_data( uart_out_data ),
+  .uart_out_valid( uart_out_valid ),
+  .uart_out_ready( uart_out_ready ),
+);
+```
+
+Note that there are no baud rates, start, stop or parity specifications as this is only a pretend UART.
+
+**Clock**
+
+You will need a 48Mhz clock.  This can be generated by pll from the TinyFPGA BX's 16Mhz oscillator.
+
+``` verilog
+SB_PLL40_CORE #(
+		.FEEDBACK_PATH("SIMPLE"),
+		.DIVR(4'b0000),		// DIVR =  0
+		.DIVF(7'b0101111),	// DIVF = 47
+		.DIVQ(3'b100),		// DIVQ =  4
+		.FILTER_RANGE(3'b001)	// FILTER_RANGE = 1
+	) uut (
+		.LOCK(locked),
+		.RESETB(1'b1),
+		.BYPASS(1'b0),
+		.REFERENCECLK(clock_in),
+		.PLLOUTCORE(clock_out)
+		);
+```
+
+In this project, the pll is contained in its own module (pll.v) that is created by the IceStorm project tool `icepll`.
+
+Amazingly, the 48MHz signal can also be generated by dividing down a faster clock.  Using an `icepll` configured pll at 192MHz, a 48MHz signal can be derived the simple way, by divider, and (possibly unnecessarily) put through the global buffer network for distribution.  This worked for a few experiments, but probably requires more development and testing to confirm.  Perhaps it can be done better.
+
+``` verilog
+wire clk_192mhz;
+wire clk_locked;
+
+// Use an icepll generated pll to give us 192MHz
+pll pll192( .clock_in(pin_clk), .clock_out(clk_192mhz), .locked(clk_locked) );
+
+reg [4:0] reset_counter = 0;
+
+// Generate the slower clock
+reg       clk_48mhz_logic;
+reg [1:0] clk_divider;
+always @(posedge clk_192mhz ) begin
+    if ( ~clk_locked ) begin
+        clk_divider <= 0;
+    end else begin
+        case (clk_divider)
+            0: begin
+                clk_48mhz_logic <= 1;
+                clk_divider <= 1;
+            end
+            1: begin
+                clk_divider <= 2;
+            end
+            2: begin
+                clk_48mhz_logic <= 0;
+                clk_divider <= 3;
+            end
+            3: begin
+                clk_divider <= 0;
+            end
+      endcase
+  end
+end
+
+// This clock has to go places.  Put it through a global buffer
+wire clk_48mhz;
+SB_GB gbc(
+    .USER_SIGNAL_TO_GLOBAL_BUFFER (clk_48mhz_logic),
+    .GLOBAL_BUFFER_OUTPUT ( clk_48mhz ) );
+```
+
+**Device Pins**
+
+The pins in the interface to the module (`pin_usb_p` and `pin_usb_n`) are the raw device pins, the direction control logic is internal to `usb_uart_i40`.  The original usb_uart module is retained below to facilitate reuse in other architectures.
+
+Somewhere the USB pull up pin has to be asserted.  This is done in the top level code, since usb_uart doesn't manipulate it.
+
+``` verilog
+assign pin_pu = 1'b1;
+```
+
+**Pipeline Interface**
+
+There are two pipeline interfaces to the module, `uart_in` and `uart_out`.  The former being a pipeline *receiver* and the latter being a pipeline *sender*.  The naming can be a bit confusing.  `uart_in` is into the module, out of the device, into the host, `uart_out` is out of the host, into the device, out of the module.
+
+These can just be tied together (as they are in this project) to create a UART loopback.
+
+## Use
+
+Development has been done on Ubuntu.
+
+Clone the repo
+
+```
+git clone git@github.com:davidthings/tinyfpga_bx_usbserial.git
+```
+
+and enter the directory
+
+`cd tinyfpga_bx_usbserial`
+
+And make it!
+
+`make`
+
+The make process has got to do a few things so it may take a minute.
+
+If it completes successfully, press the "program" button on the TinyFPGA BX and program it
+
+`make prog`
+
+If all went well, you will then see a new port which you can connect to with a serial terminal emulator (on Ubuntu the port is /dev/ttyACM0 and a good terminal program is **gtkterminal** since it doesn't seem to get upset if you forget to disconnect before reprogramming).
+
+For this demo, characters typed are rather unspectacularly just echo'ed back.
+
+`make gui`
+
+Let's you perform the place and route manually and generate pretty pictures like the ones above.
+
+## Dependencies
+
+Nothing is required beyond the usual tools needed for TinyFPGA development.  This is a command-line makefile project.
+
+**Icestorm**
+
+http://www.clifford.at/icestorm/
+
+Make sure you get NextPNR.
+
+**TinyFPGA BX**
+
+https://tinyfpga.com/bx/guide.html
+
+## Debug
+
+There is some debug instrumentation left in the code.  This will just disappear if you don't use it.  For the Device Host bug, there were 16 lines connected to the hardware to present as much state as possible from the USB stack for debugging.  Here's one resulting screenshot where the interface is working to near capacity.
+
+![](usb_serial_deep_debug.png)
+
+- D0 - trigger (to send a 40-ish byte block if the last one was done)
+- D1 Pipeline Data[ 0 ] (toggles when presented with a sequence of odd-even data)
+- D2 Pipeline Valid - there is data available
+- D3 Pipeline Ready - the data can be accepted
+- D4 USB SERIAL IN State Machine[0] - controlling the pipeline from FPGA to Host (usb_uart_bridge_ep.v)
+- D5 USB SERIAL IN State Machine[1]
+- D6 `in_ep_data_done` (asserted when a partial outgoing buffer should be sent)
+- D7  `in_ep_data_free` (asserted while the usb serial sysyem can accept data)
+- D8 - EP State Machine[0] - `current_ep_state` (usb_fs_in_pe.v)
+- D9 - EP State Machine[1]
+- D10 - IN TX State Machine[0] - `in_xfr_state` (usb_fs_in_pe.v)
+- D11 - IN TX State Machine[1]
+- D12 - Bytes available to Tx - this indicates that there are bytes to send the USB transmitter
+- D13 - Byte to Tx - this is the strobe of the next byte into the USB transmitter
+- D14 - Receiver Message Start - the USB receiver has received a message start (an IN token or Ack here)
+- D15 - Receiver Message End - the USB receiver has received a message start (an IN token or Ack here)
+
+Overall, you can see the data source pipelining data (D1) into the buffer whenever the USB port is ready (D3).  When a buffer is full, the interface waits (EP State Machine D9,D8 = 1,0) until it gets an IN Token (D14,D15).  When this happens, the waiting buffer is sent as fast as the USB lines can send send them.  The interface waits for an ACK (D14,D15) and when all is well, signals up the stack that it's ready to fill another buffer.  And the cycle restarts.
+
+## Issues
+
+**Pipeline Interface**
+
+Run slowly, the pipeline is pretty simple.  Data is available (`valid`), receiver (signaling `ready`) receives it.  Wait.  Repeat.  You can certainly use it in a simple way by de-asserting `ready` every cycle forcing the interface into a two step (`valid` `ready`, `valid` `~ready`).  The logic to do this is pretty simple.
+
+Where the pipeline shines is when data is streaming - one in, one out every clock cycle, (as happens in multibyte transfers), but for a simple seeming interface, and one that appears in near all FPGA code, a pipeline like this can be *fiendishly* complex to implement, especially for modules both receiving and sending data.  Implementers *must* have a firm grasp on their `=`'s vs `<=`'s, know their `always @(*)`'s from their `always @(posedge clk)`'s, and really understand combinatorial vs registered signals.
+
+Here's a taste.  Consider a pipeline module, m with both upstream and downstream communicating partners.  The main area of complexity happens when data is streaming (`valid` and `ready` are asserted by all).  Every clock, data is flowing from the upstream module into m, and from m into the downstream module below it. Suddenly the downstream module gets busy or is itself held up for some reason and it lowers `ready`.  When this happens module m has to latch the data that it is currently sending (since data is transferred only when *both* parties agree), hold `valid` high and wait.  Meanwhile the upstream module's data *was considered transfered*.  So the poor module m in the middle has to both latch its data word and store the new overflow one and just hang out.  Then when the downstream module finally signals that it's ready (raising the `ready` line), module m first needs to give it the original data, then the stored overflow data, and only then can it start accepting data again (raising its `ready` to the upstream module).  Getting all this in your head and implemented correctly can take days (or weeks)
+
+Mr ZipCPU talks about pipelining a lot here - https://zipcpu.com/blog/2017/08/14/strategies-for-pipelining.html . He uses "STB" and "Busy" as his signals, and his development of the subject is pretty nice.  I haven't used his code.  There are a few places where I have skeptical squint-eye, and so to not end up balling and throwing things every time I implemented something pipeline-y, I ended up writing my own pipeline code from scratch.
+
+So, feel free to use this interface, or put another one on it!  Maybe someone will create a whole suite of pipelined modules to do stuff...
+
+**Command Line**
+
+There are rumors that some people don't like command-line tools.  If you (or a friend) think you might be one of these people, please feel free to connect this project to your other fancy environment (Apio, PlatformIO) and submit the appropriate files so others may experience these delights.
+
+**Accuracy / Mistakes / Etc.**
+
+Please feel free to suggest fixes / improvements / changes.
+
+## Fixed Issues
+
+**Removed Extra Endpoint**
+
+There was an extra unused endpoint burried in the code.  Removing it results 2% less LUT use, and improves the chances of a design passing timing.  Thanks very much to Olof Kindren for taking the time to understand this code and post the PR.
+
+**Design Passing Timing**
+
+Originally some long constants were creating very long carry chains.  The code could never be made to pass at 48MHz.  This was dangerous since some parts under some conditions might not work.  Now it does pass!
+
+```
+Info: Max frequency for clock 'clk_48mhz_$glb_clk': 51.60 MHz (PASS at 48.00 MHz)
+```
+
+For reference, there were a few places like the following:
+
+usb/usb_fs_out_pe.v:185
+```
+              if (ep_get_addr[ep_num][5:0] >= (ep_put_addr[ep_num][5:0] - 2)) begin
+```
+
+usb/usb_fs_out_pe.v:212
+```
+          ep_get_addr_next[ep_num][5:0] <= ep_get_addr[ep_num][5:0] + 1;
+```
+
+In these cases, the constant is interpreted as 32b and the whole operation is conducted at that width.  32b long carry chains can not be done at 48MHz in the iCE40. The fix was for these needed to become explicitly shorter.
+
+usb/usb_fs_out_pe.v:185
+```
+              if (ep_get_addr[ep_num][5:0] >= (ep_put_addr[ep_num][5:0] - 6'H2)) begin
+```
+
+usb/usb_fs_out_pe.v:212
+```
+          ep_get_addr_next[ep_num][5:0] <= ep_get_addr[ep_num][5:0] + 6H'1;
+```
+
+So that the full 32b addition and subtraction was not conducted.  This is possibly an issue with yosys (and may even be already fixed) since the Xilinx Vivado tools just silently ignore all the extra bits.  This kind of problem occurs in a few other places.  See the relevant [commit](https://github.com/davidthings/tinyfpga_bx_usbserial/commit/d9e157e09c166894e25777a0037a3c3d1592f135) for more.
+
+
+**Device-Host Bug**
+
+If the device sent data when the host was not ready, bad things happened.  If the device sent more than 32 bytes in a single burst, bad things happened. Only good things happen now from single bytes up to streams almost at link capacity.
+
+**32 Character Bug**
+
+Turns out that was all me.  Fixed now.
+
+**Back Pressure Bugs**
+
+The OUT EP interface (characters from the host) would stutter a little sometimes when the pipeline signaled `~ready`.  This is fixed now.
+
+**Send Timeout**
+
+The IN EP (characters to the host) employed a very aggressive policy for buffer termination.  Whenever the pipeline went dry - `~valid` it would send the bytes already received, initiating a whole packet turnaround.  This is not ideal when a pipeline may stop for a cycle or two periodically.  So now when there's a pause, the IN EP waits for up to 8 cycles before dispatching the packet.
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/dual_usb_cmoda7_hw.jpg b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/dual_usb_cmoda7_hw.jpg
new file mode 100644
index 0000000..470e78c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/dual_usb_cmoda7_hw.jpg
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/dual_usb_cmoda7_pnr.png b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/dual_usb_cmoda7_pnr.png
new file mode 100644
index 0000000..a345d7c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/dual_usb_cmoda7_pnr.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/dual_usb_cmoda7_term.png b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/dual_usb_cmoda7_term.png
new file mode 100644
index 0000000..175b954
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/dual_usb_cmoda7_term.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/ecp5_usb_serial.jpeg b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/ecp5_usb_serial.jpeg
new file mode 100644
index 0000000..4a8b269
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/ecp5_usb_serial.jpeg
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/pins.pcf b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/pins.pcf
new file mode 100644
index 0000000..d1aa483
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/pins.pcf
@@ -0,0 +1,11 @@
+set_io pin_led   B3

+set_io pin_usb_p B4

+set_io pin_usb_n A4

+set_io pin_pu    A3

+set_io pin_clk   B2

+

+# Your debug pins might be different

+set_io --warn-no-port debug[0] H9   # Pin_14

+set_io --warn-no-port debug[1] D9   # Pin_15

+set_io --warn-no-port debug[2] D8   # Pin_16

+set_io --warn-no-port debug[3] C9   # Pin_17

diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/edge_detect.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/edge_detect.v
new file mode 100644
index 0000000..62f053a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/edge_detect.v
@@ -0,0 +1,27 @@
+module rising_edge_detector ( 

+  input clk,

+  input in,

+  output out

+);

+  reg in_q;

+

+  always @(posedge clk) begin

+    in_q <= in;

+  end

+

+  assign out = !in_q && in;

+endmodule

+

+module falling_edge_detector ( 

+  input clk,

+  input in,

+  output out

+);

+  reg in_q;

+

+  always @(posedge clk) begin

+    in_q <= in;

+  end

+

+  assign out = in_q && !in;

+endmodule

diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/serial.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/serial.v
new file mode 100644
index 0000000..b776c70
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/serial.v
@@ -0,0 +1,53 @@
+module width_adapter #(

+  parameter [31:0] INPUT_WIDTH = 8,

+  parameter [31:0] OUTPUT_WIDTH = 1

+) (

+  input clk,

+  input reset,

+

+  input data_in_put,

+  output data_in_free,

+  input [INPUT_WIDTH-1:0] data_in,

+

+  output data_out_put,

+  input data_out_free,

+  output [OUTPUT_WIDTH-1:0] data_out

+);

+

+  generate

+    if (INPUT_WIDTH > OUTPUT_WIDTH) begin

+      // wide to narrow conversion

+      reg [INPUT_WIDTH:0] data_in_q;

+      reg has_data;

+

+      always @(posedge clk) begin

+        if (!has_data && data_in_put) begin

+          data_in_q <= {1'b1, data_in};

+          has_data <= 1;

+        end

+

+        if (has_data && data_out_free) begin

+          data_in_q <= data_in_q >> OUTPUT_WIDTH;

+        end

+

+        if (data_in_q == 1'b1) begin

+          has_data <= 0;

+        end

+      end

+

+      assign data_out = data_in_q[OUTPUT_WIDTH:1];

+      assign data_out_put = has_data;

+

+

+    end else if (INPUT_WIDTH < OUTPUT_WIDTH) begin

+      // narrow to wide conversion

+

+

+    end else begin

+      assign data_in_free = data_out_free;

+      assign data_out_put = data_in_put;

+      assign data_out = data_in;

+    end

+  endgenerate

+

+endmodule

diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_in_arb.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_in_arb.v
new file mode 100644
index 0000000..20b8fa3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_in_arb.v
@@ -0,0 +1,39 @@
+module usb_fs_in_arb #(

+  parameter NUM_IN_EPS = 1

+) (

+  ////////////////////

+  // endpoint interface

+  ////////////////////

+  input [NUM_IN_EPS-1:0] in_ep_req,

+  output reg [NUM_IN_EPS-1:0] in_ep_grant,

+  input [(NUM_IN_EPS*8)-1:0] in_ep_data,

+

+

+  ////////////////////

+  // protocol engine interface

+  ////////////////////

+  output reg [7:0] arb_in_ep_data

+);

+  integer i;

+  reg grant;

+

+  always @* begin

+    grant = 0;

+

+    arb_in_ep_data <= 0;

+

+    for (i = 0; i < NUM_IN_EPS; i = i + 1) begin

+      in_ep_grant[i] <= 0;

+

+      if (in_ep_req[i] && !grant) begin

+        in_ep_grant[i] <= 1;

+        arb_in_ep_data <= in_ep_data[i * 8 +: 8];

+        grant = 1;

+      end

+    end

+

+    // if (!grant) begin

+    //    arb_in_ep_data <= 0;

+    // end

+  end

+endmodule

diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_in_pe.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_in_pe.v
new file mode 100644
index 0000000..e5cf144
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_in_pe.v
@@ -0,0 +1,421 @@
+// The IN Protocol Engine sends data to the host.

+module usb_fs_in_pe #(

+  parameter NUM_IN_EPS = 11,

+  parameter MAX_IN_PACKET_SIZE = 32

+) (

+  input clk,

+  input reset,

+  input [NUM_IN_EPS-1:0] reset_ep,

+  input [6:0] dev_addr,

+

+

+  ////////////////////

+  // endpoint interface

+  ////////////////////

+  output reg [NUM_IN_EPS-1:0] in_ep_data_free = 0,

+  input [NUM_IN_EPS-1:0] in_ep_data_put,

+  input [7:0] in_ep_data,

+  input [NUM_IN_EPS-1:0] in_ep_data_done,

+  input [NUM_IN_EPS-1:0] in_ep_stall,

+  output reg [NUM_IN_EPS-1:0] in_ep_acked = 0,

+

+

+  ////////////////////

+  // rx path

+  ////////////////////

+

+  // Strobed on reception of packet.

+  input rx_pkt_start,

+  input rx_pkt_end,

+  input rx_pkt_valid,

+

+  // Most recent packet received.

+  input [3:0] rx_pid,

+  input [6:0] rx_addr,

+  input [3:0] rx_endp,

+  input [10:0] rx_frame_num,

+

+

+  ////////////////////

+  // tx path

+  ////////////////////

+

+  // Strobe to send new packet.

+  output reg tx_pkt_start = 0,

+  input tx_pkt_end,

+

+

+  // Packet type to send

+  output reg [3:0] tx_pid = 0,

+

+  // Data payload to send if any

+  output tx_data_avail,

+  input tx_data_get,

+  output reg [7:0] tx_data,

+

+  output [7:0] debug

+);

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // endpoint state machine

+  ////////////////////////////////////////////////////////////////////////////////

+  reg [1:0] ep_state [NUM_IN_EPS - 1:0];

+  reg [1:0] ep_state_next [NUM_IN_EPS - 1:0];

+

+  // latched on valid IN token

+  reg [3:0] current_endp = 0;

+

+  wire [1:0] current_ep_state = ep_state[current_endp][1:0];

+

+  localparam READY_FOR_PKT = 0;

+  localparam PUTTING_PKT = 1;

+  localparam GETTING_PKT = 2;

+  localparam STALL = 3;

+

+  assign debug[1:0] = ( current_endp == 1 ) ? current_ep_state : 0;

+

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // in transfer state machine

+  ////////////////////////////////////////////////////////////////////////////////

+  localparam IDLE = 0;

+  localparam RCVD_IN = 1;

+  localparam SEND_DATA = 2;

+  localparam WAIT_ACK = 3;

+

+  reg [1:0] in_xfr_state = IDLE;

+  reg [1:0] in_xfr_state_next;

+

+  assign debug[3:2] = ( current_endp == 1 ) ? in_xfr_state : 0;

+

+  reg in_xfr_start = 0;

+  reg in_xfr_end = 0;

+

+  assign debug[4] = tx_data_avail; 

+  assign debug[5] = tx_data_get; 

+

+  // data toggle state

+  reg [NUM_IN_EPS - 1:0] data_toggle = 0;

+

+  // endpoint data buffer

+  reg [7:0] in_data_buffer [(MAX_IN_PACKET_SIZE * NUM_IN_EPS) - 1:0];

+  // Address registers - one bit longer (6) than required (5) to permit fullness != emptyness

+  reg [5:0] ep_put_addr [NUM_IN_EPS - 1:0];

+  reg [5:0] ep_get_addr [NUM_IN_EPS - 1:0];

+

+  integer i = 0;

+  initial begin

+    for (i = 0; i < NUM_IN_EPS; i = i + 1) begin

+      ep_put_addr[i] = 0;

+      ep_get_addr[i] = 0;

+      ep_state[i] = 0;

+    end

+  end

+

+  reg [3:0] in_ep_num = 0;

+

+  // the actual address (note using only the real 5 bits of the incoming address + the high order buffer select)

+  wire [8:0] buffer_put_addr = {in_ep_num[3:0], ep_put_addr[in_ep_num][4:0]};

+  wire [8:0] buffer_get_addr = {current_endp[3:0], ep_get_addr[current_endp][4:0]};

+

+  // endpoint data packet buffer has a data packet ready to send

+  reg [NUM_IN_EPS - 1:0] endp_ready_to_send = 0;

+

+  // endpoint has some space free in its buffer

+  reg [NUM_IN_EPS - 1:0] endp_free = 0;

+

+  wire token_received =

+    rx_pkt_end &&

+    rx_pkt_valid &&

+    rx_pid[1:0] == 2'b01 &&

+    rx_addr == dev_addr &&

+    rx_endp < NUM_IN_EPS;

+

+  wire setup_token_received =

+    token_received &&

+    rx_pid[3:2] == 2'b11;

+

+  wire in_token_received =

+    token_received &&

+    rx_pid[3:2] == 2'b10;

+

+  wire ack_received =

+    rx_pkt_end &&

+    rx_pkt_valid &&

+    rx_pid == 4'b0010;

+

+  assign debug[ 6 ] = rx_pkt_start;

+  assign debug[ 7 ] = rx_pkt_end;

+  

+

+  wire more_data_to_send =

+    ep_get_addr[current_endp][5:0] < ep_put_addr[current_endp][5:0];

+

+  wire [5:0] current_ep_get_addr = ep_get_addr[current_endp][5:0];

+  wire [5:0] current_ep_put_addr = ep_put_addr[current_endp][5:0];

+

+

+

+

+  wire tx_data_avail_i =

+    in_xfr_state == SEND_DATA &&

+    more_data_to_send;

+

+  assign tx_data_avail = tx_data_avail_i;

+

+

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // endpoint state machine

+  ////////////////////////////////////////////////////////////////////////////////

+

+

+  genvar ep_num;

+  generate

+    for (ep_num = 0; ep_num < NUM_IN_EPS; ep_num = ep_num + 1) begin

+

+      // Manage next state

+      always @* begin

+        in_ep_acked[ep_num] <= 0;

+

+        ep_state_next[ep_num] <= ep_state[ep_num];

+

+        if (in_ep_stall[ep_num]) begin

+          ep_state_next[ep_num] <= STALL;

+

+        end else begin

+          case (ep_state[ep_num])

+            READY_FOR_PKT : begin

+              ep_state_next[ep_num] <= PUTTING_PKT;

+            end

+

+            PUTTING_PKT : begin

+              // if either the user says they're done or the buffer is full, move on to GETTING_PKT

+              if ( ( in_ep_data_done[ep_num] ) || ( ep_put_addr[ep_num][5] ) ) begin   

+                ep_state_next[ep_num] <= GETTING_PKT;

+              end else begin

+                ep_state_next[ep_num] <= PUTTING_PKT;

+              end

+            end

+

+            GETTING_PKT : begin

+              // here we're waiting to send the data out, and receive an ACK token back

+              // No token, and we're here for a while.

+              if (in_xfr_end && current_endp == ep_num) begin

+                ep_state_next[ep_num] <= READY_FOR_PKT;

+                in_ep_acked[ep_num] <= 1;

+

+              end else begin

+                ep_state_next[ep_num] <= GETTING_PKT;

+              end

+            end

+

+            STALL : begin

+              if (setup_token_received && rx_endp == ep_num) begin

+                ep_state_next[ep_num] <= READY_FOR_PKT;

+

+              end else begin

+                ep_state_next[ep_num] <= STALL;

+              end

+            end

+

+            default begin

+              ep_state_next[ep_num] <= READY_FOR_PKT;

+            end

+          endcase

+        end

+

+        endp_free[ep_num] = !ep_put_addr[ep_num][5];

+        in_ep_data_free[ep_num] = endp_free[ep_num] && ep_state[ep_num] == PUTTING_PKT;

+      end

+

+      // Handle the data pointer (advancing and clearing)

+      always @(posedge clk) begin

+        if (reset || reset_ep[ep_num]) begin

+          ep_state[ep_num] <= READY_FOR_PKT;

+

+        end else begin

+          ep_state[ep_num] <= ep_state_next[ep_num];

+

+          case (ep_state[ep_num])

+            READY_FOR_PKT : begin

+              // make sure we start with a clear buffer (and the extra bit!)

+              ep_put_addr[ep_num][5:0] <= 0;

+            end

+

+            PUTTING_PKT : begin

+              // each time we are putting, and there's a data_put signal, increment the address

+              if (in_ep_data_put[ep_num] && ( ~ep_put_addr[ep_num][5] ) ) begin

+                ep_put_addr[ep_num][5:0] <= ep_put_addr[ep_num][5:0] + 1;

+              end

+            end

+

+            GETTING_PKT : begin

+            end

+

+            STALL : begin

+            end

+          endcase

+        end

+      end

+    end

+  endgenerate

+

+  // Decide which in_ep_num we're talking to

+  // Using the data put register is OK here

+  integer ep_num_decoder;

+  always @* begin

+    in_ep_num <= 0;

+

+    for (ep_num_decoder = 0; ep_num_decoder < NUM_IN_EPS; ep_num_decoder = ep_num_decoder + 1) begin

+      if (in_ep_data_put[ep_num_decoder]) begin

+        in_ep_num <= ep_num_decoder;

+      end

+    end

+  end

+

+  // Handle putting the new data into the buffer

+  always @(posedge clk) begin

+    case (ep_state[in_ep_num])

+      PUTTING_PKT : begin

+        if (in_ep_data_put[in_ep_num] && !ep_put_addr[in_ep_num][5]) begin

+          in_data_buffer[buffer_put_addr] <= in_ep_data;

+        end

+      end

+    endcase

+  end

+

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // in transfer state machine

+  ////////////////////////////////////////////////////////////////////////////////

+

+  reg rollback_in_xfr;

+

+  always @* begin

+    in_xfr_state_next <= in_xfr_state;

+    in_xfr_start <= 0;

+    in_xfr_end <= 0;

+    tx_pkt_start <= 0;

+    tx_pid <= 4'b0000;

+    rollback_in_xfr <= 0;

+

+    case (in_xfr_state)

+      IDLE : begin

+        rollback_in_xfr <= 1;

+

+        if (in_token_received) begin

+          in_xfr_state_next <= RCVD_IN;

+

+        end else begin

+          in_xfr_state_next <= IDLE;

+        end

+      end

+

+      // Got an IN token

+      RCVD_IN : begin

+        tx_pkt_start <= 1;

+

+        if (ep_state[current_endp] == STALL) begin

+          in_xfr_state_next <= IDLE;

+          tx_pid <= 4'b1110; // STALL

+

+        end else if (ep_state[current_endp] == GETTING_PKT) begin

+          // if we were in GETTING_PKT (done getting data from the device), Send it!

+          in_xfr_state_next <= SEND_DATA;

+          tx_pid <= {data_toggle[current_endp], 3'b011}; // DATA0/1

+          in_xfr_start <= 1;

+

+        end else begin

+          in_xfr_state_next <= IDLE;

+          tx_pid <= 4'b1010; // NAK

+        end

+      end

+

+      SEND_DATA : begin

+        // Send the data from the buffer now (until the out (get) address = the in (put) address)

+        if (!more_data_to_send) begin

+          in_xfr_state_next <= WAIT_ACK;

+

+        end else begin

+          in_xfr_state_next <= SEND_DATA;

+        end

+      end

+

+      WAIT_ACK : begin

+        // FIXME: need to handle smash/timeout

+        // Could wait here forever (although another token will come along)

+        if (ack_received) begin

+          in_xfr_state_next <= IDLE;

+          in_xfr_end <= 1;

+

+        end else if (in_token_received) begin

+          in_xfr_state_next <= RCVD_IN;

+          rollback_in_xfr <= 1;

+

+        end else if (rx_pkt_end) begin

+          in_xfr_state_next <= IDLE;

+          rollback_in_xfr <= 1;

+

+        end else begin

+          in_xfr_state_next <= WAIT_ACK;

+        end

+      end

+    endcase

+  end

+

+ always @(posedge clk)

+     tx_data <= in_data_buffer[buffer_get_addr];

+

+  integer j;

+  always @(posedge clk) begin

+    if (reset) begin

+      in_xfr_state <= IDLE;

+

+    end else begin

+      in_xfr_state <= in_xfr_state_next;

+

+      // tx_data <= in_data_buffer[buffer_get_addr];

+

+      if (setup_token_received) begin

+        data_toggle[rx_endp] <= 1;

+      end

+

+      if (in_token_received) begin

+        current_endp <= rx_endp;

+      end

+

+      if (rollback_in_xfr) begin

+        ep_get_addr[current_endp][5:0] <= 0;

+      end

+

+      case (in_xfr_state)

+        IDLE : begin

+        end

+

+        RCVD_IN : begin

+        end

+

+        SEND_DATA : begin

+          if (tx_data_get && tx_data_avail_i) begin

+            ep_get_addr[current_endp][5:0] <= ep_get_addr[current_endp][5:0] + 1;

+          end

+        end

+

+        WAIT_ACK : begin

+          if (ack_received) begin

+            data_toggle[current_endp] <= !data_toggle[current_endp];

+          end

+        end

+      endcase

+    end

+

+    for (j = 0; j < NUM_IN_EPS; j = j + 1) begin

+      if (reset || reset_ep[j]) begin

+        data_toggle[j] <= 0;

+        ep_get_addr[j][5:0] <= 0;

+      end

+    end

+  end

+

+endmodule

diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_out_arb.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_out_arb.v
new file mode 100644
index 0000000..968f406
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_out_arb.v
@@ -0,0 +1,25 @@
+module usb_fs_out_arb #(

+  parameter NUM_OUT_EPS = 1

+) (

+  ////////////////////

+  // endpoint interface 

+  ////////////////////

+  input [NUM_OUT_EPS-1:0] out_ep_req,

+  output reg [NUM_OUT_EPS-1:0] out_ep_grant

+);

+  integer i;

+  reg grant;

+

+  always @* begin

+    grant = 0;

+

+    for (i = 0; i < NUM_OUT_EPS; i = i + 1) begin

+      out_ep_grant[i] <= 0;

+

+      if (out_ep_req[i] && !grant) begin

+        out_ep_grant[i] <= 1;

+        grant = 1;

+      end

+    end

+  end

+endmodule

diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_out_pe.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_out_pe.v
new file mode 100644
index 0000000..4a76ac2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_out_pe.v
@@ -0,0 +1,417 @@
+// The OUT Protocol Engine receives data from the host.

+module usb_fs_out_pe #(

+  parameter NUM_OUT_EPS = 1,

+  parameter MAX_OUT_PACKET_SIZE = 32

+) (

+  input clk,

+  input reset,

+  input [NUM_OUT_EPS-1:0] reset_ep,

+  input [6:0] dev_addr,

+

+  ////////////////////

+  // endpoint interface

+  ////////////////////

+  output [NUM_OUT_EPS-1:0] out_ep_data_avail,

+  output reg [NUM_OUT_EPS-1:0] out_ep_setup = 0,

+  input [NUM_OUT_EPS-1:0] out_ep_data_get,

+  output reg [7:0] out_ep_data,

+  input [NUM_OUT_EPS-1:0] out_ep_stall,

+  output reg [NUM_OUT_EPS-1:0] out_ep_acked = 0,

+  // Added to provide a more constant way of detecting the current OUT EP than data get

+  input [NUM_OUT_EPS-1:0] out_ep_grant,

+

+  ////////////////////

+  // rx path

+  ////////////////////

+

+  // Strobed on reception of packet.

+  input rx_pkt_start,

+  input rx_pkt_end,

+  input rx_pkt_valid,

+

+  // Most recent packet received.

+  input [3:0] rx_pid,

+  input [6:0] rx_addr,

+  input [3:0] rx_endp,

+  input [10:0] rx_frame_num,

+

+  // rx_data is pushed into endpoint controller.

+  input rx_data_put,

+  input [7:0] rx_data,

+

+

+  ////////////////////

+  // tx path

+  ////////////////////

+

+  // Strobe to send new packet.

+  output reg tx_pkt_start = 0,

+  input tx_pkt_end,

+  output reg [3:0] tx_pid = 0

+);

+  ////////////////////////////////////////////////////////////////////////////////

+  // endpoint state machine

+  ////////////////////////////////////////////////////////////////////////////////

+  localparam READY_FOR_PKT = 0;

+  localparam PUTTING_PKT = 1;

+  localparam GETTING_PKT = 2;

+  localparam STALL = 3;

+

+  reg [1:0] ep_state [NUM_OUT_EPS - 1:0];

+  reg [1:0] ep_state_next [NUM_OUT_EPS - 1:0];

+

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // out transfer state machine

+  ////////////////////////////////////////////////////////////////////////////////

+  localparam IDLE = 0;

+  localparam RCVD_OUT = 1;

+  localparam RCVD_DATA_START = 2;

+  localparam RCVD_DATA_END = 3;

+

+  reg [1:0] out_xfr_state = IDLE;

+  reg [1:0] out_xfr_state_next;

+

+  reg out_xfr_start = 0;

+  reg new_pkt_end = 0;

+  reg rollback_data = 0;

+

+

+  reg [3:0] out_ep_num = 0;

+

+

+  reg [NUM_OUT_EPS - 1:0] out_ep_data_avail_i = 0;

+  reg [NUM_OUT_EPS - 1:0] out_ep_data_avail_j = 0;

+

+  // set when the endpoint buffer is unable to receive the out transfer

+  reg nak_out_transfer = 0;

+

+  // data toggle state

+  reg [NUM_OUT_EPS - 1:0] data_toggle = 0;

+

+  // latched on valid OUT/SETUP token

+  reg [3:0] current_endp = 0;

+  wire [1:0] current_ep_state = ep_state[current_endp];

+

+  // endpoint data buffer

+  reg [7:0] out_data_buffer [(MAX_OUT_PACKET_SIZE * NUM_OUT_EPS) - 1:0];

+

+  // current get_addr when outputting a packet from the buffer

+  reg [5:0] ep_get_addr [NUM_OUT_EPS - 1:0];

+  reg [5:0] ep_get_addr_next [NUM_OUT_EPS - 1:0];

+

+

+  // endpoint put_addrs when inputting a packet into the buffer

+  reg [5:0] ep_put_addr [NUM_OUT_EPS - 1:0];

+

+  // total buffer put addr, uses endpoint number and that endpoints current

+  // put address

+  wire [8:0] buffer_put_addr = {current_endp[3:0], ep_put_addr[current_endp][4:0]};

+  wire [8:0] buffer_get_addr = {out_ep_num[3:0], ep_get_addr[out_ep_num][4:0]};

+

+  wire token_received =

+    rx_pkt_end &&

+    rx_pkt_valid &&

+    rx_pid[1:0] == 2'b01 &&

+    rx_addr == dev_addr &&

+    rx_endp < NUM_OUT_EPS;

+

+  wire out_token_received =

+    token_received &&

+    rx_pid[3:2] == 2'b00;

+

+  wire setup_token_received =

+    token_received &&

+    rx_pid[3:2] == 2'b11;

+

+  wire invalid_packet_received =

+    rx_pkt_end &&

+    !rx_pkt_valid;

+

+  wire data_packet_received =

+    rx_pkt_end &&

+    rx_pkt_valid &&

+    rx_pid[2:0] == 3'b011;

+

+  wire non_data_packet_received =

+    rx_pkt_end &&

+    rx_pkt_valid &&

+    rx_pid[2:0] != 3'b011;

+

+  //reg last_data_toggle = 0;

+

+  wire bad_data_toggle =

+    data_packet_received &&

+    rx_pid[3] != data_toggle[rx_endp];

+

+    //last_data_toggle == data_toggle[current_endp];

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // endpoint state machine

+  ////////////////////////////////////////////////////////////////////////////////

+

+  genvar ep_num;

+  generate

+    for (ep_num = 0; ep_num < NUM_OUT_EPS; ep_num = ep_num + 1) begin

+      always @* begin

+

+        ep_state_next[ep_num] <= ep_state[ep_num];

+

+        if (out_ep_stall[ep_num]) begin

+          ep_state_next[ep_num] <= STALL;

+

+        end else begin

+          case (ep_state[ep_num])

+            READY_FOR_PKT : begin

+              if (out_xfr_start && rx_endp == ep_num) begin

+                ep_state_next[ep_num] <= PUTTING_PKT;

+

+              end else begin

+                ep_state_next[ep_num] <= READY_FOR_PKT;

+              end

+            end

+

+            PUTTING_PKT : begin

+              if (new_pkt_end && current_endp == ep_num) begin

+                ep_state_next[ep_num] <= GETTING_PKT;

+

+              end else if (rollback_data && current_endp == ep_num) begin

+                ep_state_next[ep_num] <= READY_FOR_PKT;

+

+              end else begin

+                ep_state_next[ep_num] <= PUTTING_PKT;

+              end

+            end

+

+            GETTING_PKT : begin

+

+              if (ep_get_addr[ep_num][5:0] >= (ep_put_addr[ep_num][5:0] - 6'H2)) begin

+                ep_state_next[ep_num] <= READY_FOR_PKT;

+

+              end else begin

+                ep_state_next[ep_num] <= GETTING_PKT;

+              end

+            end

+

+            STALL : begin

+              if (setup_token_received && rx_endp == ep_num) begin

+                ep_state_next[ep_num] <= READY_FOR_PKT;

+

+              end else begin

+                ep_state_next[ep_num] <= STALL;

+              end

+            end

+

+            default begin

+              ep_state_next[ep_num] <= READY_FOR_PKT;

+            end

+          endcase

+        end

+

+        // Determine the next get_address (init, inc, maintain)

+        if (ep_state_next[ep_num][1:0] == READY_FOR_PKT) begin

+          ep_get_addr_next[ep_num][5:0] <= 0;

+        end else if (ep_state_next[ep_num][1:0] == GETTING_PKT && out_ep_data_get[ep_num]) begin

+          ep_get_addr_next[ep_num][5:0] <= ep_get_addr[ep_num][5:0] + 6'H1;

+        end else begin

+          ep_get_addr_next[ep_num][5:0] <= ep_get_addr[ep_num][5:0];

+        end

+

+      end  // end of the always @*

+

+      // Advance the state to the next one.

+      always @(posedge clk) begin

+        if (reset || reset_ep[ep_num]) begin

+          ep_state[ep_num] <= READY_FOR_PKT;

+        end else begin

+          ep_state[ep_num] <= ep_state_next[ep_num];

+        end

+

+        ep_get_addr[ep_num][5:0] <= ep_get_addr_next[ep_num][5:0];

+      end

+

+

+      assign out_ep_data_avail[ep_num] =

+        (ep_get_addr[ep_num][5:0] < (ep_put_addr[ep_num][5:0] - 6'H2)) &&

+        (ep_state[ep_num][1:0] == GETTING_PKT);

+

+

+

+    end

+  endgenerate

+

+  integer i;

+  always @(posedge clk) begin

+    if (reset) begin

+      out_ep_setup <= 0;

+

+    end else begin

+      if (setup_token_received) begin

+        out_ep_setup[rx_endp] <= 1;

+      end else if (out_token_received) begin

+        out_ep_setup[rx_endp] <= 0;

+      end

+    end

+

+    for (i = 0; i < NUM_OUT_EPS; i = i + 1) begin

+      if (reset_ep[i]) begin

+        out_ep_setup[i] <= 0;

+      end

+    end

+  end

+

+  always @(posedge clk) out_ep_data <= out_data_buffer[buffer_get_addr][7:0];

+  // use the bus grant line to determine the out_ep_num (where the data is)

+  integer ep_num_decoder;

+  always @* begin

+    out_ep_num <= 0;

+

+    for (ep_num_decoder = 0; ep_num_decoder < NUM_OUT_EPS; ep_num_decoder = ep_num_decoder + 1) begin

+      if (out_ep_grant[ep_num_decoder]) begin

+        out_ep_num <= ep_num_decoder;

+      end

+    end

+  end

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // out transfer state machine

+  ////////////////////////////////////////////////////////////////////////////////

+

+  always @* begin

+    out_ep_acked <= 0;

+    out_xfr_start <= 0;

+    out_xfr_state_next <= out_xfr_state;

+    tx_pkt_start <= 0;

+    tx_pid <= 0;

+    new_pkt_end <= 0;

+    rollback_data <= 0;

+

+    case (out_xfr_state)

+      IDLE : begin

+        if (out_token_received || setup_token_received) begin

+          out_xfr_state_next <= RCVD_OUT;

+          out_xfr_start <= 1;

+

+        end else begin

+          out_xfr_state_next <= IDLE;

+        end

+      end

+

+      RCVD_OUT : begin

+        if (rx_pkt_start) begin

+          out_xfr_state_next <= RCVD_DATA_START;

+

+        end else begin

+          out_xfr_state_next <= RCVD_OUT;

+        end

+      end

+

+      RCVD_DATA_START : begin

+        if (bad_data_toggle) begin

+          out_xfr_state_next <= IDLE;

+          rollback_data <= 1;

+          tx_pkt_start <= 1;

+          tx_pid <= 4'b0010; // ACK

+

+        end else if (invalid_packet_received || non_data_packet_received) begin

+          out_xfr_state_next <= IDLE;

+          rollback_data <= 1;

+

+        end else if (data_packet_received) begin

+          out_xfr_state_next <= RCVD_DATA_END;

+

+        end else begin

+          out_xfr_state_next <= RCVD_DATA_START;

+        end

+      end

+

+      RCVD_DATA_END : begin

+        out_xfr_state_next <= IDLE;

+        tx_pkt_start <= 1;

+

+        if (ep_state[current_endp] == STALL) begin

+          tx_pid <= 4'b1110; // STALL

+

+        end else if (nak_out_transfer) begin

+          tx_pid <= 4'b1010; // NAK

+          rollback_data <= 1;

+

+        end else begin

+          tx_pid <= 4'b0010; // ACK

+          new_pkt_end <= 1;

+          out_ep_acked[current_endp] <= 1;

+

+        //end else begin

+        //  tx_pid <= 4'b0010; // ACK

+        //  rollback_data <= 1;

+        end

+      end

+

+      default begin

+        out_xfr_state_next <= IDLE;

+      end

+    endcase

+  end

+

+  wire current_ep_busy =

+    (ep_state[current_endp] == GETTING_PKT) ||

+    (ep_state[current_endp] == READY_FOR_PKT);

+

+  integer j;

+  always @(posedge clk) begin

+    if (reset) begin

+      out_xfr_state <= IDLE;

+    end else begin

+      out_xfr_state <= out_xfr_state_next;

+

+      if (out_xfr_start) begin

+        current_endp <= rx_endp;

+        //last_data_toggle <= setup_token_received ? 0 : data_toggle[rx_endp];

+      end

+

+      if (new_pkt_end) begin

+        data_toggle[current_endp] <= !data_toggle[current_endp];

+      end

+

+      if (setup_token_received) begin

+        data_toggle[rx_endp] <= 0;

+      end

+

+      case (out_xfr_state)

+        IDLE : begin

+        end

+

+        RCVD_OUT : begin

+          if (current_ep_busy) begin

+            nak_out_transfer <= 1;

+          end else begin

+            nak_out_transfer <= 0;

+            ep_put_addr[current_endp][5:0] <= 0;

+          end

+        end

+

+        RCVD_DATA_START : begin

+          if (!nak_out_transfer && rx_data_put && !ep_put_addr[current_endp][5]) begin

+            out_data_buffer[buffer_put_addr][7:0] <= rx_data;

+          end

+

+          if (!nak_out_transfer && rx_data_put) begin

+            ep_put_addr[current_endp][5:0] <= ep_put_addr[current_endp][5:0] + 6'H1;

+

+          end

+        end

+

+        RCVD_DATA_END : begin

+        end

+      endcase

+    end

+

+    for (j = 0; j < NUM_OUT_EPS; j = j + 1) begin

+      if (reset || reset_ep[j]) begin

+        data_toggle[j] <= 0;

+        ep_put_addr[j][5:0] <= 0;

+      end

+    end

+  end

+

+endmodule

diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_pe.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_pe.v
new file mode 100644
index 0000000..55d87fd
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_pe.v
@@ -0,0 +1,239 @@
+module usb_fs_pe #(

+  parameter [4:0] NUM_OUT_EPS = 1,

+  parameter [4:0] NUM_IN_EPS = 1

+) (

+  input clk,

+  input [6:0] dev_addr,

+

+

+  ////////////////////////////////////////////////////////////////////////////////

+  ////////////////////////////////////////////////////////////////////////////////

+  /// USB Endpoint Interface

+  ////////////////////////////////////////////////////////////////////////////////

+  ////////////////////////////////////////////////////////////////////////////////

+

+  ////////////////////

+  // global endpoint interface

+  ////////////////////

+  input reset,

+

+

+  ////////////////////

+  // out endpoint interfaces

+  ////////////////////

+  input [NUM_OUT_EPS-1:0] out_ep_req,

+  output [NUM_OUT_EPS-1:0] out_ep_grant,

+  output [NUM_OUT_EPS-1:0] out_ep_data_avail,

+  output [NUM_OUT_EPS-1:0] out_ep_setup,

+  input [NUM_OUT_EPS-1:0] out_ep_data_get,

+  output [7:0] out_ep_data,

+  input [NUM_OUT_EPS-1:0] out_ep_stall,

+  output [NUM_OUT_EPS-1:0] out_ep_acked,

+

+

+  ////////////////////

+  // in endpoint interfaces

+  ////////////////////

+  input [NUM_IN_EPS-1:0] in_ep_req,

+  output [NUM_IN_EPS-1:0] in_ep_grant,

+  output [NUM_IN_EPS-1:0] in_ep_data_free,

+  input [NUM_IN_EPS-1:0] in_ep_data_put,

+  input [(NUM_IN_EPS*8)-1:0] in_ep_data,

+  input [NUM_IN_EPS-1:0] in_ep_data_done,

+  input [NUM_IN_EPS-1:0] in_ep_stall,

+  output [NUM_IN_EPS-1:0] in_ep_acked,

+

+

+  ////////////////////

+  // sof interface

+  ////////////////////

+  output sof_valid,

+  output [10:0] frame_index,

+

+

+

+  ////////////////////////////////////////////////////////////////////////////////

+  ////////////////////////////////////////////////////////////////////////////////

+  /// USB TX/RX Interface

+  ////////////////////////////////////////////////////////////////////////////////

+  ////////////////////////////////////////////////////////////////////////////////

+  output usb_p_tx,

+  output usb_n_tx,

+

+  input  usb_p_rx,

+  input  usb_n_rx,

+

+  output usb_tx_en,

+

+  output [7:0] debug

+);

+  // in pe interface

+  wire [7:0] arb_in_ep_data;

+

+  // rx interface

+  wire bit_strobe;

+  wire rx_pkt_start;

+  wire rx_pkt_end;

+  wire [3:0] rx_pid;

+  wire [6:0] rx_addr;

+  wire [3:0] rx_endp;

+  wire [10:0] rx_frame_num;

+  wire rx_data_put;

+  wire [7:0] rx_data;

+  wire rx_pkt_valid;

+

+  // tx mux

+  wire in_tx_pkt_start;

+  wire [3:0] in_tx_pid;

+  wire out_tx_pkt_start;

+  wire [3:0] out_tx_pid;

+

+  // tx interface

+  wire tx_pkt_start;

+  wire tx_pkt_end;

+  wire [3:0] tx_pid;

+  wire tx_data_avail;

+  wire tx_data_get;

+  wire [7:0] tx_data;

+

+  // sof interface

+  assign sof_valid = rx_pkt_end && rx_pkt_valid && rx_pid == 4'b0101;

+  assign frame_index = rx_frame_num;

+

+

+  usb_fs_in_arb #(

+    .NUM_IN_EPS(NUM_IN_EPS)

+  ) usb_fs_in_arb_inst (

+    // endpoint interface

+    .in_ep_req(in_ep_req),

+    .in_ep_grant(in_ep_grant),

+    .in_ep_data(in_ep_data),

+

+    // protocol engine interface

+    .arb_in_ep_data(arb_in_ep_data)

+  );

+

+  usb_fs_out_arb #(

+    .NUM_OUT_EPS(NUM_OUT_EPS)

+  ) usb_fs_out_arb_inst (

+    // endpoint interface

+    .out_ep_req(out_ep_req),

+    .out_ep_grant(out_ep_grant)

+  );

+

+  usb_fs_in_pe #(

+    .NUM_IN_EPS(NUM_IN_EPS)

+  ) usb_fs_in_pe_inst (

+    .clk(clk),

+    .reset(reset),

+    .reset_ep({NUM_IN_EPS{1'b0}}),

+    .dev_addr(dev_addr),

+

+    // endpoint interface

+    .in_ep_data_free(in_ep_data_free),

+    .in_ep_data_put(in_ep_data_put),

+    .in_ep_data(arb_in_ep_data),

+    .in_ep_data_done(in_ep_data_done),

+    .in_ep_stall(in_ep_stall),

+    .in_ep_acked(in_ep_acked),

+

+    // rx path

+    .rx_pkt_start(rx_pkt_start),

+    .rx_pkt_end(rx_pkt_end),

+    .rx_pkt_valid(rx_pkt_valid),

+    .rx_pid(rx_pid),

+    .rx_addr(rx_addr),

+    .rx_endp(rx_endp),

+    .rx_frame_num(rx_frame_num),

+

+    // tx path

+    .tx_pkt_start(in_tx_pkt_start),

+    .tx_pkt_end(tx_pkt_end),

+    .tx_pid(in_tx_pid),

+    .tx_data_avail(tx_data_avail),

+    .tx_data_get(tx_data_get),

+    .tx_data(tx_data),

+

+    .debug(debug)

+  );

+

+  usb_fs_out_pe #(

+    .NUM_OUT_EPS(NUM_OUT_EPS)

+  ) usb_fs_out_pe_inst (

+    .clk(clk),

+    .reset(reset),

+    .reset_ep({NUM_OUT_EPS{1'b0}}),

+    .dev_addr(dev_addr),

+

+    // endpoint interface

+    .out_ep_data_avail(out_ep_data_avail),

+    .out_ep_data_get(out_ep_data_get),

+    .out_ep_data(out_ep_data),

+    .out_ep_setup(out_ep_setup),

+    .out_ep_stall(out_ep_stall),

+    .out_ep_acked(out_ep_acked),

+    .out_ep_grant(out_ep_grant),

+

+    // rx path

+    .rx_pkt_start(rx_pkt_start),

+    .rx_pkt_end(rx_pkt_end),

+    .rx_pkt_valid(rx_pkt_valid),

+    .rx_pid(rx_pid),

+    .rx_addr(rx_addr),

+    .rx_endp(rx_endp),

+    .rx_frame_num(rx_frame_num),

+    .rx_data_put(rx_data_put),

+    .rx_data(rx_data),

+

+    // tx path

+    .tx_pkt_start(out_tx_pkt_start),

+    .tx_pkt_end(tx_pkt_end),

+    .tx_pid(out_tx_pid)

+  );

+

+  usb_fs_rx usb_fs_rx_inst (

+    .clk_48mhz(clk),

+    .reset(reset),

+    .dp(usb_p_rx),

+    .dn(usb_n_rx),

+    .bit_strobe(bit_strobe),

+    .pkt_start(rx_pkt_start),

+    .pkt_end(rx_pkt_end),

+    .pid(rx_pid),

+    .addr(rx_addr),

+    .endp(rx_endp),

+    .frame_num(rx_frame_num),

+    .rx_data_put(rx_data_put),

+    .rx_data(rx_data),

+    .valid_packet(rx_pkt_valid)

+  );

+

+  usb_fs_tx_mux usb_fs_tx_mux_inst (

+    // interface to IN Protocol Engine

+    .in_tx_pkt_start(in_tx_pkt_start),

+    .in_tx_pid(in_tx_pid),

+

+    // interface to OUT Protocol Engine

+    .out_tx_pkt_start(out_tx_pkt_start),

+    .out_tx_pid(out_tx_pid),

+

+    // interface to tx module

+    .tx_pkt_start(tx_pkt_start),

+    .tx_pid(tx_pid)

+  );

+

+  usb_fs_tx usb_fs_tx_inst (

+    .clk_48mhz(clk),

+    .reset(reset),

+    .bit_strobe(bit_strobe),

+    .oe(usb_tx_en),

+    .dp(usb_p_tx),

+    .dn(usb_n_tx),

+    .pkt_start(tx_pkt_start),

+    .pkt_end(tx_pkt_end),

+    .pid(tx_pid),

+    .tx_data_avail(tx_data_avail),

+    .tx_data_get(tx_data_get),

+    .tx_data(tx_data)

+  );

+endmodule

diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_rx.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_rx.v
new file mode 100644
index 0000000..3ea598d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_rx.v
@@ -0,0 +1,366 @@
+module usb_fs_rx (

+  // A 48MHz clock is required to recover the clock from the incoming data. 

+  input clk_48mhz,

+  input reset,

+

+  // USB data+ and data- lines.

+  input dp,

+  input dn,

+

+  // pulse on every bit transition.

+  output bit_strobe,

+

+  // Pulse on beginning of new packet.

+  output pkt_start,

+

+  // Pulse on end of current packet.

+  output pkt_end,

+

+  // Most recent packet decoded.

+  output [3:0] pid,

+  output reg [6:0] addr = 0,

+  output reg [3:0] endp = 0,

+  output reg [10:0] frame_num = 0,

+

+  // Pulse on valid data on rx_data.

+  output rx_data_put,

+  output [7:0] rx_data,

+

+  // Most recent packet passes PID and CRC checks

+  output valid_packet

+);

+  wire clk = clk_48mhz;

+

+  ////////////////////////////////////////////////////////////////////////////////

+  ////////////////////////////////////////////////////////////////////////////////

+  ////////

+  //////// usb receive path

+  ////////

+  ////////////////////////////////////////////////////////////////////////////////

+  ////////////////////////////////////////////////////////////////////////////////

+

+  

+  ////////////////////////////////////////////////////////////////////////////////

+  // double flop for metastability

+  /*

+    all asynchronous inputs into the RTL need to be double-flopped to protect 

+    against metastable scenarios.  if the RTL clock samples an asynchronous signal

+    at the same time the signal is transitioning the result is undefined.  flopping

+    the signal twice ensures it will be either 1 or 0 and nothing in between.

+  */

+

+  reg [3:0] dpair_q = 0;

+

+  always @(posedge clk) begin

+      dpair_q[3:0] <= {dpair_q[1:0], dp, dn};

+  end

+

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // line state recovery state machine

+  /*

+    the recieve path doesn't currently use a differential reciever.  because of

+    this there is a chance that one of the differential pairs will appear to have

+    changed to the new state while the other is still in the old state.  the 

+    following state machine detects transitions and waits an extra sampling clock

+    before decoding the state on the differential pair.  this transition period 

+    will only ever last for one clock as long as there is no noise on the line.

+    if there is enough noise on the line then the data may be corrupted and the

+    packet will fail the data integrity checks.

+  */

+

+  reg [2:0] line_state = 0;

+  localparam  DT = 3'b100;

+  localparam  DJ = 3'b010;

+  localparam  DK = 3'b001;

+  localparam SE0 = 3'b000;

+  localparam SE1 = 3'b011;

+

+  wire [1:0] dpair = dpair_q[3:2];

+

+  always @(posedge clk) begin

+      case (line_state)

+          // if we are in a transition state, then we can sample the pair and 

+          // move to the next corresponding line state

+          DT : begin

+              case (dpair)

+                  2'b10 : line_state <= DJ;

+                  2'b01 : line_state <= DK;

+                  2'b00 : line_state <= SE0;

+                  2'b11 : line_state <= SE1;

+              endcase

+          end

+

+          // if we are in a valid line state and the value of the pair changes,

+          // then we need to move to the transition state

+          DJ  : if (dpair != 2'b10) line_state <= DT;

+          DK  : if (dpair != 2'b01) line_state <= DT;

+          SE0 : if (dpair != 2'b00) line_state <= DT;

+          SE1 : if (dpair != 2'b11) line_state <= DT;        

+

+          // if we are in an invalid state we should move to the transition state

+          default : line_state <= DT;

+      endcase

+  end

+

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // clock recovery

+  /*

+    the DT state from the line state recovery state machine is used to align to 

+    transmit clock.  the line state is sampled in the middle of the bit time.

+

+    example of signal relationships

+    -------------------------------

+    line_state        DT  DJ  DJ  DJ  DT  DK  DK  DK  DK  DK  DK  DT  DJ  DJ  DJ

+    line_state_valid  ________----____________----____________----________----____

+    bit_phase         0   0   1   2   3   0   1   2   3   0   1   2   0   1   2

+  */

+

+  reg [1:0] bit_phase = 0;

+

+  wire line_state_valid = (bit_phase == 1);

+  assign bit_strobe = (bit_phase == 2);

+

+  always @(posedge clk) begin

+      // keep track of phase within each bit

+      if (line_state == DT) begin

+          bit_phase <= 0;

+

+      end else begin

+          bit_phase <= bit_phase + 1;

+      end

+  end

+

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // packet detection 

+  /*

+    usb uses a sync to denote the beginning of a packet and two single-ended-0 to

+    denote the end of a packet.  this state machine recognizes the beginning and

+    end of packets for subsequent layers to process.

+  */

+  reg [5:0] line_history = 0;

+  reg packet_valid = 0;

+  reg next_packet_valid;

+  wire packet_start = next_packet_valid && !packet_valid;

+  wire packet_end = !next_packet_valid && packet_valid;

+

+  always @* begin

+    if (line_state_valid) begin

+      // check for packet start: KJKJKK

+      if (!packet_valid && line_history[5:0] == 6'b100101) begin

+        next_packet_valid <= 1;

+      end

+ 

+      // check for packet end: SE0 SE0

+      else if (packet_valid && line_history[3:0] == 4'b0000) begin

+        next_packet_valid <= 0;

+

+      end else begin

+        next_packet_valid <= packet_valid;

+      end

+    end else begin

+      next_packet_valid <= packet_valid;

+    end

+  end

+

+  always @(posedge clk) begin

+    if (reset) begin

+      line_history <= 6'b101010;

+      packet_valid <= 0;

+    end else begin

+      // keep a history of the last two states on the line

+      if (line_state_valid) begin

+        line_history[5:0] <= {line_history[3:0], line_state[1:0]};

+      end

+    end

+    packet_valid <= next_packet_valid;

+  end

+

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // NRZI decode

+  /*

+    in order to ensure there are enough bit transitions for a receiver to recover

+    the clock usb uses NRZI encoding.

+

+    https://en.wikipedia.org/wiki/Non-return-to-zero

+  */

+  reg dvalid_raw;

+  reg din;

+

+  always @* begin

+    case (line_history[3:0])

+      4'b0101 : din <= 1;

+      4'b0110 : din <= 0;

+      4'b1001 : din <= 0;

+      4'b1010 : din <= 1;

+      default : din <= 0;

+    endcase

+ 

+    if (packet_valid && line_state_valid) begin

+      case (line_history[3:0])

+        4'b0101 : dvalid_raw <= 1;

+        4'b0110 : dvalid_raw <= 1;

+        4'b1001 : dvalid_raw <= 1;

+        4'b1010 : dvalid_raw <= 1;

+        default : dvalid_raw <= 0;

+      endcase

+    end else begin

+      dvalid_raw <= 0;

+    end

+  end

+

+  reg [5:0] bitstuff_history = 0;

+

+  always @(posedge clk) begin

+    if (reset || packet_end) begin

+      bitstuff_history <= 6'b000000;

+    end else begin

+      if (dvalid_raw) begin

+        bitstuff_history <= {bitstuff_history[4:0], din};

+      end

+    end  

+  end

+

+  wire dvalid = dvalid_raw && !(bitstuff_history == 6'b111111);

+

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // save and check pid

+  /*

+    shift in the entire 8-bit pid with an additional 9th bit used as a sentinal.

+  */

+

+  reg [8:0] full_pid = 0;

+  wire pid_valid = full_pid[4:1] == ~full_pid[8:5];

+  wire pid_complete = full_pid[0];

+

+  always @(posedge clk) begin

+    if (packet_start) begin

+      full_pid <= 9'b100000000;

+    end

+

+    if (dvalid && !pid_complete) begin

+        full_pid <= {din, full_pid[8:1]};

+    end

+  end

+

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // check crc5

+  reg [4:0] crc5 = 0;

+  wire crc5_valid = crc5 == 5'b01100;

+  wire crc5_invert = din ^ crc5[4];

+  always @(posedge clk) begin

+    if (packet_start) begin

+      crc5 <= 5'b11111;

+    end

+

+    if (dvalid && pid_complete) begin

+      crc5[4] <= crc5[3];

+      crc5[3] <= crc5[2];

+      crc5[2] <= crc5[1] ^ crc5_invert;

+      crc5[1] <= crc5[0];

+      crc5[0] <= crc5_invert;

+    end

+  end

+

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // check crc16

+  reg [15:0] crc16 = 0;

+  wire crc16_valid = crc16 == 16'b1000000000001101;

+  wire crc16_invert = din ^ crc16[15];  

+

+  always @(posedge clk) begin

+    if (packet_start) begin

+      crc16 <= 16'b1111111111111111;

+    end

+

+    if (dvalid && pid_complete) begin

+      crc16[15] <= crc16[14] ^ crc16_invert;

+      crc16[14] <= crc16[13];

+      crc16[13] <= crc16[12];

+      crc16[12] <= crc16[11];

+      crc16[11] <= crc16[10];

+      crc16[10] <= crc16[9];

+      crc16[9] <= crc16[8];

+      crc16[8] <= crc16[7];

+      crc16[7] <= crc16[6];

+      crc16[6] <= crc16[5];

+      crc16[5] <= crc16[4];

+      crc16[4] <= crc16[3];

+      crc16[3] <= crc16[2];

+      crc16[2] <= crc16[1] ^ crc16_invert;

+      crc16[1] <= crc16[0];

+      crc16[0] <= crc16_invert;

+    end

+  end

+

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // output control signals

+  wire pkt_is_token = full_pid[2:1] == 2'b01;

+  wire pkt_is_data = full_pid[2:1] == 2'b11;

+  wire pkt_is_handshake = full_pid[2:1] == 2'b10;

+

+

+  // TODO: need to check for data packet babble

+  // TODO: do i need to check for bitstuff error?

+  assign valid_packet = pid_valid && (

+    (pkt_is_handshake) || 

+    (pkt_is_data && crc16_valid) ||

+    (pkt_is_token && crc5_valid)

+  );

+  

+

+  reg [11:0] token_payload = 0;

+  wire token_payload_done = token_payload[0];

+

+  always @(posedge clk) begin

+    if (packet_start) begin

+      token_payload <= 12'b100000000000;

+    end

+

+    if (dvalid && pid_complete && pkt_is_token && !token_payload_done) begin

+      token_payload <= {din, token_payload[11:1]};

+    end

+  end

+

+  always @(posedge clk) begin

+    if (token_payload_done && pkt_is_token) begin

+      addr <= token_payload[7:1];

+      endp <= token_payload[11:8];

+      frame_num <= token_payload[11:1];

+    end

+  end

+

+  assign pkt_start = packet_start;

+  assign pkt_end = packet_end; 

+  assign pid = full_pid[4:1]; 

+  //assign addr = token_payload[7:1];

+  //assign endp = token_payload[11:8];

+  //assign frame_num = token_payload[11:1];

+  

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // deserialize and output data

+  //assign rx_data_put = dvalid && pid_complete && pkt_is_data;

+  reg [8:0] rx_data_buffer = 0;

+  wire rx_data_buffer_full = rx_data_buffer[0];

+  assign rx_data_put = rx_data_buffer_full;

+  assign rx_data = rx_data_buffer[8:1];

+

+  always @(posedge clk) begin

+    if (packet_start || rx_data_buffer_full) begin

+      rx_data_buffer <= 9'b100000000;

+    end

+

+    if (dvalid && pid_complete && pkt_is_data) begin

+        rx_data_buffer <= {din, rx_data_buffer[8:1]};

+    end

+  end

+

+endmodule // usb_fs_rx

diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_tx.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_tx.v
new file mode 100644
index 0000000..c9ba07a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_tx.v
@@ -0,0 +1,243 @@
+module usb_fs_tx (

+  // A 48MHz clock is required to receive USB data at 12MHz

+  // it's simpler to juse use 48MHz everywhere

+  input clk_48mhz,

+  input reset,

+

+  // bit strobe from rx to align with senders clock

+  input bit_strobe,

+

+  // output enable to take ownership of bus and data out

+  output reg oe = 0,

+  output reg dp = 0,

+  output reg dn = 0,

+

+  // pulse to initiate new packet transmission

+  input pkt_start,

+  output pkt_end,

+

+  // pid to send

+  input [3:0] pid,

+

+  // tx logic pulls data until there is nothing available

+  input tx_data_avail,  

+  output reg tx_data_get = 0,

+  input [7:0] tx_data

+);

+  wire clk = clk_48mhz;

+

+  // save packet parameters at pkt_start

+  reg [3:0] pidq = 0;

+

+  always @(posedge clk) begin

+    if (pkt_start) begin

+      pidq <= pid;

+    end

+  end

+

+  reg [7:0] data_shift_reg = 0;

+  reg [7:0] oe_shift_reg = 0;

+  reg [7:0] se0_shift_reg = 0;

+

+

+  wire serial_tx_data = data_shift_reg[0];

+  wire serial_tx_oe = oe_shift_reg[0];

+  wire serial_tx_se0 = se0_shift_reg[0];

+

+

+  // serialize sync, pid, data payload, and crc16

+  reg byte_strobe = 0;

+  reg [2:0] bit_count = 0;

+

+  reg [4:0] bit_history_q = 0;

+  wire [5:0] bit_history = {serial_tx_data, bit_history_q};

+  wire bitstuff = bit_history == 6'b111111;

+  reg bitstuff_q = 0;

+  reg bitstuff_qq = 0;

+  reg bitstuff_qqq = 0;

+  reg bitstuff_qqqq = 0;

+

+

+  always @(posedge clk) begin

+    bitstuff_q <= bitstuff;

+    bitstuff_qq <= bitstuff_q;

+    bitstuff_qqq <= bitstuff_qq;

+    bitstuff_qqqq <= bitstuff_qqq;

+  end

+

+  assign pkt_end = bit_strobe && se0_shift_reg[1:0] == 2'b01;

+

+  reg data_payload = 0;

+

+  reg [31:0] pkt_state = 0;

+  localparam IDLE = 0;

+  localparam SYNC = 1;

+  localparam PID = 2;

+  localparam DATA_OR_CRC16_0 = 3;

+  localparam CRC16_1 = 4;

+  localparam EOP = 5;

+

+  reg [15:0] crc16 = 0;

+

+  always @(posedge clk) begin

+    case (pkt_state)

+      IDLE : begin

+        if (pkt_start) begin

+          pkt_state <= SYNC;

+        end

+      end

+

+      SYNC : begin

+        if (byte_strobe) begin

+          pkt_state <= PID;

+          data_shift_reg <= 8'b10000000;

+          oe_shift_reg <= 8'b11111111;

+          se0_shift_reg <= 8'b00000000;

+        end

+      end

+

+      PID : begin

+        if (byte_strobe) begin

+          if (pidq[1:0] == 2'b11) begin

+            pkt_state <= DATA_OR_CRC16_0;

+          end else begin

+            pkt_state <= EOP;

+          end

+

+          data_shift_reg <= {~pidq, pidq};

+          oe_shift_reg <= 8'b11111111;

+          se0_shift_reg <= 8'b00000000;

+        end

+      end

+

+      DATA_OR_CRC16_0 : begin

+        if (byte_strobe) begin

+          if (tx_data_avail) begin

+            pkt_state <= DATA_OR_CRC16_0;

+            data_payload <= 1;

+            tx_data_get <= 1;

+            data_shift_reg <= tx_data;

+            oe_shift_reg <= 8'b11111111;

+            se0_shift_reg <= 8'b00000000;

+          end else begin

+            pkt_state <= CRC16_1;

+            data_payload <= 0;

+            tx_data_get <= 0;

+            data_shift_reg <= ~{crc16[8], crc16[9], crc16[10], crc16[11], crc16[12], crc16[13], crc16[14], crc16[15]};

+            oe_shift_reg <= 8'b11111111;

+            se0_shift_reg <= 8'b00000000;

+          end

+        end else begin

+          tx_data_get <= 0; 

+        end

+      end

+

+      CRC16_1 : begin

+        if (byte_strobe) begin

+          pkt_state <= EOP;

+          data_shift_reg <= ~{crc16[0], crc16[1], crc16[2], crc16[3], crc16[4], crc16[5], crc16[6], crc16[7]};

+          oe_shift_reg <= 8'b11111111;

+          se0_shift_reg <= 8'b00000000;

+        end

+      end

+

+      EOP : begin

+        if (byte_strobe) begin

+          pkt_state <= IDLE;

+          oe_shift_reg <= 8'b00000111;

+          se0_shift_reg <= 8'b00000111;

+        end

+      end

+    endcase

+

+    if (bit_strobe && !bitstuff) begin

+      byte_strobe <= (bit_count == 3'b000);

+    end else begin

+      byte_strobe <= 0;

+    end

+

+    if (pkt_start) begin

+      bit_count <= 1;

+      bit_history_q <= 0;

+

+    end else if (bit_strobe) begin

+      // bitstuff

+      if (bitstuff /* && !serial_tx_se0*/) begin

+        bit_history_q <= bit_history[5:1];

+        data_shift_reg[0] <= 0;

+

+      // normal deserialize

+      end else begin

+        bit_count <= bit_count + 1;

+

+        data_shift_reg <= (data_shift_reg >> 1);

+        oe_shift_reg <= (oe_shift_reg >> 1);

+        se0_shift_reg <= (se0_shift_reg >> 1);

+

+        bit_history_q <= bit_history[5:1];

+      end

+    end

+  end

+

+

+

+  // calculate crc16

+  wire crc16_invert = serial_tx_data ^ crc16[15];  

+

+  always @(posedge clk) begin

+    if (pkt_start) begin

+      crc16 <= 16'b1111111111111111;

+    end

+

+    if (bit_strobe && data_payload && !bitstuff_qqqq && !pkt_start) begin

+      crc16[15] <= crc16[14] ^ crc16_invert;

+      crc16[14] <= crc16[13];

+      crc16[13] <= crc16[12];

+      crc16[12] <= crc16[11];

+      crc16[11] <= crc16[10];

+      crc16[10] <= crc16[9];

+      crc16[9] <= crc16[8];

+      crc16[8] <= crc16[7];

+      crc16[7] <= crc16[6];

+      crc16[6] <= crc16[5];

+      crc16[5] <= crc16[4];

+      crc16[4] <= crc16[3];

+      crc16[3] <= crc16[2];

+      crc16[2] <= crc16[1] ^ crc16_invert;

+      crc16[1] <= crc16[0];

+      crc16[0] <= crc16_invert;

+    end

+  end

+

+  reg [2:0] dp_eop = 0;

+

+

+  // nrzi and differential driving

+  always @(posedge clk) begin

+    if (pkt_start) begin

+      // J

+      dp <= 1;

+      dn <= 0;

+      

+      dp_eop <= 3'b100;

+

+    end else if (bit_strobe) begin

+      oe <= serial_tx_oe;

+

+      if (serial_tx_se0) begin

+        dp <= dp_eop[0];

+        dn <= 0;

+

+        dp_eop <= dp_eop >> 1;

+

+      end else if (serial_tx_data) begin

+        // value should stay the same, do nothing

+

+      end else begin

+        dp <= !dp;

+        dn <= !dn;

+      end

+    end

+  end 

+

+endmodule

diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_tx_mux.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_tx_mux.v
new file mode 100644
index 0000000..5716b46
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_fs_tx_mux.v
@@ -0,0 +1,16 @@
+module usb_fs_tx_mux (

+  // interface to IN Protocol Engine

+  input in_tx_pkt_start,

+  input [3:0] in_tx_pid,

+

+  // interface to OUT Protocol Engine

+  input out_tx_pkt_start,

+  input [3:0] out_tx_pid,

+

+  // interface to tx module

+  output tx_pkt_start,

+  output [3:0] tx_pid

+);

+  assign tx_pkt_start = in_tx_pkt_start | out_tx_pkt_start;

+  assign tx_pid = out_tx_pkt_start ? out_tx_pid : in_tx_pid;

+endmodule

diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_reset_det.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_reset_det.v
new file mode 100644
index 0000000..37f2aba
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_reset_det.v
@@ -0,0 +1,31 @@
+// detects USB port reset signal from host

+module usb_reset_det (

+  input clk,

+  output reset,

+

+  input usb_p_rx,

+  input usb_n_rx

+);

+  // reset detection

+  reg [16:0] reset_timer = 0;

+  reg reset_i = 0;

+

+

+  wire timer_expired = reset_timer > 16'd30000;

+  always @(posedge clk) reset_i <= timer_expired;

+  assign reset = reset_i;

+ 

+  

+  always @(posedge clk) begin

+    if (usb_p_rx || usb_n_rx) begin

+      reset_timer <= 0;

+    end else begin

+      // SE0 detected from host

+      if (!timer_expired) begin

+        // timer not expired yet, keep counting

+        reset_timer <= reset_timer + 1;

+      end

+    end

+  end

+  

+endmodule

diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_serial_ctrl_ep.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_serial_ctrl_ep.v
new file mode 100644
index 0000000..3842643
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_serial_ctrl_ep.v
@@ -0,0 +1,489 @@
+module usb_serial_ctrl_ep #(

+  parameter MAX_IN_PACKET_SIZE = 32,

+  parameter MAX_OUT_PACKET_SIZE = 32

+) (

+  input clk,

+  input reset,

+  output [6:0] dev_addr,

+

+  ////////////////////

+  // out endpoint interface

+  ////////////////////

+  output out_ep_req,

+  input out_ep_grant,

+  input out_ep_data_avail,

+  input out_ep_setup,

+  output out_ep_data_get,

+  input [7:0] out_ep_data,

+  output out_ep_stall,

+  input out_ep_acked,

+

+

+  ////////////////////

+  // in endpoint interface

+  ////////////////////

+  output in_ep_req,

+  input in_ep_grant,

+  input in_ep_data_free,

+  output in_ep_data_put,

+  output reg [7:0] in_ep_data = 0,

+  output in_ep_data_done,

+  output reg in_ep_stall,

+  input in_ep_acked

+);

+

+

+  localparam IDLE = 0;

+  localparam SETUP = 1;

+  localparam DATA_IN = 2;

+  localparam DATA_OUT = 3;

+  localparam STATUS_IN = 4;

+  localparam STATUS_OUT = 5;

+

+  reg [5:0] ctrl_xfr_state = IDLE;

+  reg [5:0] ctrl_xfr_state_next;

+

+

+

+  reg setup_stage_end = 0;

+  reg data_stage_end = 0;

+  reg status_stage_end = 0;

+  reg send_zero_length_data_pkt = 0;

+

+

+

+  // the default control endpoint gets assigned the device address

+  reg [6:0] dev_addr_i = 0;

+  assign dev_addr = dev_addr_i;

+

+  assign out_ep_req = out_ep_data_avail;

+  assign out_ep_data_get = out_ep_data_avail;

+  reg out_ep_data_valid = 0;

+  always @(posedge clk) out_ep_data_valid <= out_ep_data_avail && out_ep_grant;

+

+  // need to record the setup data

+  reg [3:0] setup_data_addr = 0;

+  reg [9:0] raw_setup_data [7:0];

+

+  wire [7:0] bmRequestType = raw_setup_data[0];

+  wire [7:0] bRequest = raw_setup_data[1];

+  wire [15:0] wValue = {raw_setup_data[3][7:0], raw_setup_data[2][7:0]};

+  wire [15:0] wIndex = {raw_setup_data[5][7:0], raw_setup_data[4][7:0]};

+  wire [15:0] wLength = {raw_setup_data[7][7:0], raw_setup_data[6][7:0]};

+

+  // keep track of new out data start and end

+  wire pkt_start;

+  wire pkt_end;

+

+  rising_edge_detector detect_pkt_start (

+    .clk(clk),

+    .in(out_ep_data_avail),

+    .out(pkt_start)

+  );

+

+  falling_edge_detector detect_pkt_end (

+    .clk(clk),

+    .in(out_ep_data_avail),

+    .out(pkt_end)

+  );

+

+  assign out_ep_stall = 1'b0;

+

+  wire setup_pkt_start = pkt_start && out_ep_setup;

+

+  // wire has_data_stage = wLength != 16'b0000000000000000; // this version for some reason causes a 16b carry which is slow

+  wire has_data_stage = |wLength;

+

+  wire out_data_stage;

+  assign out_data_stage = has_data_stage && !bmRequestType[7];

+

+  wire in_data_stage;

+  assign in_data_stage = has_data_stage && bmRequestType[7];

+

+  reg [7:0] bytes_sent = 0;

+  reg [6:0] rom_length = 0;

+

+  wire wLength_is_large = |wLength[15:7]; // 15-7 bits because rom_length is only 7 bits wide

+

+  wire all_data_sent =

+    (bytes_sent >= rom_length) ||

+    (!wLength_is_large && bytes_sent >= wLength[7:0]); // if the requested wLength is large, we only send rom_length bytes

+

+  wire more_data_to_send =

+    !all_data_sent;

+

+  wire in_data_transfer_done;

+

+  rising_edge_detector detect_in_data_transfer_done (

+    .clk(clk),

+    .in(all_data_sent),

+    .out(in_data_transfer_done)

+  );

+

+  assign in_ep_data_done = (in_data_transfer_done && ctrl_xfr_state == DATA_IN) || send_zero_length_data_pkt;

+

+  assign in_ep_req = ctrl_xfr_state == DATA_IN && more_data_to_send;

+  assign in_ep_data_put = ctrl_xfr_state == DATA_IN && more_data_to_send && in_ep_data_free;

+

+

+  reg [6:0] rom_addr = 0;

+

+  reg save_dev_addr = 0;

+  reg [6:0] new_dev_addr = 0;

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // control transfer state machine

+  ////////////////////////////////////////////////////////////////////////////////

+

+

+  always @* begin

+    setup_stage_end <= 0;

+    data_stage_end <= 0;

+    status_stage_end <= 0;

+    send_zero_length_data_pkt <= 0;

+

+    case (ctrl_xfr_state)

+      IDLE : begin

+        if (setup_pkt_start) begin

+          ctrl_xfr_state_next <= SETUP;

+        end else begin

+          ctrl_xfr_state_next <= IDLE;

+        end

+      end

+

+      SETUP : begin

+        if (pkt_end) begin

+          setup_stage_end <= 1;

+

+          if (in_data_stage) begin

+            ctrl_xfr_state_next <= DATA_IN;

+

+          end else if (out_data_stage) begin

+            ctrl_xfr_state_next <= DATA_OUT;

+

+          end else begin

+            ctrl_xfr_state_next <= STATUS_IN;

+            send_zero_length_data_pkt <= 1;

+          end

+

+        end else begin

+          ctrl_xfr_state_next <= SETUP;

+        end

+      end

+

+      DATA_IN : begin

+	if (in_ep_stall) begin

+          ctrl_xfr_state_next <= IDLE;

+          data_stage_end <= 1;

+          status_stage_end <= 1;

+

+	end else if (in_ep_acked && all_data_sent) begin

+          ctrl_xfr_state_next <= STATUS_OUT;

+          data_stage_end <= 1;

+

+        end else begin

+          ctrl_xfr_state_next <= DATA_IN;

+        end

+      end

+

+      DATA_OUT : begin

+        if (out_ep_acked) begin

+          ctrl_xfr_state_next <= STATUS_IN;

+          send_zero_length_data_pkt <= 1;

+          data_stage_end <= 1;

+

+        end else begin

+          ctrl_xfr_state_next <= DATA_OUT;

+        end

+      end

+

+      STATUS_IN : begin

+        if (in_ep_acked) begin

+          ctrl_xfr_state_next <= IDLE;

+          status_stage_end <= 1;

+

+        end else begin

+          ctrl_xfr_state_next <= STATUS_IN;

+        end

+      end

+

+      STATUS_OUT: begin

+        if (out_ep_acked) begin

+          ctrl_xfr_state_next <= IDLE;

+          status_stage_end <= 1;

+

+        end else begin

+          ctrl_xfr_state_next <= STATUS_OUT;

+        end

+      end

+

+      default begin

+        ctrl_xfr_state_next <= IDLE;

+      end

+    endcase

+  end

+

+  always @(posedge clk) begin

+    if (reset) begin

+      ctrl_xfr_state <= IDLE;

+    end else begin

+      ctrl_xfr_state <= ctrl_xfr_state_next;

+    end

+  end

+

+  always @(posedge clk) begin

+    in_ep_stall <= 0;

+

+    if (out_ep_setup && out_ep_data_valid) begin

+      raw_setup_data[setup_data_addr] <= out_ep_data;

+      setup_data_addr <= setup_data_addr + 1;

+    end

+

+    if (setup_stage_end) begin

+      case (bRequest)

+        'h06 : begin

+          // GET_DESCRIPTOR

+          case (wValue[15:8])

+            1 : begin

+              // DEVICE

+              rom_addr    <= 'h00;

+              rom_length  <= 'h12;

+            end

+

+            2 : begin

+              // CONFIGURATION

+              rom_addr    <= 'h12;

+              rom_length  <= 'h43;

+            end

+

+            3 : begin

+              // STRING

+              in_ep_stall <= 1;

+              rom_addr    <= 'h00;

+              rom_length  <= 'h00;

+            end

+

+            6 : begin

+              // DEVICE_QUALIFIER

+              in_ep_stall <= 1;

+              rom_addr   <= 'h00;

+              rom_length <= 'h00;

+            end

+            

+            default : begin

+              // DEVICE_QUALIFIER

+              in_ep_stall <= 1;

+              rom_addr   <= 'h00;

+              rom_length <= 'h00;

+            end

+

+          endcase

+        end

+

+        'h05 : begin

+          // SET_ADDRESS

+          rom_addr   <= 'h00;

+          rom_length <= 'h00;

+

+          // we need to save the address after the status stage ends

+          // this is because the status stage token will still be using

+          // the old device address

+          save_dev_addr <= 1;

+          new_dev_addr <= wValue[6:0];

+        end

+

+        'h09 : begin

+          // SET_CONFIGURATION

+          rom_addr   <= 'h00;

+          rom_length <= 'h00;

+        end

+

+        'h20 : begin

+          // SET_LINE_CODING

+          rom_addr   <= 'h00;

+          rom_length <= 'h00;

+        end

+

+        'h21 : begin

+          // GET_LINE_CODING

+          rom_addr   <= 'h55;

+          rom_length <= 'h07;

+        end

+

+        'h22 : begin

+          // SET_CONTROL_LINE_STATE

+          rom_addr   <= 'h00;

+          rom_length <= 'h00;

+        end

+

+        'h23 : begin

+          // SEND_BREAK

+          rom_addr   <= 'h00;

+          rom_length <= 'h00;

+        end

+

+        default begin

+          rom_addr   <= 'h00;

+          rom_length <= 'h00;

+        end

+      endcase

+    end

+

+    if (ctrl_xfr_state == DATA_IN && more_data_to_send && in_ep_grant && in_ep_data_free) begin

+      rom_addr <= rom_addr + 1;

+      bytes_sent <= bytes_sent + 1;

+    end

+

+    if (status_stage_end) begin

+      setup_data_addr <= 0;

+      bytes_sent <= 0;

+      rom_addr <= 0;

+      rom_length <= 0;

+

+      if (save_dev_addr) begin

+        save_dev_addr <= 0;

+        dev_addr_i <= new_dev_addr;

+      end

+    end

+

+    if (reset) begin

+      dev_addr_i <= 0;

+      setup_data_addr <= 0;

+      save_dev_addr <= 0;

+    end

+  end

+

+

+  `define CDC_ACM_ENDPOINT 2

+  `define CDC_RX_ENDPOINT 1

+  `define CDC_TX_ENDPOINT 1

+

+

+  always @* begin

+    case (rom_addr)

+      // device descriptor

+      'h000 : in_ep_data <= 18; // bLength

+      'h001 : in_ep_data <= 1; // bDescriptorType

+      'h002 : in_ep_data <= 'h00; // bcdUSB[0]

+      'h003 : in_ep_data <= 'h02; // bcdUSB[1]

+      'h004 : in_ep_data <= 'h02; // bDeviceClass (Communications Device Class)

+      'h005 : in_ep_data <= 'h00; // bDeviceSubClass (Abstract Control Model)

+      'h006 : in_ep_data <= 'h00; // bDeviceProtocol (No class specific protocol required)

+      'h007 : in_ep_data <= MAX_IN_PACKET_SIZE; // bMaxPacketSize0

+

+      'h008 : in_ep_data <= 'h50; // idVendor[0] http://wiki.openmoko.org/wiki/USB_Product_IDs

+      'h009 : in_ep_data <= 'h1d; // idVendor[1]

+      'h00A : in_ep_data <= 'h30; // idProduct[0]

+      'h00B : in_ep_data <= 'h61; // idProduct[1]

+

+      'h00C : in_ep_data <= 0; // bcdDevice[0]

+      'h00D : in_ep_data <= 0; // bcdDevice[1]

+      'h00E : in_ep_data <= 0; // iManufacturer

+      'h00F : in_ep_data <= 0; // iProduct

+      'h010 : in_ep_data <= 0; // iSerialNumber

+      'h011 : in_ep_data <= 1; // bNumConfigurations

+

+      // configuration descriptor

+      'h012 : in_ep_data <= 9; // bLength

+      'h013 : in_ep_data <= 2; // bDescriptorType

+      'h014 : in_ep_data <= (9+9+5+5+4+5+7+9+7+7); // wTotalLength[0]

+      'h015 : in_ep_data <= 0; // wTotalLength[1]

+      'h016 : in_ep_data <= 2; // bNumInterfaces

+      'h017 : in_ep_data <= 1; // bConfigurationValue

+      'h018 : in_ep_data <= 0; // iConfiguration

+      'h019 : in_ep_data <= 'hC0; // bmAttributes

+      'h01A : in_ep_data <= 50; // bMaxPower

+

+      // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12

+      'h01B : in_ep_data <= 9; // bLength

+      'h01C : in_ep_data <= 4; // bDescriptorType

+      'h01D : in_ep_data <= 0; // bInterfaceNumber

+      'h01E : in_ep_data <= 0; // bAlternateSetting

+      'h01F : in_ep_data <= 1; // bNumEndpoints

+      'h020 : in_ep_data <= 2; // bInterfaceClass (Communications Device Class)

+      'h021 : in_ep_data <= 2; // bInterfaceSubClass (Abstract Control Model)

+      'h022 : in_ep_data <= 0; // bInterfaceProtocol (0 = ?, 1 = AT Commands: V.250 etc)

+      'h023 : in_ep_data <= 0; // iInterface

+

+      // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26

+      'h024 : in_ep_data <= 5;					// bFunctionLength

+	    'h025 : in_ep_data <= 'h24;					// bDescriptorType

+	    'h026 : in_ep_data <= 'h00;					// bDescriptorSubtype

+	    'h027 : in_ep_data <= 'h10;

+      'h028 : in_ep_data <= 'h01;				// bcdCDC

+

+	    // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27

+	    'h029 : in_ep_data <= 5;					// bFunctionLength

+	    'h02A : in_ep_data <= 'h24;					// bDescriptorType

+	    'h02B : in_ep_data <= 'h01;					// bDescriptorSubtype

+	    'h02C : in_ep_data <= 'h00;					// bmCapabilities

+	    'h02D : in_ep_data <= 1;					// bDataInterface

+

+	    // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28

+	    'h02E : in_ep_data <= 4;					// bFunctionLength

+	    'h02F : in_ep_data <= 'h24;					// bDescriptorType

+	    'h030 : in_ep_data <= 'h02;					// bDescriptorSubtype

+	    'h031 : in_ep_data <= 'h06;					// bmCapabilities

+

+	    // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33

+    	'h032 : in_ep_data <= 5;					// bFunctionLength

+    	'h033 : in_ep_data <= 'h24;					// bDescriptorType

+    	'h034 : in_ep_data <= 'h06;					// bDescriptorSubtype

+    	'h035 : in_ep_data <= 0;					// bMasterInterface

+    	'h036 : in_ep_data <= 1;					// bSlaveInterface0

+

+    	// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13

+    	'h037 : in_ep_data <= 7;					// bLength

+    	'h038 : in_ep_data <= 5;					// bDescriptorType

+    	'h039 : in_ep_data <= `CDC_ACM_ENDPOINT | 'h80;		// bEndpointAddress

+    	'h03A : in_ep_data <= 'h03;					// bmAttributes (0x03=intr)

+    	'h03B : in_ep_data <= 8;     // wMaxPacketSize[0]

+      'h03C : in_ep_data <= 0;			// wMaxPacketSize[1]

+    	'h03D : in_ep_data <= 64;					// bInterval

+

+    	// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12

+    	'h03E : in_ep_data <= 9;					// bLength

+    	'h03F : in_ep_data <= 4;					// bDescriptorType

+    	'h040 : in_ep_data <= 1;					// bInterfaceNumber

+    	'h041 : in_ep_data <= 0;					// bAlternateSetting

+    	'h042 : in_ep_data <= 2;					// bNumEndpoints

+    	'h043 : in_ep_data <= 'h0A;					// bInterfaceClass

+    	'h044 : in_ep_data <= 'h00;					// bInterfaceSubClass

+    	'h045 : in_ep_data <= 'h00;					// bInterfaceProtocol

+    	'h046 : in_ep_data <= 0;					// iInterface

+

+    	// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13

+    	'h047 : in_ep_data <= 7;					// bLength

+    	'h048 : in_ep_data <= 5;					// bDescriptorType

+    	'h049 : in_ep_data <= `CDC_RX_ENDPOINT;			// bEndpointAddress

+    	'h04A : in_ep_data <= 'h02;					// bmAttributes (0x02=bulk)

+    	'h04B : in_ep_data <= MAX_IN_PACKET_SIZE; // wMaxPacketSize[0]

+      'h04C : in_ep_data <= 0;				// wMaxPacketSize[1]

+    	'h04D : in_ep_data <= 0;					// bInterval

+

+    	// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13

+    	'h04E : in_ep_data <= 7;					// bLength

+    	'h04F : in_ep_data <= 5;					// bDescriptorType

+    	'h050 : in_ep_data <= `CDC_TX_ENDPOINT | 'h80;			// bEndpointAddress

+    	'h051 : in_ep_data <= 'h02;					// bmAttributes (0x02=bulk)

+

+    	'h052 : in_ep_data <= MAX_OUT_PACKET_SIZE; // wMaxPacketSize[0]

+      'h053 : in_ep_data <= 0;				// wMaxPacketSize[1]

+    	'h054 : in_ep_data <= 0;				// bInterval

+

+      // LINE_CODING

+      'h055 : in_ep_data <= 'h80; // dwDTERate[0]

+      'h056 : in_ep_data <= 'h25; // dwDTERate[1]

+      'h057 : in_ep_data <= 'h00; // dwDTERate[2]

+      'h058 : in_ep_data <= 'h00; // dwDTERate[3]

+      'h059 : in_ep_data <= 1; // bCharFormat (1 stop bit)

+      'h05A : in_ep_data <= 0; // bParityType (None)

+      'h05B : in_ep_data <= 8; // bDataBits (8 bits)

+

+      default begin

+        in_ep_data <= 0;

+      end

+    endcase

+  end

+

+endmodule

diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart.v
new file mode 100644
index 0000000..e65d5b1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart.v
@@ -0,0 +1,331 @@
+/*

+   usb_uart

+

+  Luke Valenti's USB module, as adapted by Lawrie Griffiths.

+

+  This module was originally tinyfpga_bootloader.v in Luke's code.

+

+  It creates the endpoint modules and the protocol engine to run things.  Whereas

+  the original creates a usb_spi_bridge, this one creates a usb_uart_bridge.

+

+  Instanciation template

+

+  ----------------------------------------------------

+  usb_uart uart (

+    .clk_48mhz  (clk_48mhz),

+    .reset      (reset),

+

+    // pins - these must be connected properly to the outside world.  See below.

+    .usb_p_tx(usb_p_tx),

+    .usb_n_tx(usb_n_tx),

+    .usb_p_rx(usb_p_rx),

+    .usb_n_rx(usb_n_rx),

+    .usb_tx_en(usb_tx_en),

+

+    // uart pipeline in

+    .uart_in_data( uart_in_data ),

+    .uart_in_valid( uart_in_valid ),

+    .uart_in_ready( uart_in_ready ),

+

+    // uart pipeline out

+    .uart_out_data( uart_out_data ),

+    .uart_out_valid( uart_out_valid ),

+    .uart_out_ready( uart_out_ready ),

+

+    .debug( debug )

+  );

+

+  ----------------------------------------------------

+

+  Then, the actual physical pins need some special handling.  Get some

+  help from the device.

+

+  ----------------------------------------------------

+  assign usb_p_rx = usb_tx_en ? 1'b1 : usb_p_in;

+  assign usb_n_rx = usb_tx_en ? 1'b0 : usb_n_in;

+

+  SB_IO #(

+    .PIN_TYPE(6'b 1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT

+    .PULLUP(1'b 0)

+  )

+  iobuf_usbp

+  (

+    .PACKAGE_PIN(pin_usbp),

+    .OUTPUT_ENABLE(usb_tx_en),

+    .D_OUT_0(usb_p_tx),

+    .D_IN_0(usb_p_in)

+  );

+

+  SB_IO #(

+    .PIN_TYPE(6'b 1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT

+    .PULLUP(1'b 0)

+  )

+  iobuf_usbn

+  (

+    .PACKAGE_PIN(pin_usbn),

+    .OUTPUT_ENABLE(usb_tx_en),

+    .D_OUT_0(usb_n_tx),

+    .D_IN_0(usb_n_in)

+  );

+  ----------------------------------------------------

+

+It should be noted that there are no other invocations of usb stuff other than

+usb_uart.v.   Since it's the top, I'm going to put some doc in here.

+

+General note: USB communications happen over endpoints.  The OUT endpoints are out

+with respect to the HOST, and IN endpoints are in with respect to the HOST.

+

+Files:

+

+usb_uart.v      - top level module creates the end points clusters, (usb_serial_ctrl_ep,

+                  usb_uart_bridge_ep) and the main protocol engine (usb_fs_pe - passing

+                  in the in (3) and out (2) count, along with the actual usb signal

+                  lines).  Also, all the end point signals are connected to the protocol

+                  engine in its invocation.  The serial end point cluster and the control

+                  end point cluster have two endpoints each - one in and one out.

+

+usb_serial_ctrl_ep - serial control logic.  Two end point interfaces are (one in one

+                  out) passed in with their various signal lines.  Contains all the

+                  USB setup logic.  Returns the configuration etc.  Vendor 50 1D

+                  Product 30 61.  Two interfaces. Descriptors.  Obviously the main

+                  configuration file.

+

+usb_uart_bridge.v - where the data action is for us. Is passed in the out endpoint

+                  and the in endpoint, and also the (strange) UART interface signals

+                  (uart_we, uart_re, uart_di, uart_do, uart_wait).  So this translates

+                  between endpoint talk and UART talk.

+

+usb_fs_pe.v     - full speed protocol engine - instanciates all the endpoints, making

+                  arrays of in and out end point signals.  Also is passed in are all

+                  the actual interfaces to the end points.

+

+                  Creates the in and out arbitors (usb_fs_in_arb, usb_fs_out_arb)

+

+                  Creates the in protocol engine (usb_fs_in_pe), and the out protocol

+                  engine (usb_fs_out_pe)

+

+                  Creates the receiver and transmitter (usb_fs_rx, usb_fs_tx)

+

+                  Creates the tx mux and the rx mux which permit the different engines

+                  to talk.

+

+usb_fs_in_pe.v  - in protocol engine

+

+usb_fs_out_pe.v - out protocol engine

+

+usb_fs_rx.v     - Actual rx logic

+

+usb_fs_tx.v     - Actual tx logic

+

+edge_detect.v   - rising and falling edge detectors

+

+serial.v        - width adapter (x widths to y widths)

+

+*/

+

+module usb_uart (

+  input  clk_48mhz,

+  input reset,

+

+  // USB lines.  Split into input vs. output and oe control signal to maintain

+  // highest level of compatibility with synthesis tools.

+  output usb_p_tx,

+  output usb_n_tx,

+  input  usb_p_rx,

+  input  usb_n_rx,

+  output usb_tx_en,

+

+  // uart pipeline in (into the module, out of the device, into the host)

+  input [7:0] uart_in_data,

+  input       uart_in_valid,

+  output      uart_in_ready,

+

+  // uart pipeline out (out of the host, into the device, out of the module)

+  output [7:0] uart_out_data,

+  output       uart_out_valid,

+  input        uart_out_ready,

+

+  output [11:0] debug

+);

+

+  ////////////////////////////////////////////////////////////////////////////////

+  ////////////////////////////////////////////////////////////////////////////////

+  ////////

+  //////// usb engine

+  ////////

+  ////////////////////////////////////////////////////////////////////////////////

+  ////////////////////////////////////////////////////////////////////////////////

+

+  wire [6:0] dev_addr;

+  wire [7:0] out_ep_data;

+

+  wire ctrl_out_ep_req;

+  wire ctrl_out_ep_grant;

+  wire ctrl_out_ep_data_avail;

+  wire ctrl_out_ep_setup;

+  wire ctrl_out_ep_data_get;

+  wire ctrl_out_ep_stall;

+  wire ctrl_out_ep_acked;

+

+  wire ctrl_in_ep_req;

+  wire ctrl_in_ep_grant;

+  wire ctrl_in_ep_data_free;

+  wire ctrl_in_ep_data_put;

+  wire [7:0] ctrl_in_ep_data;

+  wire ctrl_in_ep_data_done;

+  wire ctrl_in_ep_stall;

+  wire ctrl_in_ep_acked;

+

+

+  wire serial_out_ep_req;

+  wire serial_out_ep_grant;

+  wire serial_out_ep_data_avail;

+  wire serial_out_ep_setup;

+  wire serial_out_ep_data_get;

+  wire serial_out_ep_stall;

+  wire serial_out_ep_acked;

+

+  wire serial_in_ep_req;

+  wire serial_in_ep_grant;

+  wire serial_in_ep_data_free;

+  wire serial_in_ep_data_put;

+  wire [7:0] serial_in_ep_data;

+  wire serial_in_ep_data_done;

+  wire serial_in_ep_stall;

+  wire serial_in_ep_acked;

+

+  wire sof_valid;

+  wire [10:0] frame_index;

+

+  reg [31:0] host_presence_timer = 0;

+  reg host_presence_timeout = 0;

+

+  usb_serial_ctrl_ep ctrl_ep_inst (

+    .clk(clk_48mhz),

+    .reset(reset),

+    .dev_addr(dev_addr),

+

+    // out endpoint interface

+    .out_ep_req(ctrl_out_ep_req),

+    .out_ep_grant(ctrl_out_ep_grant),

+    .out_ep_data_avail(ctrl_out_ep_data_avail),

+    .out_ep_setup(ctrl_out_ep_setup),

+    .out_ep_data_get(ctrl_out_ep_data_get),

+    .out_ep_data(out_ep_data),

+    .out_ep_stall(ctrl_out_ep_stall),

+    .out_ep_acked(ctrl_out_ep_acked),

+

+

+    // in endpoint interface

+    .in_ep_req(ctrl_in_ep_req),

+    .in_ep_grant(ctrl_in_ep_grant),

+    .in_ep_data_free(ctrl_in_ep_data_free),

+    .in_ep_data_put(ctrl_in_ep_data_put),

+    .in_ep_data(ctrl_in_ep_data),

+    .in_ep_data_done(ctrl_in_ep_data_done),

+    .in_ep_stall(ctrl_in_ep_stall),

+    .in_ep_acked(ctrl_in_ep_acked)

+  );

+

+  usb_uart_bridge_ep usb_uart_bridge_ep_inst (

+    .clk(clk_48mhz),

+    .reset(reset),

+

+    // out endpoint interface

+    .out_ep_req(serial_out_ep_req),

+    .out_ep_grant(serial_out_ep_grant),

+    .out_ep_data_avail(serial_out_ep_data_avail),

+    .out_ep_setup(serial_out_ep_setup),

+    .out_ep_data_get(serial_out_ep_data_get),

+    .out_ep_data(out_ep_data),

+    .out_ep_stall(serial_out_ep_stall),

+    .out_ep_acked(serial_out_ep_acked),

+

+    // in endpoint interface

+    .in_ep_req(serial_in_ep_req),

+    .in_ep_grant(serial_in_ep_grant),

+    .in_ep_data_free(serial_in_ep_data_free),

+    .in_ep_data_put(serial_in_ep_data_put),

+    .in_ep_data(serial_in_ep_data),

+    .in_ep_data_done(serial_in_ep_data_done),

+    .in_ep_stall(serial_in_ep_stall),

+    .in_ep_acked(serial_in_ep_acked),

+

+    // uart pipeline in

+    .uart_in_data( uart_in_data ),

+    .uart_in_valid( uart_in_valid ),

+    .uart_in_ready( uart_in_ready ),

+

+    // uart pipeline out

+    .uart_out_data( uart_out_data ),

+    .uart_out_valid( uart_out_valid ),

+    .uart_out_ready( uart_out_ready ),

+

+    .debug(debug[3:0])

+  );

+

+  wire nak_in_ep_grant;

+  wire nak_in_ep_data_free;

+  wire nak_in_ep_acked;

+

+  usb_fs_pe #(

+    .NUM_OUT_EPS(5'd2),

+    .NUM_IN_EPS(5'd3)

+  ) usb_fs_pe_inst (

+    .clk(clk_48mhz),

+    .reset(reset),

+

+    .usb_p_tx(usb_p_tx),

+    .usb_n_tx(usb_n_tx),

+    .usb_p_rx(usb_p_rx),

+    .usb_n_rx(usb_n_rx),

+    .usb_tx_en(usb_tx_en),

+

+    .dev_addr(dev_addr),

+

+    // out endpoint interfaces

+    .out_ep_req({serial_out_ep_req, ctrl_out_ep_req}),

+    .out_ep_grant({serial_out_ep_grant, ctrl_out_ep_grant}),

+    .out_ep_data_avail({serial_out_ep_data_avail, ctrl_out_ep_data_avail}),

+    .out_ep_setup({serial_out_ep_setup, ctrl_out_ep_setup}),

+    .out_ep_data_get({serial_out_ep_data_get, ctrl_out_ep_data_get}),

+    .out_ep_data(out_ep_data),

+    .out_ep_stall({serial_out_ep_stall, ctrl_out_ep_stall}),

+    .out_ep_acked({serial_out_ep_acked, ctrl_out_ep_acked}),

+

+    // in endpoint interfaces

+    .in_ep_req({1'b0, serial_in_ep_req, ctrl_in_ep_req}),

+    .in_ep_grant({nak_in_ep_grant, serial_in_ep_grant, ctrl_in_ep_grant}),

+    .in_ep_data_free({nak_in_ep_data_free, serial_in_ep_data_free, ctrl_in_ep_data_free}),

+    .in_ep_data_put({1'b0, serial_in_ep_data_put, ctrl_in_ep_data_put}),

+    .in_ep_data({8'b0, serial_in_ep_data[7:0], ctrl_in_ep_data[7:0]}),

+    .in_ep_data_done({1'b0, serial_in_ep_data_done, ctrl_in_ep_data_done}),

+    .in_ep_stall({1'b0, serial_in_ep_stall, ctrl_in_ep_stall}),

+    .in_ep_acked({nak_in_ep_acked, serial_in_ep_acked, ctrl_in_ep_acked}),

+

+    // sof interface

+    .sof_valid(sof_valid),

+    .frame_index(frame_index),

+

+    // Debug

+    .debug(debug[11:4])

+  );

+

+

+  ////////////////////////////////////////////////////////////////////////////////

+  // host presence detection

+  ////////////////////////////////////////////////////////////////////////////////

+

+  always @(posedge clk_48mhz) begin

+    if (sof_valid) begin

+      host_presence_timer <= 0;

+      host_presence_timeout <= 0;

+    end else begin

+      host_presence_timer <= host_presence_timer + 1;

+    end

+

+    if (host_presence_timer > 48000000) begin

+      host_presence_timeout <= 1;

+    end

+  end

+endmodule

diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart_bridge_ep.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart_bridge_ep.v
new file mode 100644
index 0000000..8d59f71
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart_bridge_ep.v
@@ -0,0 +1,315 @@
+/*
+    usb_uart_bridge_ep
+
+    This is the endpoint to uart translator.  Two things to highlight:  the directions
+    IN and OUT are set with respect to the HOST, and also in USB, the HOST runs all
+    endpoint interactions.
+
+    The out endpoint interface.  This is the out w.r.t. the host, hence in to
+    us.  There are request grant, data available and data get signals, stall and
+    acked signals.  And the data itself.
+
+    The in endpoint interface.  This is the in w.r.t. the host, hence out to us.
+    This interface also has a req and grant.  There's a put signal and a free
+    signal.  Stall and acked.  And the data.
+
+    To get data in and out there are two pipeline interfaces - one in and one out.
+
+    OUT (or into this device)
+
+    Roughly, the USB innards signal that a packet has arrived by raising out_ep_data_available.
+    The data multiplexor has to be switched, so the interface is requested.  This is
+    combinatorial logic so clever req and grant stuff can happen in the same line.
+
+         assign out_ep_req = ( out_ep_req_reg || out_ep_data_avail );
+
+    With the interface granted, the data is free to get.  Every cycle that the out_ep_data_get
+    signal is high, the input address is advanced.  Inside the USB innards, when the 
+    read address pointer equals the address of the write pointer (when all the data is 
+    retreived, the out_ep_data_available flag is lowered and we withdraw our request for
+    the interface and go back to idle.
+
+    Interestingly, if you stop taking data... you lose your buffer.  So don't.
+
+    IN (or out of this device back to the host)
+
+    The IN EP works by providing a buffer and waiting for the local logic to fill it, 
+    or to say that it's done.  When this happens the interface switches to a new state where
+    it waits for a token from the host.  When it get the token, it sends the data.  When that
+    is acknoledged, the buffer is released and returned ready to be filled again.
+
+    in_ep_data_free signals that there's a buffer waiting.  And that signal goes low when 
+    the buffer is full and not available.
+
+    In the case where a buffer is not full - just sitting around with some data in it, a decision
+    has to be made at some point just to send.  This is handled by a timeout mechanism, which 
+    asserts in_ep_data_done and lets the buffer be sent.
+
+    In the case where the buffer fills to the top, in_ep_data_free goes low by itself.
+
+*/
+
+module usb_uart_bridge_ep (
+  input clk,
+  input reset,
+
+  ////////////////////
+  // out endpoint interface
+  ////////////////////
+  output out_ep_req,               // request the data interface for the out endpoint
+  input out_ep_grant,              // data interface granted
+  input out_ep_data_avail,         // flagging data available to get from the host - stays up until the cycle upon which it is empty
+  input out_ep_setup,              // [setup packet sent? - not used here]
+  output out_ep_data_get,          // request to get the data
+  input [7:0] out_ep_data,         // data from the host
+  output out_ep_stall,             // an output enabling the device to stop inputs (not used)
+  input out_ep_acked,              // indicating that the outgoing data was acked
+
+  ////////////////////
+  // in endpoint interface
+  ////////////////////
+  output in_ep_req,                // request the data interface for the in endpoint
+  input in_ep_grant,               // data interface granted
+  input in_ep_data_free,           // end point is ready for data - (specifically there is a buffer and it has space)
+                                   // after going low it takes a while to get another back, but it does this automatically
+  output in_ep_data_put,           // forces end point to read our data
+  output [7:0] in_ep_data,         // data back to the host
+  output in_ep_data_done,          // signalling that we're done sending data
+  output in_ep_stall,              // an output enabling the device to stop outputs (not used)
+  input in_ep_acked,               // indicating that the outgoing data was acked
+
+  // uart pipeline in
+  input [7:0] uart_in_data,
+  input       uart_in_valid,
+  output      uart_in_ready,
+
+  // uart pipeline out
+  output [7:0] uart_out_data,
+  output       uart_out_valid,
+  input        uart_out_ready,
+
+  output [3:0] debug
+);
+
+  // Timeout counter width.
+  localparam TimeoutWidth = 3;
+
+  // We don't stall
+  assign out_ep_stall = 1'b0;
+  assign in_ep_stall = 1'b0;
+
+  // Registers for the out pipeline (out of the module)
+  reg [7:0] uart_out_data_reg;
+  reg [7:0] uart_out_data_overflow_reg;
+  reg       uart_out_valid_reg;
+
+  // registers for the out end point (out of the host)
+  reg       out_ep_req_reg;
+  reg       out_ep_data_get_reg;
+
+  // out pipeline / out endpoint state machine state (6 states -> 3 bits)
+  reg [1:0] pipeline_out_state;
+
+  localparam PipelineOutState_Idle         = 0;
+  localparam PipelineOutState_WaitData     = 1;
+  localparam PipelineOutState_PushData     = 2;
+  localparam PipelineOutState_WaitPipeline = 3;
+
+  // connect the pipeline registers to the outgoing ports
+  assign uart_out_data = uart_out_data_reg;
+  assign uart_out_valid = uart_out_valid_reg;
+
+  // automatically make the bus request from the data_available
+  // latch it with out_ep_req_reg
+  assign out_ep_req = ( out_ep_req_reg || out_ep_data_avail );
+
+  wire out_granted_data_available;
+
+  assign out_granted_data_available = out_ep_req && out_ep_grant;
+
+  assign out_ep_data_get = ( uart_out_ready || ~uart_out_valid_reg ) && out_ep_data_get_reg;
+
+  reg [7:0] out_stall_data;
+  reg       out_stall_valid;
+
+  // do HOST OUT, DEVICE IN, PIPELINE OUT (!)
+  always @(posedge clk) begin
+      if ( reset ) begin
+          pipeline_out_state <= PipelineOutState_Idle;
+          uart_out_data_reg <= 0;
+          uart_out_valid_reg <= 0;
+          out_ep_req_reg <= 0;
+          out_ep_data_get_reg <= 0;
+          out_stall_data <= 0;
+          out_stall_valid <= 0;
+      end else begin
+          case( pipeline_out_state )
+              PipelineOutState_Idle: begin
+                  // Waiting for the data_available signal indicating that a data packet has arrived
+                  if ( out_granted_data_available ) begin
+                      // indicate that we want the data
+                      out_ep_data_get_reg <= 1;
+                      // although the bus has been requested automatically, we latch the request so we control it
+                      out_ep_req_reg <= 1;
+                      // now wait for the data to set up
+                      pipeline_out_state <= PipelineOutState_WaitData;
+                      uart_out_valid_reg <= 0;
+                      out_stall_data <= 0;
+                      out_stall_valid <= 0;
+                  end
+              end
+              PipelineOutState_WaitData: begin
+                  // it takes one cycle for the juices to start flowing
+                  // we got here when we were starting or if the outgoing pipe stalled
+                  if ( uart_out_ready || ~uart_out_valid_reg ) begin
+                      //if we were stalled, we can send the byte we caught while we were stalled
+                      // the actual stalled byte now having been VALID & READY'ed
+                      if ( out_stall_valid ) begin
+                        uart_out_data_reg <= out_stall_data;
+                        uart_out_valid_reg <= 1;
+                        out_stall_data <= 0;
+                        out_stall_valid <= 0;
+                        if ( out_ep_data_avail )
+                          pipeline_out_state <= PipelineOutState_PushData;
+                        else begin
+                          pipeline_out_state <= PipelineOutState_WaitPipeline;
+                        end
+                      end else begin
+                          pipeline_out_state <= PipelineOutState_PushData;
+                      end
+                  end
+              end
+              PipelineOutState_PushData: begin
+                  // can grab a character if either the out was accepted or the out reg is empty
+                  if ( uart_out_ready || ~uart_out_valid_reg ) begin
+                    // now we really have got some data and a place to shove it
+                    uart_out_data_reg <= out_ep_data;
+                    uart_out_valid_reg <= 1;
+                    if ( ~out_ep_data_avail ) begin
+                        // stop streaming, now just going to wait until the character is accepted
+                        out_ep_data_get_reg <= 0;
+                        pipeline_out_state <= PipelineOutState_WaitPipeline;
+                    end
+                  end else begin
+                    // We're in push data so there is a character, but our pipeline has stalled
+                    // need to save the character and wait.
+                    out_stall_data <= out_ep_data;
+                    out_stall_valid <= 1;
+                    pipeline_out_state <= PipelineOutState_WaitData;                     
+                    if ( ~out_ep_data_avail )
+                        out_ep_data_get_reg <= 0;
+                  end
+              end
+              PipelineOutState_WaitPipeline: begin
+                  // unhand the bus (don't want to block potential incoming) - be careful, this works instantly!
+                  out_ep_req_reg <= 0;
+                  if ( uart_out_ready ) begin
+                      uart_out_valid_reg <= 0;
+                      uart_out_data_reg <= 0;
+                      pipeline_out_state <= PipelineOutState_Idle;
+                  end
+
+              end
+
+          endcase
+      end
+  end
+
+  // in endpoint control registers
+  reg       in_ep_req_reg;
+  reg       in_ep_data_done_reg;
+
+  // in pipeline / in endpoint state machine state (4 states -> 2 bits)
+  reg [1:0] pipeline_in_state;
+
+  localparam PipelineInState_Idle      = 0;
+  localparam PipelineInState_WaitData  = 1;
+  localparam PipelineInState_CycleData = 2;
+  localparam PipelineInState_WaitEP    = 3;
+
+  // connect the pipeline register to the outgoing port
+  assign uart_in_ready = ( pipeline_in_state == PipelineInState_CycleData ) && in_ep_data_free;
+
+  // uart_in_valid and a buffer being ready is the request for the bus. 
+  // It is granted automatically if available, and latched on by the SM.
+  // Note once requested, uart_in_valid may go on and off as data is available.
+  // When requested, connect the end point registers to the outgoing ports
+  assign in_ep_req = ( uart_in_valid && in_ep_data_free) || in_ep_req_reg;
+
+  // Confirmation that the bus was granted
+  wire in_granted_in_valid = in_ep_grant && uart_in_valid;
+
+  // Here are the things we use to get data sent
+  // ... put this word
+  assign in_ep_data_put = ( pipeline_in_state == PipelineInState_CycleData ) && uart_in_valid && in_ep_data_free;
+  // ... we're done putting - send the buffer
+  assign in_ep_data_done = in_ep_data_done_reg;
+  // ... the actual data, direct from the pipeline to the usb in buffer
+  assign in_ep_data = uart_in_data;
+
+  // If we have a half filled buffer, send it after a while by using a timer
+  // 4 bits of counter, we'll just count up until bit 3 is high... 8 clock cycles seems more than enough to wait
+  // to send the packet
+  reg [TimeoutWidth:0] in_ep_timeout;
+
+  // do PIPELINE IN, FPGA/Device OUT, Host IN
+  always @(posedge clk) begin
+      if ( reset ) begin
+          pipeline_in_state <= PipelineInState_Idle;
+          in_ep_req_reg <= 0;
+          in_ep_data_done_reg <= 0;
+      end else begin
+          case( pipeline_in_state )
+              PipelineInState_Idle: begin
+                  in_ep_data_done_reg <= 0;
+                  if ( in_granted_in_valid && in_ep_data_free ) begin
+                      // got the bus, there is free space, now do the data
+                      // confirm request bus - this will hold the request up until we're done with it
+                      in_ep_req_reg <= 1;
+                      pipeline_in_state <= PipelineInState_CycleData;
+                  end
+              end
+              PipelineInState_CycleData: begin
+                  if  (uart_in_valid ) begin
+                      if ( ~in_ep_data_free ) begin
+                        // back to idle
+                        pipeline_in_state <= PipelineInState_Idle;
+                        // release the bus
+                        in_ep_req_reg <= 0;
+                      end
+                  end else begin
+                      // No valid character.  Let's just pause for a second to see if any more are forthcoming.
+                      // clear the timeout counter
+                      in_ep_timeout <= 0;
+                      pipeline_in_state <= PipelineInState_WaitData;
+                 end
+              end
+              PipelineInState_WaitData: begin
+                  in_ep_timeout <= in_ep_timeout + 1;
+                  if ( uart_in_valid ) begin
+                      pipeline_in_state <= PipelineInState_CycleData;                
+                  end else begin
+                        // check for a timeout
+                        if ( in_ep_timeout[ TimeoutWidth ] ) begin
+                            in_ep_data_done_reg <= 1;
+                            pipeline_in_state <= PipelineInState_WaitEP;
+                        end
+                  end
+              end
+
+              PipelineInState_WaitEP: begin
+                  // maybe done is ignored if putting?
+                  in_ep_data_done_reg <= 0;
+
+                  // back to idle
+                  pipeline_in_state <= PipelineInState_Idle;
+                  // release the bus
+                  in_ep_req_reg <= 0;
+              end
+          endcase
+      end
+  end
+
+  assign debug = { in_ep_data_free, in_ep_data_done, pipeline_in_state[ 1 ], pipeline_in_state[ 0 ] };  
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart_core.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart_core.v
new file mode 100644
index 0000000..a137502
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart_core.v
@@ -0,0 +1,328 @@
+/*
+   usb_uart
+
+  Luke Valenti's USB module, as adapted by Lawrie Griffiths.
+
+  This module was originally tinyfpga_bootloader.v in Luke's code.
+
+  It creates the endpoint modules and the protocol engine to run things.  Whereas
+  the original creates a usb_spi_bridge, this one creates a usb_uart_bridge.
+
+  Instanciation template with separate pipe signals
+
+  ----------------------------------------------------
+  usb_uart_core_np uart (
+    .clk_48mhz  (clk_48mhz),
+    .reset      (reset),
+
+    // pins - these must be connected properly to the outside world.  See below.
+    .usb_p_tx(usb_p_tx),
+    .usb_n_tx(usb_n_tx),
+    .usb_p_rx(usb_p_rx),
+    .usb_n_rx(usb_n_rx),
+    .usb_tx_en(usb_tx_en),
+
+    // uart pipeline in
+    .uart_in_data( uart_in_data ),
+    .uart_in_valid( uart_in_valid ),
+    .uart_in_ready( uart_in_ready ),
+
+    // uart pipeline out
+    .uart_out_data( uart_out_data ),
+    .uart_out_valid( uart_out_valid ),
+    .uart_out_ready( uart_out_ready ),
+
+    .debug( debug )
+  );
+
+  ----------------------------------------------------
+
+  Then, the actual physical pins need some special handling.  Get some
+  help from the device.
+
+  ----------------------------------------------------
+  assign usb_p_rx = usb_tx_en ? 1'b1 : usb_p_in;
+  assign usb_n_rx = usb_tx_en ? 1'b0 : usb_n_in;
+
+  SB_IO #(
+    .PIN_TYPE(6'b 1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
+    .PULLUP(1'b 0)
+  )
+  iobuf_usbp
+  (
+    .PACKAGE_PIN(pin_usbp),
+    .OUTPUT_ENABLE(usb_tx_en),
+    .D_OUT_0(usb_p_tx),
+    .D_IN_0(usb_p_in)
+  );
+
+  SB_IO #(
+    .PIN_TYPE(6'b 1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
+    .PULLUP(1'b 0)
+  )
+  iobuf_usbn
+  (
+    .PACKAGE_PIN(pin_usbn),
+    .OUTPUT_ENABLE(usb_tx_en),
+    .D_OUT_0(usb_n_tx),
+    .D_IN_0(usb_n_in)
+  );
+  ----------------------------------------------------
+
+It should be noted that there are no other invocations of usb stuff other than
+usb_uart.v.   Since it's the top, I'm going to put some doc in here.
+
+General note: USB communications happen over endpoints.  The OUT endpoints are out
+with respect to the HOST, and IN endpoints are in with respect to the HOST.
+
+Files:
+
+usb_uart_core.v - top level module creates the end points clusters, (usb_serial_ctrl_ep,
+                  usb_uart_bridge_ep) and the main protocol engine (usb_fs_pe - passing
+                  in the in (3) and out (2) count, along with the actual usb signal
+                  lines).  Also, all the end point signals are connected to the protocol
+                  engine in its invocation.  The serial end point cluster and the control
+                  end point cluster have two endpoints each - one in and one out.
+
+usb_serial_ctrl_ep - serial control logic.  Two end point interfaces are (one in one
+                  out) passed in with their various signal lines.  Contains all the
+                  USB setup logic.  Returns the configuration etc.  Vendor 50 1D
+                  Product 30 61.  Two interfaces. Descriptors.  Obviously the main
+                  configuration file.
+
+usb_uart_bridge.v - where the data action is for us. Is passed in the out endpoint
+                  and the in endpoint, and also the (strange) UART interface signals
+                  (uart_we, uart_re, uart_di, uart_do, uart_wait).  So this translates
+                  between endpoint talk and UART talk.
+
+usb_fs_pe.v     - full speed protocol engine - instanciates all the endpoints, making
+                  arrays of in and out end point signals.  Also is passed in are all
+                  the actual interfaces to the end points.
+
+                  Creates the in and out arbitors (usb_fs_in_arb, usb_fs_out_arb)
+
+                  Creates the in protocol engine (usb_fs_in_pe), and the out protocol
+                  engine (usb_fs_out_pe)
+
+                  Creates the receiver and transmitter (usb_fs_rx, usb_fs_tx)
+
+                  Creates the tx mux and the rx mux which permit the different engines
+                  to talk.
+
+usb_fs_in_pe.v  - in protocol engine
+
+usb_fs_out_pe.v - out protocol engine
+
+usb_fs_rx.v     - Actual rx logic
+
+usb_fs_tx.v     - Actual tx logic
+
+edge_detect.v   - rising and falling edge detectors
+
+serial.v        - width adapter (x widths to y widths)
+
+*/
+
+module usb_uart_core(
+  input  clk_48mhz,
+  input reset,
+
+  // USB lines.  Split into input vs. output and oe control signal to maintain
+  // highest level of compatibility with synthesis tools.
+  output usb_p_tx,
+  output usb_n_tx,
+  input  usb_p_rx,
+  input  usb_n_rx,
+  output usb_tx_en,
+
+  // uart pipeline in (into the module, out of the device, into the host)
+  input [7:0] uart_in_data,
+  input       uart_in_valid,
+  output      uart_in_ready,
+
+  // uart pipeline out (out of the host, into the device, out of the module)
+  output [7:0] uart_out_data,
+  output       uart_out_valid,
+  input        uart_out_ready,
+
+  output [11:0] debug
+);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  ////////////////////////////////////////////////////////////////////////////////
+  ////////
+  //////// usb engine
+  ////////
+  ////////////////////////////////////////////////////////////////////////////////
+  ////////////////////////////////////////////////////////////////////////////////
+
+  wire [6:0] dev_addr;
+  wire [7:0] out_ep_data;
+
+  wire ctrl_out_ep_req;
+  wire ctrl_out_ep_grant;
+  wire ctrl_out_ep_data_avail;
+  wire ctrl_out_ep_setup;
+  wire ctrl_out_ep_data_get;
+  wire ctrl_out_ep_stall;
+  wire ctrl_out_ep_acked;
+
+  wire ctrl_in_ep_req;
+  wire ctrl_in_ep_grant;
+  wire ctrl_in_ep_data_free;
+  wire ctrl_in_ep_data_put;
+  wire [7:0] ctrl_in_ep_data;
+  wire ctrl_in_ep_data_done;
+  wire ctrl_in_ep_stall;
+  wire ctrl_in_ep_acked;
+
+
+  wire serial_out_ep_req;
+  wire serial_out_ep_grant;
+  wire serial_out_ep_data_avail;
+  wire serial_out_ep_setup;
+  wire serial_out_ep_data_get;
+  wire serial_out_ep_stall;
+  wire serial_out_ep_acked;
+
+  wire serial_in_ep_req;
+  wire serial_in_ep_grant;
+  wire serial_in_ep_data_free;
+  wire serial_in_ep_data_put;
+  wire [7:0] serial_in_ep_data;
+  wire serial_in_ep_data_done;
+  wire serial_in_ep_stall;
+  wire serial_in_ep_acked;
+
+  wire sof_valid;
+  wire [10:0] frame_index;
+
+  reg [31:0] host_presence_timer = 0;
+  reg host_presence_timeout = 0;
+
+  usb_serial_ctrl_ep ctrl_ep_inst (
+    .clk(clk_48mhz),
+    .reset(reset),
+    .dev_addr(dev_addr),
+
+    // out endpoint interface
+    .out_ep_req(ctrl_out_ep_req),
+    .out_ep_grant(ctrl_out_ep_grant),
+    .out_ep_data_avail(ctrl_out_ep_data_avail),
+    .out_ep_setup(ctrl_out_ep_setup),
+    .out_ep_data_get(ctrl_out_ep_data_get),
+    .out_ep_data(out_ep_data),
+    .out_ep_stall(ctrl_out_ep_stall),
+    .out_ep_acked(ctrl_out_ep_acked),
+
+
+    // in endpoint interface
+    .in_ep_req(ctrl_in_ep_req),
+    .in_ep_grant(ctrl_in_ep_grant),
+    .in_ep_data_free(ctrl_in_ep_data_free),
+    .in_ep_data_put(ctrl_in_ep_data_put),
+    .in_ep_data(ctrl_in_ep_data),
+    .in_ep_data_done(ctrl_in_ep_data_done),
+    .in_ep_stall(ctrl_in_ep_stall),
+    .in_ep_acked(ctrl_in_ep_acked)
+  );
+
+  usb_uart_bridge_ep usb_uart_bridge_ep_inst (
+    .clk(clk_48mhz),
+    .reset(reset),
+
+    // out endpoint interface
+    .out_ep_req(serial_out_ep_req),
+    .out_ep_grant(serial_out_ep_grant),
+    .out_ep_data_avail(serial_out_ep_data_avail),
+    .out_ep_setup(serial_out_ep_setup),
+    .out_ep_data_get(serial_out_ep_data_get),
+    .out_ep_data(out_ep_data),
+    .out_ep_stall(serial_out_ep_stall),
+    .out_ep_acked(serial_out_ep_acked),
+
+    // in endpoint interface
+    .in_ep_req(serial_in_ep_req),
+    .in_ep_grant(serial_in_ep_grant),
+    .in_ep_data_free(serial_in_ep_data_free),
+    .in_ep_data_put(serial_in_ep_data_put),
+    .in_ep_data(serial_in_ep_data),
+    .in_ep_data_done(serial_in_ep_data_done),
+    .in_ep_stall(serial_in_ep_stall),
+    .in_ep_acked(serial_in_ep_acked),
+
+    // uart pipeline in
+    .uart_in_data( uart_in_data ),
+    .uart_in_valid( uart_in_valid ),
+    .uart_in_ready( uart_in_ready ),
+
+    // uart pipeline out
+    .uart_out_data( uart_out_data ),
+    .uart_out_valid( uart_out_valid ),
+    .uart_out_ready( uart_out_ready ),
+
+    .debug(debug[3:0])
+  );
+
+  usb_fs_pe #(
+    .NUM_OUT_EPS(5'd2),
+    .NUM_IN_EPS(5'd2)
+  ) usb_fs_pe_inst (
+    .clk(clk_48mhz),
+    .reset(reset),
+
+    .usb_p_tx(usb_p_tx),
+    .usb_n_tx(usb_n_tx),
+    .usb_p_rx(usb_p_rx),
+    .usb_n_rx(usb_n_rx),
+    .usb_tx_en(usb_tx_en),
+
+    .dev_addr(dev_addr),
+
+    // out endpoint interfaces
+    .out_ep_req({serial_out_ep_req, ctrl_out_ep_req}),
+    .out_ep_grant({serial_out_ep_grant, ctrl_out_ep_grant}),
+    .out_ep_data_avail({serial_out_ep_data_avail, ctrl_out_ep_data_avail}),
+    .out_ep_setup({serial_out_ep_setup, ctrl_out_ep_setup}),
+    .out_ep_data_get({serial_out_ep_data_get, ctrl_out_ep_data_get}),
+    .out_ep_data(out_ep_data),
+    .out_ep_stall({serial_out_ep_stall, ctrl_out_ep_stall}),
+    .out_ep_acked({serial_out_ep_acked, ctrl_out_ep_acked}),
+
+    // in endpoint interfaces
+    .in_ep_req({serial_in_ep_req, ctrl_in_ep_req}),
+    .in_ep_grant({serial_in_ep_grant, ctrl_in_ep_grant}),
+    .in_ep_data_free({serial_in_ep_data_free, ctrl_in_ep_data_free}),
+    .in_ep_data_put({serial_in_ep_data_put, ctrl_in_ep_data_put}),
+    .in_ep_data({serial_in_ep_data[7:0], ctrl_in_ep_data[7:0]}),
+    .in_ep_data_done({serial_in_ep_data_done, ctrl_in_ep_data_done}),
+    .in_ep_stall({serial_in_ep_stall, ctrl_in_ep_stall}),
+    .in_ep_acked({serial_in_ep_acked, ctrl_in_ep_acked}),
+
+    // sof interface
+    .sof_valid(sof_valid),
+    .frame_index(frame_index),
+
+    // Debug
+    .debug(debug[11:4])
+  );
+
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // host presence detection
+  ////////////////////////////////////////////////////////////////////////////////
+
+//   always @(posedge clk_48mhz) begin
+//     if (sof_valid) begin
+//       host_presence_timer <= 0;
+//       host_presence_timeout <= 0;
+//     end else begin
+//       host_presence_timer <= host_presence_timer + 1;
+//     end
+
+//     if (host_presence_timer > 48000000) begin
+//       host_presence_timeout <= 1;
+//     end
+//   end
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart_ecp5.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart_ecp5.v
new file mode 100644
index 0000000..0f898e1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart_ecp5.v
@@ -0,0 +1,139 @@
+/*
+  usb_uart_ecp5
+
+  Simple wrapper around the usb_uart which incorporates the Pin driver logic
+  so this doesn't clutter the top level circuit
+
+  Make the signature generic (usb_uart) and rely on the file inclusion process (makefile)
+  to bring the correct architecture in
+
+  ----------------------------------------------------
+  usb_uart u_u (
+    .clk_48mhz  (clk_48mhz),
+    .reset      (reset),
+
+    // pins
+    .pin_usb_p( pin_usb_p ),
+    .pin_usb_n( pin_usb_n ),
+
+    // uart pipeline in (w.r.t module)
+    .pipe_in( pipe_in )
+
+    // uart pipeline out (w.r.t. module)
+    .pipe_out( pipe_out )
+  );
+
+  Utilization
+
+    707 LUTs?
+
+*/
+
+`include "../../pipe/rtl/pipe_defs.v"
+
+module usb_uart  #( parameter PipeSpec = `PS_d8 ) (
+        input  clk_48mhz,
+        input reset,
+
+        // USB pins
+        inout  pin_usb_p,
+        inout  pin_usb_n,
+
+        inout [`P_m(PipeSpec):0] pipe_in,
+        inout [`P_m(PipeSpec):0] pipe_out,
+
+        output [11:0] debug
+    );
+
+    wire [`P_Data_m(PipeSpec):0] in_data;
+    wire                     in_valid;
+    wire                     in_ready;
+
+    wire [`P_Data_m(PipeSpec):0] out_data;
+    wire                     out_valid;
+    wire                     out_ready;
+
+    p_unpack_data #( .PipeSpec( PipeSpec ) ) in_unpack_data( .pipe(pipe_in), .data(in_data) );
+    p_unpack_valid_ready #( .PipeSpec( PipeSpec ) ) in_unpack_valid_ready( .pipe(pipe_in), .valid(in_valid), .ready(in_ready) );
+
+    // start and stop signals are ignored - packetization has to be escaped
+    usb_uart_np  u_u_np(
+            clk_48mhz, reset,
+
+            pin_usb_p, pin_usb_n,
+
+            in_data, in_valid, in_ready,
+            out_data, out_valid, out_ready,
+
+            debug
+        );
+
+    p_pack_data #( .PipeSpec( PipeSpec ) ) out_pack_d( .data(out_data), .pipe(pipe_out) );
+    p_pack_valid_ready #( .PipeSpec( PipeSpec ) ) out_pack_vr( .valid(out_valid), .ready(out_ready), .pipe(pipe_out) );
+
+endmodule
+
+module usb_uart_np (
+  input  clk_48mhz,
+  input reset,
+
+  // USB pins
+  inout  pin_usb_p,
+  inout  pin_usb_n,
+
+  // uart pipeline in (out of the device, into the host)
+  input [7:0] uart_in_data,
+  input       uart_in_valid,
+  output      uart_in_ready,
+
+  // uart pipeline out (into the device, out of the host)
+  output [7:0] uart_out_data,
+  output       uart_out_valid,
+  input        uart_out_ready,
+
+  output [11:0] debug
+);
+
+    wire usb_p_tx;
+    wire usb_n_tx;
+    wire usb_p_rx;
+    wire usb_n_rx;
+    wire usb_tx_en;
+
+    // wire [11:0] debug_dum;
+
+    usb_uart_core_np u_u_c_np (
+        .clk_48mhz  (clk_48mhz),
+        .reset      (reset),
+
+        // pins - these must be connected properly to the outside world.  See below.
+        .usb_p_tx(usb_p_tx),
+        .usb_n_tx(usb_n_tx),
+        .usb_p_rx(usb_p_rx),
+        .usb_n_rx(usb_n_rx),
+        .usb_tx_en(usb_tx_en),
+
+        // uart pipeline in
+        .uart_in_data( uart_in_data ),
+        .uart_in_valid( uart_in_valid ),
+        .uart_in_ready( uart_in_ready ),
+
+        // uart pipeline out
+        .uart_out_data( uart_out_data ),
+        .uart_out_valid( uart_out_valid ),
+        .uart_out_ready( uart_out_ready ),
+
+        .debug( debug )
+    );
+
+    wire usb_p_in;
+    wire usb_n_in;
+
+    assign usb_p_rx = usb_tx_en ? 1'b1 : usb_p_in;
+    assign usb_n_rx = usb_tx_en ? 1'b0 : usb_n_in;
+
+	// T = TRISTATE (not transmit)
+	BB io_p( .I( usb_p_tx ), .T( !usb_tx_en ), .O( usb_p_in ), .B( pin_usb_p ) );
+	BB io_n( .I( usb_n_tx ), .T( !usb_tx_en ), .O( usb_n_in ), .B( pin_usb_n ) );
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart_i40.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart_i40.v
new file mode 100644
index 0000000..aa0703d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart_i40.v
@@ -0,0 +1,110 @@
+/*
+   usb_uart_i40
+
+  Simple wrapper around the usb_uart which incorporates the Pin driver logic
+  so this doesn't clutter the top level circuit
+
+  The layer above has to assert the Host Pull Up line
+
+  ----------------------------------------------------
+  usb_uart_i40 u_u_i40 (
+    .clk_48mhz  (clk_48mhz),
+    .reset      (reset),
+
+    // pins
+    .pin_usb_p( pin_usb_p ),
+    .pin_usb_n( pin_usb_n ),
+
+    // uart pipeline in
+    .uart_in_data( uart_in_data ),
+    .uart_in_valid( uart_in_valid ),
+    .uart_in_ready( uart_in_ready ),
+
+    // uart pipeline out
+    .uart_out_data( uart_out_data ),
+    .uart_out_valid( uart_out_valid ),
+    .uart_out_ready( uart_out_ready ),
+  );
+
+*/
+
+module usb_uart (
+  input  clk_48mhz,
+  input reset,
+
+  // USB pins
+  inout  pin_usb_p,
+  inout  pin_usb_n,
+
+  // uart pipeline in (out of the device, into the host)
+  input [7:0] uart_in_data,
+  input       uart_in_valid,
+  output      uart_in_ready,
+
+  // uart pipeline out (into the device, out of the host)
+  output [7:0] uart_out_data,
+  output       uart_out_valid,
+  input        uart_out_ready,
+
+  output [11:0] debug
+);
+
+    wire usb_p_tx;
+    wire usb_n_tx;
+    wire usb_p_rx;
+    wire usb_n_rx;
+    wire usb_tx_en;
+
+    //wire [3:0] debug;
+
+    usb_uart_core uart (
+        .clk_48mhz  (clk_48mhz),
+        .reset      (reset),
+
+        // pins - these must be connected properly to the outside world.  See below.
+        .usb_p_tx(usb_p_tx),
+        .usb_n_tx(usb_n_tx),
+        .usb_p_rx(usb_p_rx),
+        .usb_n_rx(usb_n_rx),
+        .usb_tx_en(usb_tx_en),
+
+        // uart pipeline in
+        .uart_in_data( uart_in_data ),
+        .uart_in_valid( uart_in_valid ),
+        .uart_in_ready( uart_in_ready ),
+
+        // uart pipeline out
+        .uart_out_data( uart_out_data ),
+        .uart_out_valid( uart_out_valid ),
+        .uart_out_ready( uart_out_ready ),
+
+        .debug( debug )
+    );
+
+    wire usb_p_in;
+    wire usb_n_in;
+
+    assign usb_p_rx = usb_tx_en ? 1'b1 : usb_p_in;
+    assign usb_n_rx = usb_tx_en ? 1'b0 : usb_n_in;
+
+    SB_IO #(
+        .PIN_TYPE(6'b 1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
+        .PULLUP(1'b 0)
+    ) iobuf_usbp (
+        .PACKAGE_PIN(pin_usb_p),
+        .OUTPUT_ENABLE(usb_tx_en),
+        .D_OUT_0(usb_p_tx),
+        .D_IN_0(usb_p_in)
+    );
+
+    SB_IO #(
+        .PIN_TYPE(6'b 1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
+        .PULLUP(1'b 0)
+    ) iobuf_usbn (
+        .PACKAGE_PIN(pin_usb_n),
+        .OUTPUT_ENABLE(usb_tx_en),
+        .D_OUT_0(usb_n_tx),
+        .D_IN_0(usb_n_in)
+    );
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart_x7.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart_x7.v
new file mode 100644
index 0000000..6793233
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb/usb_uart_x7.v
@@ -0,0 +1,118 @@
+/*
+   usb_uart_x7
+
+  Simple wrapper around the usb_uart which incorporates the Pin driver logic
+  so this doesn't clutter the top level circuit
+
+  Make the signature generic (usb_uart) and rely on the file inclusion process (makefile)
+  to bring the correct architecture in
+
+  The layer above has to assert the Host Pull Up line
+
+    usb_uart u_u (
+        .clk_48mhz  (clk_48mhz),
+        .reset      (reset),
+
+        // pins
+        .pin_usb_p( pin_usb_p ),
+        .pin_usb_n( pin_usb_n ),
+
+        // uart pipeline in
+        .uart_in_data( uart_in_data ),
+        .uart_in_valid( uart_in_valid ),
+        .uart_in_ready( uart_in_ready ),
+
+        // uart pipeline out
+        .uart_out_data( uart_out_data ),
+        .uart_out_valid( uart_out_valid ),
+        .uart_out_ready( uart_out_ready ),
+    );
+
+*/
+
+`include "../../pipe/rtl/pipe_defs.v"
+
+module usb_uart (
+        input  clk_48mhz,
+        input reset,
+
+        // USB pins
+        inout  pin_usb_p,
+        inout  pin_usb_n,
+
+        // uart pipeline in (out of the device, into the host)
+        input [7:0] uart_in_data,
+        input       uart_in_valid,
+        output      uart_in_ready,
+
+        // uart pipeline out (into the device, out of the host)
+        output [7:0] uart_out_data,
+        output       uart_out_valid,
+        input        uart_out_ready,
+
+        output [11:0] debug
+    );
+
+    wire usb_p_tx;
+    wire usb_n_tx;
+    wire usb_p_rx;
+    wire usb_n_rx;
+    wire usb_tx_en;
+
+    //wire [3:0] debug;
+
+    usb_uart_core_np u_u_c_np (
+        .clk_48mhz  (clk_48mhz),
+        .reset      (reset),
+
+        // pins - these must be connected properly to the outside world.  See below.
+        .usb_p_tx(usb_p_tx),
+        .usb_n_tx(usb_n_tx),
+        .usb_p_rx(usb_p_rx),
+        .usb_n_rx(usb_n_rx),
+        .usb_tx_en(usb_tx_en),
+
+        // uart pipeline in
+        .uart_in_data( uart_in_data ),
+        .uart_in_valid( uart_in_valid ),
+        .uart_in_ready( uart_in_ready ),
+
+        // uart pipeline out
+        .uart_out_data( uart_out_data ),
+        .uart_out_valid( uart_out_valid ),
+        .uart_out_ready( uart_out_ready ),
+
+        .debug( debug )
+    );
+
+    wire usb_p_in;
+    wire usb_n_in;
+
+    assign usb_p_rx = usb_tx_en ? 1'b1 : usb_p_in;
+    assign usb_n_rx = usb_tx_en ? 1'b0 : usb_n_in;
+
+    IOBUF #(
+        .DRIVE(16), // Specify the output drive strength
+        .IBUF_LOW_PWR("FALSE"),  // Low Power - "TRUE", High Performance = "FALSE"
+        .IOSTANDARD("DEFAULT"), // Specify the I/O standard
+        .SLEW("FAST") // Specify the output slew rate
+    ) iobuf_p (
+        .O( usb_p_in  ),       // Buffer output
+        .I( usb_p_tx ),       // Buffer input
+        .IO( pin_usb_p ),     // Buffer inout port (connect directly to top-level port)
+        .T( !usb_tx_en )      // 3-state enable input, high=input, low=output
+    );
+
+    IOBUF #(
+        .DRIVE(16), // Specify the output drive strength
+        .IBUF_LOW_PWR("FALSE"),  // Low Power - "TRUE", High Performance = "FALSE"
+        .IOSTANDARD("DEFAULT"), // Specify the I/O standard
+        .SLEW("FAST") // Specify the output slew rate
+    ) iobuf_n (
+        .O( usb_n_in  ),      // Buffer output
+        .I( usb_n_tx ),       // Buffer input
+        .IO( pin_usb_n ),     // Buffer inout port (connect directly to top-level port)
+        .T( !usb_tx_en )      // 3-state enable input, high=input, low=output
+    );
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb_ser_ice40.png b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb_ser_ice40.png
new file mode 100644
index 0000000..91e952b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb_ser_ice40.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb_ser_ice40_detail.png b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb_ser_ice40_detail.png
new file mode 100644
index 0000000..55bae7c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb_ser_ice40_detail.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb_serial_deep_debug.png b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb_serial_deep_debug.png
new file mode 100644
index 0000000..881153c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usb_serial_deep_debug.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usbserial.core b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usbserial.core
new file mode 100644
index 0000000..caa1f27
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usbserial.core
@@ -0,0 +1,76 @@
+CAPI=2:
+
+name : ::usbserial
+
+filesets:
+  rtl:
+    files:
+      - usb/edge_detect.v
+      - usb/serial.v
+      - usb/usb_fs_in_arb.v
+      - usb/usb_fs_in_pe.v
+      - usb/usb_fs_out_arb.v
+      - usb/usb_fs_out_pe.v
+      - usb/usb_fs_pe.v
+      - usb/usb_fs_rx.v
+      - usb/usb_fs_tx_mux.v
+      - usb/usb_fs_tx.v
+      - usb/usb_reset_det.v
+      - usb/usb_serial_ctrl_ep.v
+      - usb/usb_uart_bridge_ep.v
+      - usb/usb_uart_core.v
+    file_type : verilogSource
+
+  generic: {files: [usb/usb_uart.v     : {file_type : verilogSource}]}
+  ecp5 :   {files: [usb/usb_uart_ecp5.v: {file_type : verilogSource}]}
+  ice40:   {files: [usb/usb_uart_i40.v : {file_type : verilogSource}]}
+
+  tinyfpga_bx:
+    files:
+      - usbserial_tbx.v : {file_type : verilogSource}
+      - pins.pcf: {file_type : PCF}
+    depend: [fusesoc:utils:generators]
+
+targets:
+  default:
+    filesets: [rtl]
+
+  lint:
+    default_tool : verilator
+    description: Lint check core with Verilator
+    filesets: [rtl, generic]
+    tools:
+      verilator:
+        mode : lint-only
+    toplevel: usb_uart
+
+  synth:
+    default_tool: icestorm
+    description: Run synthesis for resource/timing analysis
+    filesets:
+      - rtl
+      - "tool_icestorm? (ice40)"
+      - "!tool_icestorm?   (generic)"
+    tools:
+      icestorm: {pnr : none}
+      vivado: {pnr : none}
+    toplevel: usb_uart
+
+  tinyfpga_bx:
+    default_tool: icestorm
+    description: Build for TinyFPGA BX
+    filesets: [rtl, ice40, tinyfpga_bx]
+    generate: [tinyfpga_bx_pll]
+    tools:
+      icestorm:
+        pnr: next
+        nextpnr_options: [--freq, 48, --lp8k, --opt-timing, --package, cm81]
+    toplevel: usbserial_tbx
+
+generate:
+  tinyfpga_bx_pll:
+    generator: icepll
+    parameters:
+      freq_in  : 16
+      freq_out : 48
+      module: true
diff --git a/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usbserial_tbx.v b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usbserial_tbx.v
new file mode 100644
index 0000000..382f6a7
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/tinyfpga_bx_usbserial/usbserial_tbx.v
@@ -0,0 +1,77 @@
+/*
+    USB Serial
+
+    Wrapping usb/usb_uart_ice40.v to create a loopback.
+*/
+
+module usbserial_tbx (
+        input  pin_clk,
+
+        inout  pin_usb_p,
+        inout  pin_usb_n,
+        output pin_pu,
+
+        output pin_led,
+
+        output [3:0] debug
+    );
+
+    wire clk_48mhz;
+
+    wire clk_locked;
+
+    // Use an icepll generated pll
+    pll pll48( .clock_in(pin_clk), .clock_out(clk_48mhz), .locked( clk_locked ) );
+
+    // LED
+    reg [22:0] ledCounter;
+    always @(posedge clk_48mhz) begin
+        ledCounter <= ledCounter + 1;
+    end
+    assign pin_led = ledCounter[ 22 ];
+
+    // Generate reset signal
+    reg [5:0] reset_cnt = 0;
+    wire reset = ~reset_cnt[5];
+    always @(posedge clk_48mhz)
+        if ( clk_locked )
+            reset_cnt <= reset_cnt + reset;
+
+    // uart pipeline in
+    wire [7:0] uart_in_data;
+    wire       uart_in_valid;
+    wire       uart_in_ready;
+
+    // assign debug = { uart_in_valid, uart_in_ready, reset, clk_48mhz };
+
+    wire usb_p_tx;
+    wire usb_n_tx;
+    wire usb_p_rx;
+    wire usb_n_rx;
+    wire usb_tx_en;
+
+    // usb uart - this instanciates the entire USB device.
+    usb_uart uart (
+        .clk_48mhz  (clk_48mhz),
+        .reset      (reset),
+
+        // pins
+        .pin_usb_p( pin_usb_p ),
+        .pin_usb_n( pin_usb_n ),
+
+        // uart pipeline in
+        .uart_in_data( uart_in_data ),
+        .uart_in_valid( uart_in_valid ),
+        .uart_in_ready( uart_in_ready ),
+
+        .uart_out_data( uart_in_data ),
+        .uart_out_valid( uart_in_valid ),
+        .uart_out_ready( uart_in_ready  )
+
+        //.debug( debug )
+    );
+
+    // USB Host Detect Pull Up
+    assign pin_pu = 1'b1;
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/.gitignore b/verilog/rtl/softshell/third_party/verilog-wishbone/.gitignore
new file mode 100644
index 0000000..964df4d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/.gitignore
@@ -0,0 +1,6 @@
+*~
+*.lxt
+*.pyc
+*.vvp
+*.kate-swp
+
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/.travis.yml b/verilog/rtl/softshell/third_party/verilog-wishbone/.travis.yml
new file mode 100644
index 0000000..15f9a3c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/.travis.yml
@@ -0,0 +1,15 @@
+language: python
+python:
+  - "3.6"
+before_install:
+  - export d=`pwd`
+  - export PYTHON_EXE=`which python`
+  - sudo apt-get update -qq
+  - sudo apt-get install -y iverilog
+  - git clone https://github.com/jandecaluwe/myhdl.git
+  - cd $d/myhdl && sudo $PYTHON_EXE setup.py install
+  - cd $d/myhdl/cosimulation/icarus && make && sudo install -m 0755 -D ./myhdl.vpi /usr/lib/x86_64-linux-gnu/ivl/myhdl.vpi
+  - cd $d
+script:
+  - cd tb && py.test
+
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/AUTHORS b/verilog/rtl/softshell/third_party/verilog-wishbone/AUTHORS
new file mode 100644
index 0000000..7dab2b3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/AUTHORS
@@ -0,0 +1 @@
+Alex Forencich <alex@alexforencich.com>
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/COPYING b/verilog/rtl/softshell/third_party/verilog-wishbone/COPYING
new file mode 100644
index 0000000..a8a83f7
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/COPYING
@@ -0,0 +1,21 @@
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/README b/verilog/rtl/softshell/third_party/verilog-wishbone/README
new file mode 120000
index 0000000..42061c0
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/README
@@ -0,0 +1 @@
+README.md
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/README.md b/verilog/rtl/softshell/third_party/verilog-wishbone/README.md
new file mode 100644
index 0000000..95d42a0
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/README.md
@@ -0,0 +1,94 @@
+# Verilog Wishbone Components Readme
+
+For more information and updates: http://alexforencich.com/wiki/en/verilog/wishbone/start
+
+GitHub repository: https://github.com/alexforencich/verilog-wishbone
+
+## Introduction
+
+Collection of Wishbone bus components.  Most components are fully
+parametrizable in interface widths.  Includes full MyHDL testbench with
+intelligent bus cosimulation endpoints.
+
+## Documentation
+
+### arbiter module
+
+General-purpose parametrizable arbiter.  Supports priority and round-robin
+arbitration.  Supports blocking until request release or acknowledge. 
+
+### axis_wb_master module
+
+AXI Stream Wishbone master.  Intended to be used to bridge a streaming
+or packet-based protocol (serial, ethernet, etc.) to a Wishbone bus.
+
+### priority_encoder module
+
+Parametrizable priority encoder.
+
+### wb_adapter module
+
+Width adapter module to bridge wishbone buses of differing widths.  The module
+is parametrizable, but their are certain restrictions.  First, the bus word
+widths must be identical (same data bus width per select line).  Second, the
+bus widths must be related by an integer multiple (e.g. 2 words and 6 words,
+but not 4 words and 6 words).
+
+### wb_arbiter_N module
+
+Parametrizable arbiter module to enable sharing between multiple masters.
+
+Can be generated with arbitrary port counts with wb_arbiter.py.
+
+### wb_async_reg module
+
+Asynchronous register module for clock domain crossing with parametrizable
+data and address interface widths.  Uses internal synchronization to pass
+wishbone bus cycles across clock domain boundaries.
+
+### wb_dp_ram module
+
+Dual-port, dual-clock RAM with parametrizable data and address interface
+widths.
+
+### wb_mux_N module
+
+Wishbone multiplexer with parametrizable data and address interface widths.
+
+Can be generated with arbitrary port counts with wb_mux.py.
+
+### wb_ram module
+
+RAM with parametrizable data and address interface widths.
+
+### wb_reg module
+
+Synchronous register with parametrizable data and address interface widths.
+Registers all wishbone signals.  Used to improve timing for long routes.
+
+### Source Files
+
+    arbiter.v                   : General-purpose parametrizable arbiter
+    axis_wb_master.v            : AXI Stream Wishbone master
+    priority_encoder.v          : Parametrizable priority encoder
+    wb_adapter.v                : Parametrizable bus width adapter
+    wb_arbiter.py               : Arbiter generator
+    wb_arbiter_2.py             : 2 port WB arbiter
+    wb_async_reg.v              : Asynchronous register
+    wb_dp_ram.v                 : Dual port RAM
+    wb_mux.py                   : WB mux generator
+    wb_mux_2.v                  : 2 port WB mux
+    wb_ram.v                    : Single port RAM
+    wb_reg.v                    : Register
+
+## Testing
+
+Running the included testbenches requires MyHDL and Icarus Verilog.  Make sure
+that myhdl.vpi is installed properly for cosimulation to work correctly.  The
+testbenches can be run with a Python test runner like nose or py.test, or the
+individual test scripts can be run with python directly.
+
+### Testbench Files
+
+    tb/axis_ep.py           : MyHDL AXI Stream endpoints
+    tb/wb.py                : MyHDL Wishbone master model and RAM model
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/arbiter.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/arbiter.v
new file mode 100644
index 0000000..d2b94f5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/arbiter.v
@@ -0,0 +1,153 @@
+/*
+
+Copyright (c) 2014-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Arbiter module
+ */
+module arbiter #
+(
+    parameter PORTS = 4,
+    // arbitration type: "PRIORITY" or "ROUND_ROBIN"
+    parameter TYPE = "PRIORITY",
+    // block type: "NONE", "REQUEST", "ACKNOWLEDGE"
+    parameter BLOCK = "NONE",
+    // LSB priority: "LOW", "HIGH"
+    parameter LSB_PRIORITY = "LOW"
+)
+(
+    input  wire                     clk,
+    input  wire                     rst,
+    
+    input  wire [PORTS-1:0]         request,
+    input  wire [PORTS-1:0]         acknowledge,
+
+    output wire [PORTS-1:0]         grant,
+    output wire                     grant_valid,
+    output wire [$clog2(PORTS)-1:0] grant_encoded
+);
+
+reg [PORTS-1:0] grant_reg = 0, grant_next;
+reg grant_valid_reg = 0, grant_valid_next;
+reg [$clog2(PORTS)-1:0] grant_encoded_reg = 0, grant_encoded_next;
+
+assign grant_valid = grant_valid_reg;
+assign grant = grant_reg;
+assign grant_encoded = grant_encoded_reg;
+
+wire request_valid;
+wire [$clog2(PORTS)-1:0] request_index;
+wire [PORTS-1:0] request_mask;
+
+priority_encoder #(
+    .WIDTH(PORTS),
+    .LSB_PRIORITY(LSB_PRIORITY)
+)
+priority_encoder_inst (
+    .input_unencoded(request),
+    .output_valid(request_valid),
+    .output_encoded(request_index),
+    .output_unencoded(request_mask)
+);
+
+reg [PORTS-1:0] mask_reg = 0, mask_next;
+
+wire masked_request_valid;
+wire [$clog2(PORTS)-1:0] masked_request_index;
+wire [PORTS-1:0] masked_request_mask;
+
+priority_encoder #(
+    .WIDTH(PORTS),
+    .LSB_PRIORITY(LSB_PRIORITY)
+)
+priority_encoder_masked (
+    .input_unencoded(request & mask_reg),
+    .output_valid(masked_request_valid),
+    .output_encoded(masked_request_index),
+    .output_unencoded(masked_request_mask)
+);
+
+always @* begin
+    grant_next = 0;
+    grant_valid_next = 0;
+    grant_encoded_next = 0;
+    mask_next = mask_reg;
+
+    if (BLOCK == "REQUEST" && grant_reg & request) begin
+        // granted request still asserted; hold it
+        grant_valid_next = grant_valid_reg;
+        grant_next = grant_reg;
+        grant_encoded_next = grant_encoded_reg;
+    end else if (BLOCK == "ACKNOWLEDGE" && grant_valid && !(grant_reg & acknowledge)) begin
+        // granted request not yet acknowledged; hold it
+        grant_valid_next = grant_valid_reg;
+        grant_next = grant_reg;
+        grant_encoded_next = grant_encoded_reg;
+    end else if (request_valid) begin
+        if (TYPE == "PRIORITY") begin
+            grant_valid_next = 1;
+            grant_next = request_mask;
+            grant_encoded_next = request_index;
+        end else if (TYPE == "ROUND_ROBIN") begin
+            if (masked_request_valid) begin
+                grant_valid_next = 1;
+                grant_next = masked_request_mask;
+                grant_encoded_next = masked_request_index;
+                if (LSB_PRIORITY == "LOW") begin
+                    mask_next = {PORTS{1'b1}} >> (PORTS - masked_request_index);
+                end else begin
+                    mask_next = {PORTS{1'b1}} << (masked_request_index + 1);
+                end
+            end else begin
+                grant_valid_next = 1;
+                grant_next = request_mask;
+                grant_encoded_next = request_index;
+                if (LSB_PRIORITY == "LOW") begin
+                    mask_next = {PORTS{1'b1}} >> (PORTS - request_index);
+                end else begin
+                    mask_next = {PORTS{1'b1}} << (request_index + 1);
+                end
+            end
+        end
+    end
+end
+
+always @(posedge clk) begin
+    if (rst) begin
+        grant_reg <= 0;
+        grant_valid_reg <= 0;
+        grant_encoded_reg <= 0;
+        mask_reg <= 0;
+    end else begin
+        grant_reg <= grant_next;
+        grant_valid_reg <= grant_valid_next;
+        grant_encoded_reg <= grant_encoded_next;
+        mask_reg <= mask_next;
+    end
+end
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/axis_wb_master.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/axis_wb_master.v
new file mode 100644
index 0000000..6d25f99
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/axis_wb_master.v
@@ -0,0 +1,562 @@
+/*
+
+Copyright (c) 2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * AXI stream wishbone master
+ */
+module axis_wb_master #
+(
+    parameter IMPLICIT_FRAMING = 0,                  // implicit framing (ignore tlast, look for start)
+    parameter COUNT_SIZE = 16,                       // size of word count register
+    parameter AXIS_DATA_WIDTH = 8,                   // width of AXI data bus
+    parameter AXIS_KEEP_WIDTH = (AXIS_DATA_WIDTH/8), // width of AXI bus tkeep signal
+    parameter WB_DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
+    parameter WB_ADDR_WIDTH = 32,                    // width of address bus in bits
+    parameter WB_SELECT_WIDTH = (WB_DATA_WIDTH/8),   // width of word select bus (1, 2, 4, or 8)
+    parameter READ_REQ = 8'hA1,                      // read requst type
+    parameter WRITE_REQ = 8'hA2,                     // write requst type
+    parameter READ_RESP = 8'hA3,                     // read response type
+    parameter WRITE_RESP = 8'hA4                     // write response type
+)
+(
+    input  wire                       clk,
+    input  wire                       rst,
+
+    /*
+     * AXI input
+     */
+    input  wire [AXIS_DATA_WIDTH-1:0] input_axis_tdata,
+    input  wire [AXIS_KEEP_WIDTH-1:0] input_axis_tkeep,
+    input  wire                       input_axis_tvalid,
+    output wire                       input_axis_tready,
+    input  wire                       input_axis_tlast,
+    input  wire                       input_axis_tuser,
+
+    /*
+     * AXI output
+     */
+    output wire [AXIS_DATA_WIDTH-1:0] output_axis_tdata,
+    output wire [AXIS_KEEP_WIDTH-1:0] output_axis_tkeep,
+    output wire                       output_axis_tvalid,
+    input  wire                       output_axis_tready,
+    output wire                       output_axis_tlast,
+    output wire                       output_axis_tuser,
+
+    /*
+     * Wishbone interface
+     */
+    output wire [WB_ADDR_WIDTH-1:0]   wb_adr_o,   // ADR_O() address
+    input  wire [WB_DATA_WIDTH-1:0]   wb_dat_i,   // DAT_I() data in
+    output wire [WB_DATA_WIDTH-1:0]   wb_dat_o,   // DAT_O() data out
+    output wire                       wb_we_o,    // WE_O write enable output
+    output wire [WB_SELECT_WIDTH-1:0] wb_sel_o,   // SEL_O() select output
+    output wire                       wb_stb_o,   // STB_O strobe output
+    input  wire                       wb_ack_i,   // ACK_I acknowledge input
+    input  wire                       wb_err_i,   // ERR_I error input
+    output wire                       wb_cyc_o,   // CYC_O cycle output
+
+    /*
+     * Status
+     */
+    output wire                       busy
+);
+
+// bus word width
+localparam AXIS_DATA_WORD_SIZE = AXIS_DATA_WIDTH / AXIS_KEEP_WIDTH;
+
+// for interfaces that are more than one word wide, disable address lines
+parameter WB_VALID_ADDR_WIDTH = WB_ADDR_WIDTH - $clog2(WB_SELECT_WIDTH);
+// width of data port in words (1, 2, 4, or 8)
+parameter WB_WORD_WIDTH = WB_SELECT_WIDTH;
+// size of words (8, 16, 32, or 64 bits)
+parameter WB_WORD_SIZE = WB_DATA_WIDTH/WB_WORD_WIDTH;
+
+parameter WORD_PART_ADDR_WIDTH = $clog2(WB_WORD_SIZE/AXIS_DATA_WORD_SIZE);
+
+parameter ADDR_WIDTH_ADJ = WB_ADDR_WIDTH+WORD_PART_ADDR_WIDTH;
+
+parameter COUNT_WORD_WIDTH = (COUNT_SIZE+AXIS_DATA_WORD_SIZE-1)/AXIS_DATA_WORD_SIZE;
+parameter ADDR_WORD_WIDTH = (ADDR_WIDTH_ADJ+AXIS_DATA_WORD_SIZE-1)/AXIS_DATA_WORD_SIZE;
+
+// bus width assertions
+initial begin
+    if (AXIS_KEEP_WIDTH * AXIS_DATA_WORD_SIZE != AXIS_DATA_WIDTH) begin
+        $error("Error: AXI data width not evenly divisble");
+        $finish;
+    end
+
+    if (WB_WORD_WIDTH * WB_WORD_SIZE != WB_DATA_WIDTH) begin
+        $error("Error: WB data width not evenly divisble");
+        $finish;
+    end
+
+    if (2**$clog2(WB_WORD_WIDTH) != WB_WORD_WIDTH) begin
+        $error("Error: WB word width must be even power of two");
+        $finish;
+    end
+
+    if (AXIS_DATA_WORD_SIZE*2**$clog2(WB_WORD_SIZE/AXIS_DATA_WORD_SIZE) != WB_WORD_SIZE) begin
+        $error("Error: WB word size must be a power of two multiple of the AXI word size");
+        $finish;
+    end
+
+    if (AXIS_KEEP_WIDTH > 1) begin
+        $error("Error: currently, only single word AXI bus supported");
+        $finish;
+    end
+end
+
+localparam [2:0]
+    STATE_IDLE = 3'd0,
+    STATE_HEADER = 3'd1,
+    STATE_READ_1 = 3'd2,
+    STATE_READ_2 = 3'd3,
+    STATE_WRITE_1 = 3'd4,
+    STATE_WRITE_2 = 3'd5,
+    STATE_WAIT_LAST = 3'd6;
+
+reg [2:0] state_reg = STATE_IDLE, state_next;
+
+reg [COUNT_SIZE-1:0] ptr_reg = {COUNT_SIZE{1'b0}}, ptr_next;
+reg [7:0] count_reg = 8'd0, count_next;
+reg last_cycle_reg = 1'b0;
+
+reg [ADDR_WIDTH_ADJ-1:0] addr_reg = {ADDR_WIDTH_ADJ{1'b0}}, addr_next;
+reg [WB_DATA_WIDTH-1:0] data_reg = {WB_DATA_WIDTH{1'b0}}, data_next;
+
+reg input_axis_tready_reg = 1'b0, input_axis_tready_next;
+
+reg wb_we_o_reg = 1'b0, wb_we_o_next;
+reg [WB_SELECT_WIDTH-1:0] wb_sel_o_reg = {WB_SELECT_WIDTH{1'b0}}, wb_sel_o_next;
+reg wb_stb_o_reg = 1'b0, wb_stb_o_next;
+reg wb_cyc_o_reg = 1'b0, wb_cyc_o_next;
+
+reg busy_reg = 1'b0;
+
+// internal datapath
+reg [AXIS_DATA_WIDTH-1:0] output_axis_tdata_int;
+reg [AXIS_KEEP_WIDTH-1:0] output_axis_tkeep_int;
+reg                       output_axis_tvalid_int;
+reg                       output_axis_tready_int_reg = 1'b0;
+reg                       output_axis_tlast_int;
+reg                       output_axis_tuser_int;
+wire                      output_axis_tready_int_early;
+
+assign input_axis_tready = input_axis_tready_reg;
+
+assign wb_adr_o = {addr_reg[ADDR_WIDTH_ADJ-1:ADDR_WIDTH_ADJ-WB_VALID_ADDR_WIDTH], {WB_ADDR_WIDTH-WB_VALID_ADDR_WIDTH{1'b0}}};
+assign wb_dat_o = data_reg;
+assign wb_we_o = wb_we_o_reg;
+assign wb_sel_o = wb_sel_o_reg;
+assign wb_stb_o = wb_stb_o_reg;
+assign wb_cyc_o = wb_cyc_o_reg;
+
+assign busy = busy_reg;
+
+always @* begin
+    state_next = STATE_IDLE;
+
+    ptr_next = ptr_reg;
+    count_next = count_reg;
+
+    input_axis_tready_next = 1'b0;
+
+    output_axis_tdata_int = {AXIS_DATA_WIDTH{1'b0}};
+    output_axis_tkeep_int = {{AXIS_KEEP_WIDTH-1{1'b0}}, 1'b1};
+    output_axis_tvalid_int = 1'b0;
+    output_axis_tlast_int = 1'b0;
+    output_axis_tuser_int = 1'b0;
+
+    addr_next = addr_reg;
+    data_next = data_reg;
+
+    wb_we_o_next = wb_we_o_reg;
+    wb_sel_o_next = wb_sel_o_reg;
+    wb_stb_o_next = 1'b0;
+    wb_cyc_o_next = 1'b0;
+
+    case (state_reg)
+        STATE_IDLE: begin
+            // idle, wait for start indicator
+            input_axis_tready_next = output_axis_tready_int_early;
+            wb_we_o_next = 1'b0;
+
+            if (input_axis_tready & input_axis_tvalid) begin
+                if (!IMPLICIT_FRAMING & input_axis_tlast) begin
+                    // last asserted, ignore cycle
+                    state_next = STATE_IDLE;
+                end else if (input_axis_tdata == READ_REQ) begin
+                    // start of read
+                    output_axis_tdata_int = READ_RESP;
+                    output_axis_tvalid_int = 1'b1;
+                    output_axis_tlast_int = 1'b0;
+                    output_axis_tuser_int = 1'b0;
+                    wb_we_o_next = 1'b0;
+                    count_next = COUNT_WORD_WIDTH+ADDR_WORD_WIDTH-1;
+                    state_next = STATE_HEADER;
+                end else if (input_axis_tdata == WRITE_REQ) begin
+                    // start of write
+                    output_axis_tdata_int = WRITE_RESP;
+                    output_axis_tvalid_int = 1'b1;
+                    output_axis_tlast_int = 1'b0;
+                    output_axis_tuser_int = 1'b0;
+                    wb_we_o_next = 1'b1;
+                    count_next = COUNT_WORD_WIDTH+ADDR_WORD_WIDTH-1;
+                    state_next = STATE_HEADER;
+                end else begin
+                    // invalid start of packet
+                    if (IMPLICIT_FRAMING) begin
+                        // drop byte
+                        state_next = STATE_IDLE;
+                    end else begin
+                        // drop packet
+                        state_next = STATE_WAIT_LAST;
+                    end
+                end
+            end else begin
+                state_next = STATE_IDLE;
+            end
+        end
+        STATE_HEADER: begin
+            // store address and length
+            input_axis_tready_next = output_axis_tready_int_early;
+
+            if (input_axis_tready & input_axis_tvalid) begin
+                // pass through
+                output_axis_tdata_int = input_axis_tdata;
+                output_axis_tvalid_int = 1'b1;
+                output_axis_tlast_int = 1'b0;
+                output_axis_tuser_int = 1'b0;
+                // store pointers
+                if (count_reg < COUNT_WORD_WIDTH) begin
+                    ptr_next[AXIS_DATA_WORD_SIZE*count_reg +: AXIS_DATA_WORD_SIZE] = input_axis_tdata;
+                end else begin
+                    addr_next[AXIS_DATA_WORD_SIZE*(count_reg-COUNT_WORD_WIDTH) +: AXIS_DATA_WORD_SIZE] = input_axis_tdata;
+                end
+                count_next = count_reg - 1;
+                if (count_reg == 0) begin
+                    // end of header
+                    // set initial word offset
+                    if (WB_ADDR_WIDTH == WB_VALID_ADDR_WIDTH && WORD_PART_ADDR_WIDTH == 0) begin
+                        count_next = 0;
+                    end else begin
+                        count_next = addr_reg[ADDR_WIDTH_ADJ-WB_VALID_ADDR_WIDTH-1:0];
+                    end
+                    wb_sel_o_next = {WB_SELECT_WIDTH{1'b0}};
+                    data_next = {WB_DATA_WIDTH{1'b0}};
+                    if (wb_we_o_reg) begin
+                        // start writing
+                        if (input_axis_tlast) begin
+                            // end of frame in header
+                            output_axis_tlast_int = 1'b1;
+                            output_axis_tuser_int = 1'b1;
+                            state_next = STATE_IDLE;
+                        end else begin
+                            output_axis_tlast_int = 1'b1;
+                            state_next = STATE_WRITE_1;
+                        end
+                    end else begin
+                        // start reading
+                        if (IMPLICIT_FRAMING) begin
+                            input_axis_tready_next = 1'b0;
+                        end else begin
+                            input_axis_tready_next = !(last_cycle_reg || (input_axis_tvalid & input_axis_tlast));
+                        end
+                        wb_cyc_o_next = 1'b1;
+                        wb_stb_o_next = 1'b1;
+                        wb_sel_o_next = {WB_SELECT_WIDTH{1'b1}};
+                        state_next = STATE_READ_1;
+                    end
+                end else begin
+                    if (IMPLICIT_FRAMING) begin
+                        state_next = STATE_HEADER;
+                    end else begin
+                        if (input_axis_tlast) begin
+                            // end of frame in header
+                            output_axis_tlast_int = 1'b1;
+                            output_axis_tuser_int = 1'b1;
+                            state_next = STATE_IDLE;
+                        end else begin
+                            state_next = STATE_HEADER;
+                        end
+                    end
+                end
+            end else begin
+                state_next = STATE_HEADER;
+            end
+        end
+        STATE_READ_1: begin
+            // wait for ack
+            wb_cyc_o_next = 1'b1;
+            wb_stb_o_next = 1'b1;
+
+            // drop padding
+            if (!IMPLICIT_FRAMING) begin
+                input_axis_tready_next = !(last_cycle_reg || (input_axis_tvalid & input_axis_tlast));
+            end
+
+            if (wb_ack_i || wb_err_i) begin
+                // read cycle complete, store result
+                data_next = wb_dat_i;
+                addr_next = addr_reg + (1 << (WB_ADDR_WIDTH-WB_VALID_ADDR_WIDTH+WORD_PART_ADDR_WIDTH));
+                wb_cyc_o_next = 1'b0;
+                wb_stb_o_next = 1'b0;
+                wb_sel_o_next = {WB_SELECT_WIDTH{1'b0}};
+                state_next = STATE_READ_2;
+            end else begin
+                state_next = STATE_READ_1;
+            end
+        end
+        STATE_READ_2: begin
+            // send data
+
+            // drop padding
+            if (!IMPLICIT_FRAMING) begin
+                input_axis_tready_next = !(last_cycle_reg || (input_axis_tvalid & input_axis_tlast));
+            end
+
+            if (output_axis_tready_int_reg) begin
+                // transfer word and update pointers
+                output_axis_tdata_int = data_reg[AXIS_DATA_WORD_SIZE*count_reg +: AXIS_DATA_WORD_SIZE];
+                output_axis_tvalid_int = 1'b1;
+                output_axis_tlast_int = 1'b0;
+                output_axis_tuser_int = 1'b0;
+                count_next = count_reg + 1;
+                ptr_next = ptr_reg - 1;
+                if (ptr_reg == 1) begin
+                    // last word of read
+                    output_axis_tlast_int = 1'b1;
+                    if (!IMPLICIT_FRAMING && !(last_cycle_reg || (input_axis_tvalid & input_axis_tlast))) begin
+                        state_next = STATE_WAIT_LAST;
+                    end else begin
+                        input_axis_tready_next = output_axis_tready_int_early;
+                        state_next = STATE_IDLE;
+                    end
+                end else if (count_reg == (WB_SELECT_WIDTH*WB_WORD_SIZE/AXIS_DATA_WORD_SIZE)-1) begin
+                    // end of stored data word; read the next one
+                    count_next = 0;
+                    wb_cyc_o_next = 1'b1;
+                    wb_stb_o_next = 1'b1;
+                    wb_sel_o_next = {WB_SELECT_WIDTH{1'b1}};
+                    state_next = STATE_READ_1;
+                end else begin
+                    state_next = STATE_READ_2;
+                end
+            end else begin
+                state_next = STATE_READ_2;
+            end
+        end
+        STATE_WRITE_1: begin
+            // write data
+            input_axis_tready_next = 1'b1;
+
+            if (input_axis_tready & input_axis_tvalid) begin
+                // store word
+                data_next[AXIS_DATA_WORD_SIZE*count_reg +: AXIS_DATA_WORD_SIZE] = input_axis_tdata;
+                count_next = count_reg + 1;
+                ptr_next = ptr_reg - 1;
+                wb_sel_o_next[count_reg >> ((WB_WORD_SIZE/AXIS_DATA_WORD_SIZE)-1)] = 1'b1;
+                if (count_reg == (WB_SELECT_WIDTH*WB_WORD_SIZE/AXIS_DATA_WORD_SIZE)-1 || ptr_reg == 1) begin
+                    // have full word or at end of block, start write operation
+                    count_next = 0;
+                    input_axis_tready_next = 1'b0;
+                    wb_cyc_o_next = 1'b1;
+                    wb_stb_o_next = 1'b1;
+                    state_next = STATE_WRITE_2;
+                end else begin
+                    state_next = STATE_WRITE_1;
+                end
+            end else begin
+                state_next = STATE_WRITE_1;
+            end
+        end
+        STATE_WRITE_2: begin
+            // wait for ack
+            wb_cyc_o_next = 1'b1;
+            wb_stb_o_next = 1'b1;
+
+            if (wb_ack_i || wb_err_i) begin
+                // end of write operation
+                data_next = {WB_DATA_WIDTH{1'b0}};
+                addr_next = addr_reg + (1 << (WB_ADDR_WIDTH-WB_VALID_ADDR_WIDTH+WORD_PART_ADDR_WIDTH));
+                wb_cyc_o_next = 1'b0;
+                wb_stb_o_next = 1'b0;
+                wb_sel_o_next = {WB_SELECT_WIDTH{1'b0}};
+                if (ptr_reg == 0) begin
+                    // done writing
+                    if (!IMPLICIT_FRAMING && !last_cycle_reg) begin
+                        input_axis_tready_next = 1'b1;
+                        state_next = STATE_WAIT_LAST;
+                    end else begin
+                        input_axis_tready_next = output_axis_tready_int_early;
+                        state_next = STATE_IDLE;
+                    end
+                end else begin
+                    // more to write
+                    state_next = STATE_WRITE_1;
+                end
+            end else begin
+                state_next = STATE_WRITE_2;
+            end
+        end
+        STATE_WAIT_LAST: begin
+            // wait for end of frame
+            input_axis_tready_next = 1'b1;
+
+            if (input_axis_tready & input_axis_tvalid) begin
+                // wait for tlast
+                if (input_axis_tlast) begin
+                    input_axis_tready_next = output_axis_tready_int_early;
+                    state_next = STATE_IDLE;
+                end else begin
+                    state_next = STATE_WAIT_LAST;
+                end
+            end else begin
+                state_next = STATE_WAIT_LAST;
+            end
+        end
+    endcase
+end
+
+always @(posedge clk) begin
+    if (rst) begin
+        state_reg <= STATE_IDLE;
+        input_axis_tready_reg <= 1'b0;
+        wb_stb_o_reg <= 1'b0;
+        wb_cyc_o_reg <= 1'b0;
+        busy_reg <= 1'b0;
+    end else begin
+        state_reg <= state_next;
+        input_axis_tready_reg <= input_axis_tready_next;
+        wb_stb_o_reg <= wb_stb_o_next;
+        wb_cyc_o_reg <= wb_cyc_o_next;
+        busy_reg <= state_next != STATE_IDLE;
+    end
+
+    ptr_reg <= ptr_next;
+    count_reg <= count_next;
+
+    if (input_axis_tready & input_axis_tvalid) begin
+        last_cycle_reg <= input_axis_tlast;
+    end
+
+    addr_reg <= addr_next;
+    data_reg <= data_next;
+
+    wb_we_o_reg <= wb_we_o_next;
+    wb_sel_o_reg <= wb_sel_o_next;
+end
+
+// output datapath logic
+reg [AXIS_DATA_WIDTH-1:0] output_axis_tdata_reg = {AXIS_DATA_WIDTH{1'b0}};
+reg [AXIS_KEEP_WIDTH-1:0] output_axis_tkeep_reg = {{AXIS_KEEP_WIDTH-1{1'b0}}, 1'b1};
+reg                       output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
+reg                       output_axis_tlast_reg = 1'b0;
+reg                       output_axis_tuser_reg = 1'b0;
+
+reg [AXIS_DATA_WIDTH-1:0] temp_axis_tdata_reg = {AXIS_DATA_WIDTH{1'b0}};
+reg [AXIS_KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {{AXIS_KEEP_WIDTH-1{1'b0}}, 1'b1};
+reg                       temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
+reg                       temp_axis_tlast_reg = 1'b0;
+reg                       temp_axis_tuser_reg = 1'b0;
+
+// datapath control
+reg store_axis_int_to_output;
+reg store_axis_int_to_temp;
+reg store_axis_temp_to_output;
+
+assign output_axis_tdata = output_axis_tdata_reg;
+assign output_axis_tkeep = output_axis_tkeep_reg;
+assign output_axis_tvalid = output_axis_tvalid_reg;
+assign output_axis_tlast = output_axis_tlast_reg;
+assign output_axis_tuser = output_axis_tuser_reg;
+
+// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
+assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
+
+always @* begin
+    // transfer sink ready state to source
+    output_axis_tvalid_next = output_axis_tvalid_reg;
+    temp_axis_tvalid_next = temp_axis_tvalid_reg;
+
+    store_axis_int_to_output = 1'b0;
+    store_axis_int_to_temp = 1'b0;
+    store_axis_temp_to_output = 1'b0;
+    
+    if (output_axis_tready_int_reg) begin
+        // input is ready
+        if (output_axis_tready | ~output_axis_tvalid_reg) begin
+            // output is ready or currently not valid, transfer data to output
+            output_axis_tvalid_next = output_axis_tvalid_int;
+            store_axis_int_to_output = 1'b1;
+        end else begin
+            // output is not ready, store input in temp
+            temp_axis_tvalid_next = output_axis_tvalid_int;
+            store_axis_int_to_temp = 1'b1;
+        end
+    end else if (output_axis_tready) begin
+        // input is not ready, but output is ready
+        output_axis_tvalid_next = temp_axis_tvalid_reg;
+        temp_axis_tvalid_next = 1'b0;
+        store_axis_temp_to_output = 1'b1;
+    end
+end
+
+always @(posedge clk) begin
+    if (rst) begin
+        output_axis_tvalid_reg <= 1'b0;
+        output_axis_tready_int_reg <= 1'b0;
+        temp_axis_tvalid_reg <= 1'b0;
+    end else begin
+        output_axis_tvalid_reg <= output_axis_tvalid_next;
+        output_axis_tready_int_reg <= output_axis_tready_int_early;
+        temp_axis_tvalid_reg <= temp_axis_tvalid_next;
+    end
+
+    // datapath
+    if (store_axis_int_to_output) begin
+        output_axis_tdata_reg <= output_axis_tdata_int;
+        output_axis_tkeep_reg <= output_axis_tkeep_int;
+        output_axis_tlast_reg <= output_axis_tlast_int;
+        output_axis_tuser_reg <= output_axis_tuser_int;
+    end else if (store_axis_temp_to_output) begin
+        output_axis_tdata_reg <= temp_axis_tdata_reg;
+        output_axis_tkeep_reg <= temp_axis_tkeep_reg;
+        output_axis_tlast_reg <= temp_axis_tlast_reg;
+        output_axis_tuser_reg <= temp_axis_tuser_reg;
+    end
+
+    if (store_axis_int_to_temp) begin
+        temp_axis_tdata_reg <= output_axis_tdata_int;
+        temp_axis_tkeep_reg <= output_axis_tkeep_int;
+        temp_axis_tlast_reg <= output_axis_tlast_int;
+        temp_axis_tuser_reg <= output_axis_tuser_int;
+    end
+end
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/priority_encoder.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/priority_encoder.v
new file mode 100644
index 0000000..7303063
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/priority_encoder.v
@@ -0,0 +1,98 @@
+/*
+
+Copyright (c) 2014-2018 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Priority encoder module
+ */
+module priority_encoder #
+(
+    parameter WIDTH = 4,
+    // LSB priority: "LOW", "HIGH"
+    parameter LSB_PRIORITY = "LOW"
+)
+(
+    input  wire [WIDTH-1:0]         input_unencoded,
+    output wire                     output_valid,
+    output wire [$clog2(WIDTH)-1:0] output_encoded,
+    output wire [WIDTH-1:0]         output_unencoded
+);
+
+// power-of-two width
+parameter W1 = 2**$clog2(WIDTH);
+parameter W2 = W1/2;
+
+generate
+    if (WIDTH == 1) begin
+        // one input
+        assign output_valid = input_unencoded;
+        assign output_encoded = 0;
+    end else if (WIDTH == 2) begin
+        // two inputs - just an OR gate
+        assign output_valid = |input_unencoded;
+        if (LSB_PRIORITY == "LOW") begin
+            assign output_encoded = input_unencoded[1];
+        end else begin
+            assign output_encoded = ~input_unencoded[0];
+        end
+    end else begin
+        // more than two inputs - split into two parts and recurse
+        // also pad input to correct power-of-two width
+        wire [$clog2(W2)-1:0] out1, out2;
+        wire valid1, valid2;
+        priority_encoder #(
+            .WIDTH(W2),
+            .LSB_PRIORITY(LSB_PRIORITY)
+        )
+        priority_encoder_inst1 (
+            .input_unencoded(input_unencoded[W2-1:0]),
+            .output_valid(valid1),
+            .output_encoded(out1)
+        );
+        priority_encoder #(
+            .WIDTH(W2),
+            .LSB_PRIORITY(LSB_PRIORITY)
+        )
+        priority_encoder_inst2 (
+            .input_unencoded({{W1-WIDTH{1'b0}}, input_unencoded[WIDTH-1:W2]}),
+            .output_valid(valid2),
+            .output_encoded(out2)
+        );
+        // multiplexer to select part
+        assign output_valid = valid1 | valid2;
+        if (LSB_PRIORITY == "LOW") begin
+            assign output_encoded = valid2 ? {1'b1, out2} : {1'b0, out1};
+        end else begin
+            assign output_encoded = valid1 ? {1'b0, out1} : {1'b1, out2};
+        end
+    end
+endgenerate
+
+// unencoded output
+assign output_unencoded = 1 << output_encoded;
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_adapter.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_adapter.v
new file mode 100644
index 0000000..ee65ace
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_adapter.v
@@ -0,0 +1,361 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Wishbone width adapter
+ */
+module wb_adapter #
+(
+    parameter ADDR_WIDTH = 32,                        // width of address bus in bits
+    parameter WBM_DATA_WIDTH = 32,                    // width of master data bus in bits (8, 16, 32, or 64)
+    parameter WBM_SELECT_WIDTH = (WBM_DATA_WIDTH/8),  // width of master word select bus (1, 2, 4, or 8)
+    parameter WBS_DATA_WIDTH = 32,                    // width of slave data bus in bits (8, 16, 32, or 64)
+    parameter WBS_SELECT_WIDTH = (WBS_DATA_WIDTH/8)   // width of slave word select bus (1, 2, 4, or 8)
+)
+(
+    input  wire                        clk,
+    input  wire                        rst,
+
+    /*
+     * Wishbone master input
+     */
+    input  wire [ADDR_WIDTH-1:0]       wbm_adr_i,     // ADR_I() address input
+    input  wire [WBM_DATA_WIDTH-1:0]   wbm_dat_i,     // DAT_I() data in
+    output wire [WBM_DATA_WIDTH-1:0]   wbm_dat_o,     // DAT_O() data out
+    input  wire                        wbm_we_i,      // WE_I write enable input
+    input  wire [WBM_SELECT_WIDTH-1:0] wbm_sel_i,     // SEL_I() select input
+    input  wire                        wbm_stb_i,     // STB_I strobe input
+    output wire                        wbm_ack_o,     // ACK_O acknowledge output
+    output wire                        wbm_err_o,     // ERR_O error output
+    output wire                        wbm_rty_o,     // RTY_O retry output
+    input  wire                        wbm_cyc_i,     // CYC_I cycle input
+
+    /*
+     * Wishbone slave output
+     */
+    output wire [ADDR_WIDTH-1:0]       wbs_adr_o,     // ADR_O() address output
+    input  wire [WBS_DATA_WIDTH-1:0]   wbs_dat_i,     // DAT_I() data in
+    output wire [WBS_DATA_WIDTH-1:0]   wbs_dat_o,     // DAT_O() data out
+    output wire                        wbs_we_o,      // WE_O write enable output
+    output wire [WBS_SELECT_WIDTH-1:0] wbs_sel_o,     // SEL_O() select output
+    output wire                        wbs_stb_o,     // STB_O strobe output
+    input  wire                        wbs_ack_i,     // ACK_I acknowledge input
+    input  wire                        wbs_err_i,     // ERR_I error input
+    input  wire                        wbs_rty_i,     // RTY_I retry input
+    output wire                        wbs_cyc_o      // CYC_O cycle output
+);
+
+// address bit offets
+parameter WBM_ADDR_BIT_OFFSET = $clog2(WBM_SELECT_WIDTH);
+parameter WBS_ADDR_BIT_OFFSET = $clog2(WBS_SELECT_WIDTH);
+// for interfaces that are more than one word wide, disable address lines
+parameter WBM_VALID_ADDR_WIDTH = ADDR_WIDTH - WBM_ADDR_BIT_OFFSET;
+parameter WBS_VALID_ADDR_WIDTH = ADDR_WIDTH - WBS_ADDR_BIT_OFFSET;
+// width of data port in words (1, 2, 4, or 8)
+parameter WBM_WORD_WIDTH = WBM_SELECT_WIDTH;
+parameter WBS_WORD_WIDTH = WBS_SELECT_WIDTH;
+// size of words (8, 16, 32, or 64 bits)
+parameter WBM_WORD_SIZE = WBM_DATA_WIDTH/WBM_WORD_WIDTH;
+parameter WBS_WORD_SIZE = WBS_DATA_WIDTH/WBS_WORD_WIDTH;
+// required number of cycles to match widths
+localparam CYCLE_COUNT = (WBM_SELECT_WIDTH > WBS_SELECT_WIDTH) ? (WBM_SELECT_WIDTH / WBS_SELECT_WIDTH) : (WBS_SELECT_WIDTH / WBM_SELECT_WIDTH);
+
+// bus width assertions
+initial begin
+    if (WBM_WORD_WIDTH * WBM_WORD_SIZE != WBM_DATA_WIDTH) begin
+        $error("Error: master data width not evenly divisble");
+        $finish;
+    end
+
+    if (WBS_WORD_WIDTH * WBS_WORD_SIZE != WBS_DATA_WIDTH) begin
+        $error("Error: slave data width not evenly divisble");
+        $finish;
+    end
+
+    if (WBM_WORD_SIZE != WBS_WORD_SIZE) begin
+        $error("Error: word size mismatch");
+        $finish;
+    end
+end
+
+// state register
+localparam [1:0]
+    STATE_IDLE = 2'd0,
+    STATE_WAIT_ACK = 2'd1,
+    STATE_PAUSE = 2'd2;
+
+reg [1:0] state_reg = STATE_IDLE, state_next;
+
+reg [CYCLE_COUNT-1:0] cycle_mask_reg = {CYCLE_COUNT{1'b1}}, cycle_mask_next;
+reg [CYCLE_COUNT-1:0] cycle_sel_raw;
+wire [CYCLE_COUNT-1:0] cycle_sel;
+wire [$clog2(CYCLE_COUNT)-1:0] cycle_sel_enc;
+wire cycle_sel_valid;
+
+reg [$clog2(CYCLE_COUNT)-1:0] current_cycle_reg = 0, current_cycle_next;
+
+reg [WBM_DATA_WIDTH-1:0] wbm_dat_o_reg = {WBM_DATA_WIDTH{1'b0}}, wbm_dat_o_next;
+reg wbm_ack_o_reg = 1'b0, wbm_ack_o_next;
+reg wbm_err_o_reg = 1'b0, wbm_err_o_next;
+reg wbm_rty_o_reg = 1'b0, wbm_rty_o_next;
+
+reg [ADDR_WIDTH-1:0] wbs_adr_o_reg = {ADDR_WIDTH{1'b0}}, wbs_adr_o_next;
+reg [WBS_DATA_WIDTH-1:0] wbs_dat_o_reg = {WBS_DATA_WIDTH{1'b0}}, wbs_dat_o_next;
+reg wbs_we_o_reg = 1'b0, wbs_we_o_next;
+reg [WBS_SELECT_WIDTH-1:0] wbs_sel_o_reg = {WBS_SELECT_WIDTH{1'b0}}, wbs_sel_o_next;
+reg wbs_stb_o_reg = 1'b0, wbs_stb_o_next;
+reg wbs_cyc_o_reg = 1'b0, wbs_cyc_o_next;
+
+assign wbm_dat_o = wbm_dat_o_reg;
+assign wbm_ack_o = wbm_ack_o_reg;
+assign wbm_err_o = wbm_err_o_reg;
+assign wbm_rty_o = wbm_rty_o_reg;
+
+assign wbs_adr_o = wbs_adr_o_reg;
+assign wbs_dat_o = wbs_dat_o_reg;
+assign wbs_we_o = wbs_we_o_reg;
+assign wbs_sel_o = wbs_sel_o_reg;
+assign wbs_stb_o = wbs_stb_o_reg;
+assign wbs_cyc_o = wbs_cyc_o_reg;
+
+priority_encoder #(
+    .WIDTH(CYCLE_COUNT),
+    .LSB_PRIORITY("HIGH")
+)
+cycle_encoder_inst (
+    .input_unencoded(cycle_sel_raw & cycle_mask_reg),
+    .output_valid(cycle_sel_valid),
+    .output_encoded(cycle_sel_enc),
+    .output_unencoded(cycle_sel)
+);
+
+integer j;
+
+always @* begin
+    for (j = 0; j < CYCLE_COUNT; j = j + 1) begin
+        cycle_sel_raw[j] <= wbm_sel_i[j*WBS_SELECT_WIDTH +: WBS_SELECT_WIDTH] != 0;
+    end
+end
+
+integer i;
+
+always @* begin
+    state_next = STATE_IDLE;
+
+    cycle_mask_next = cycle_mask_reg;
+
+    current_cycle_next = current_cycle_reg;
+
+    wbm_dat_o_next = wbm_dat_o_reg;
+    wbm_ack_o_next = 1'b0;
+    wbm_err_o_next = 1'b0;
+    wbm_rty_o_next = 1'b0;
+
+    wbs_adr_o_next = wbs_adr_o_reg;
+    wbs_dat_o_next = wbs_dat_o_reg;
+    wbs_we_o_next = wbs_we_o_reg;
+    wbs_sel_o_next = wbs_sel_o_reg;
+    wbs_stb_o_next = wbs_stb_o_reg;
+    wbs_cyc_o_next = wbs_cyc_o_reg;
+
+    if (WBM_WORD_WIDTH > WBS_WORD_WIDTH) begin
+        // master is wider (multiple cycles may be necessary)
+        case (state_reg)
+            STATE_IDLE: begin
+                // idle state
+                wbm_dat_o_next = 1'b0;
+                wbs_cyc_o_next = wbm_cyc_i;
+
+                cycle_mask_next = {CYCLE_COUNT{1'b1}};
+
+                state_next = STATE_IDLE;
+
+                if (wbm_cyc_i & wbm_stb_i & ~(wbm_ack_o | wbm_err_o | wbm_rty_o)) begin
+                    // master cycle start
+                    wbm_err_o_next = 1'b1;
+
+                    if (cycle_sel_valid) begin
+                        // set current cycle and mask for next cycle
+                        current_cycle_next = cycle_sel_enc;
+                        cycle_mask_next = {CYCLE_COUNT{1'b1}} << (cycle_sel_enc+1);
+                        // mask address for slave alignment
+                        wbs_adr_o_next = wbm_adr_i & ({ADDR_WIDTH{1'b1}} << WBM_ADDR_BIT_OFFSET);
+                        wbs_adr_o_next[WBM_ADDR_BIT_OFFSET - 1:WBS_ADDR_BIT_OFFSET] = cycle_sel_enc;
+                        // select corresponding data word
+                        wbs_dat_o_next = wbm_dat_i[cycle_sel_enc*WBS_DATA_WIDTH +: WBS_DATA_WIDTH];
+                        wbs_we_o_next = wbm_we_i;
+                        // select proper select lines
+                        wbs_sel_o_next = wbm_sel_i[cycle_sel_enc*WBS_SELECT_WIDTH +: WBS_SELECT_WIDTH];
+                        wbs_stb_o_next = 1'b1;
+                        wbs_cyc_o_next = 1'b1;
+                        wbm_err_o_next = 1'b0;
+                        state_next = STATE_WAIT_ACK;
+                    end
+                end
+            end
+            STATE_WAIT_ACK: begin
+                if (wbs_err_i | wbs_rty_i) begin
+                    // error or retry - stop and propagate condition to master
+                    cycle_mask_next = {CYCLE_COUNT{1'b1}};
+                    wbm_ack_o_next = wbs_ack_i;
+                    wbm_err_o_next = wbs_err_i;
+                    wbm_rty_o_next = wbs_rty_i;
+                    wbs_we_o_next = 1'b0;
+                    wbs_stb_o_next = 1'b0;
+                    state_next = STATE_IDLE;
+                end else if (wbs_ack_i) begin
+                    // end of cycle - pass through slave to master
+                    // store output word with proper offset
+                    wbm_dat_o_next[current_cycle_reg*WBS_DATA_WIDTH +: WBS_DATA_WIDTH] = wbs_dat_i;
+                    wbm_ack_o_next = wbs_ack_i;
+                    wbs_we_o_next = 1'b0;
+                    wbs_stb_o_next = 1'b0;
+
+                    cycle_mask_next = {CYCLE_COUNT{1'b1}};
+                    state_next = STATE_IDLE;
+
+                    if (cycle_sel_valid) begin
+                        // set current cycle and mask for next cycle
+                        current_cycle_next = cycle_sel_enc;
+                        cycle_mask_next = {CYCLE_COUNT{1'b1}} << (cycle_sel_enc+1);
+                        // mask address for slave alignment
+                        wbs_adr_o_next = wbm_adr_i & ({ADDR_WIDTH{1'b1}} << WBM_ADDR_BIT_OFFSET);
+                        wbs_adr_o_next[WBM_ADDR_BIT_OFFSET - 1:WBS_ADDR_BIT_OFFSET] = cycle_sel_enc;
+                        // select corresponding data word
+                        wbs_dat_o_next = wbm_dat_i[cycle_sel_enc*WBS_DATA_WIDTH +: WBS_DATA_WIDTH];
+                        wbs_we_o_next = wbm_we_i;
+                        // select proper select lines
+                        wbs_sel_o_next = wbm_sel_i[cycle_sel_enc*WBS_SELECT_WIDTH +: WBS_SELECT_WIDTH];
+                        wbs_stb_o_next = 1'b0;
+                        wbs_cyc_o_next = 1'b1;
+                        wbm_ack_o_next = 1'b0;
+                        state_next = STATE_PAUSE;
+                    end
+                end else begin
+                    state_next = STATE_WAIT_ACK;
+                end
+            end
+            STATE_PAUSE: begin
+                // start new cycle
+                wbs_stb_o_next = 1'b1;
+                state_next = STATE_WAIT_ACK;
+            end
+        endcase
+    end else if (WBS_WORD_WIDTH > WBM_WORD_WIDTH) begin
+        // slave is wider (always single cycle)
+        if (wbs_cyc_o_reg & wbs_stb_o_reg) begin
+            // cycle - hold values
+            if (wbs_ack_i | wbs_err_i | wbs_rty_i) begin
+                // end of cycle - pass through slave to master
+                // select output word based on address LSBs
+                wbm_dat_o_next = wbs_dat_i >> (wbm_adr_i[WBS_ADDR_BIT_OFFSET - 1:WBM_ADDR_BIT_OFFSET] * WBM_DATA_WIDTH);
+                wbm_ack_o_next = wbs_ack_i;
+                wbm_err_o_next = wbs_err_i;
+                wbm_rty_o_next = wbs_rty_i;
+                wbs_we_o_next = 1'b0;
+                wbs_stb_o_next = 1'b0;
+            end
+        end else begin
+            // idle - pass through master to slave
+            wbm_ack_o_next = 1'b0;
+            wbm_err_o_next = 1'b0;
+            wbm_rty_o_next = 1'b0;
+            // mask address for slave alignment
+            wbs_adr_o_next = wbm_adr_i & ({ADDR_WIDTH{1'b1}} << WBS_ADDR_BIT_OFFSET);
+            // duplicate input data across output port
+            wbs_dat_o_next = {(WBS_WORD_WIDTH / WBM_WORD_WIDTH){wbm_dat_i}};
+            wbs_we_o_next = wbm_we_i & ~(wbm_ack_o | wbm_err_o | wbm_rty_o);
+            // shift select lines based on address LSBs
+            wbs_sel_o_next = wbm_sel_i << (wbm_adr_i[WBS_ADDR_BIT_OFFSET - 1:WBM_ADDR_BIT_OFFSET] * WBM_SELECT_WIDTH);
+            wbs_stb_o_next = wbm_stb_i & ~(wbm_ack_o | wbm_err_o | wbm_rty_o);
+            wbs_cyc_o_next = wbm_cyc_i;
+        end
+    end else begin
+        // same width - act as a simple register
+        if (wbs_cyc_o_reg & wbs_stb_o_reg) begin
+            // cycle - hold values
+            if (wbs_ack_i | wbs_err_i | wbs_rty_i) begin
+                // end of cycle - pass through slave to master
+                wbm_dat_o_next = wbs_dat_i;
+                wbm_ack_o_next = wbs_ack_i;
+                wbm_err_o_next = wbs_err_i;
+                wbm_rty_o_next = wbs_rty_i;
+                wbs_we_o_next = 1'b0;
+                wbs_stb_o_next = 1'b0;
+            end
+        end else begin
+            // idle - pass through master to slave
+            wbm_ack_o_next = 1'b0;
+            wbm_err_o_next = 1'b0;
+            wbm_rty_o_next = 1'b0;
+            wbs_adr_o_next = wbm_adr_i;
+            wbs_dat_o_next = wbm_dat_i;
+            wbs_we_o_next = wbm_we_i & ~(wbm_ack_o | wbm_err_o | wbm_rty_o);
+            wbs_sel_o_next = wbm_sel_i;
+            wbs_stb_o_next = wbm_stb_i & ~(wbm_ack_o | wbm_err_o | wbm_rty_o);
+            wbs_cyc_o_next = wbm_cyc_i;
+        end
+    end
+end
+
+always @(posedge clk) begin
+    if (rst) begin
+        state_reg <= STATE_IDLE;
+
+        cycle_mask_reg <= {CYCLE_COUNT{1'b1}};
+
+        wbm_ack_o_reg <= 1'b0;
+        wbm_err_o_reg <= 1'b0;
+        wbm_rty_o_reg <= 1'b0;
+
+        wbs_stb_o_reg <= 1'b0;
+        wbs_cyc_o_reg <= 1'b0;
+    end else begin
+        state_reg <= state_next;
+
+        cycle_mask_reg <= cycle_mask_next;
+
+        wbm_ack_o_reg <= wbm_ack_o_next;
+        wbm_err_o_reg <= wbm_err_o_next;
+        wbm_rty_o_reg <= wbm_rty_o_next;
+
+        wbs_stb_o_reg <= wbs_stb_o_next;
+        wbs_cyc_o_reg <= wbs_cyc_o_next;
+    end
+
+    current_cycle_reg <= current_cycle_next;
+
+    wbm_dat_o_reg <= wbm_dat_o_next;
+
+    wbs_adr_o_reg <= wbs_adr_o_next;
+    wbs_dat_o_reg <= wbs_dat_o_next;
+    wbs_we_o_reg <= wbs_we_o_next;
+    wbs_sel_o_reg <= wbs_sel_o_next;
+end
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter.py b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter.py
new file mode 100755
index 0000000..2fdf912
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter.py
@@ -0,0 +1,183 @@
+#!/usr/bin/env python
+"""
+Generates a Wishbone arbiter with the specified number of ports
+"""
+
+from __future__ import print_function
+
+import argparse
+import math
+from jinja2 import Template
+
+def main():
+    parser = argparse.ArgumentParser(description=__doc__.strip())
+    parser.add_argument('-p', '--ports',  type=int, default=2, help="number of ports")
+    parser.add_argument('-n', '--name',   type=str, help="module name")
+    parser.add_argument('-o', '--output', type=str, help="output file name")
+
+    args = parser.parse_args()
+
+    try:
+        generate(**args.__dict__)
+    except IOError as ex:
+        print(ex)
+        exit(1)
+
+def generate(ports=2, name=None, output=None):
+    if name is None:
+        name = "wb_arbiter_{0}".format(ports)
+
+    if output is None:
+        output = name + ".v"
+
+    print("Opening file '{0}'...".format(output))
+
+    output_file = open(output, 'w')
+
+    print("Generating {0} port Wishbone arbiter {1}...".format(ports, name))
+
+    select_width = int(math.ceil(math.log(ports, 2)))
+
+    t = Template(u"""/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1 ns / 1 ps
+
+/*
+ * Wishbone {{n}} port arbiter
+ */
+module {{name}} #
+(
+    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8),      // width of word select bus (1, 2, 4, or 8)
+    parameter ARB_TYPE = "PRIORITY",              // arbitration type: "PRIORITY" or "ROUND_ROBIN"
+    parameter LSB_PRIORITY = "HIGH"               // LSB priority: "LOW", "HIGH"
+)
+(
+    input  wire                    clk,
+    input  wire                    rst,
+{%- for p in ports %}
+
+    /*
+     * Wishbone master {{p}} input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm{{p}}_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm{{p}}_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm{{p}}_dat_o,    // DAT_O() data out
+    input  wire                    wbm{{p}}_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm{{p}}_sel_i,    // SEL_I() select input
+    input  wire                    wbm{{p}}_stb_i,    // STB_I strobe input
+    output wire                    wbm{{p}}_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm{{p}}_err_o,    // ERR_O error output
+    output wire                    wbm{{p}}_rty_o,    // RTY_O retry output
+    input  wire                    wbm{{p}}_cyc_i,    // CYC_I cycle input
+{%- endfor %}
+
+    /*
+     * Wishbone slave output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs_adr_o,     // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs_dat_i,     // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs_dat_o,     // DAT_O() data out
+    output wire                    wbs_we_o,      // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs_sel_o,     // SEL_O() select output
+    output wire                    wbs_stb_o,     // STB_O strobe output
+    input  wire                    wbs_ack_i,     // ACK_I acknowledge input
+    input  wire                    wbs_err_i,     // ERR_I error input
+    input  wire                    wbs_rty_i,     // RTY_I retry input
+    output wire                    wbs_cyc_o      // CYC_O cycle output
+);
+
+wire [{{n-1}}:0] request;
+wire [{{n-1}}:0] grant;
+{% for p in ports %}
+assign request[{{p}}] = wbm{{p}}_cyc_i;
+{%- endfor %}
+{% for p in ports %}
+wire wbm{{p}}_sel = grant[{{p}}] & grant_valid;
+{%- endfor %}
+{%- for p in ports %}
+
+// master {{p}}
+assign wbm{{p}}_dat_o = wbs_dat_i;
+assign wbm{{p}}_ack_o = wbs_ack_i & wbm{{p}}_sel;
+assign wbm{{p}}_err_o = wbs_err_i & wbm{{p}}_sel;
+assign wbm{{p}}_rty_o = wbs_rty_i & wbm{{p}}_sel;
+{%- endfor %}
+
+// slave
+assign wbs_adr_o = {% for p in ports %}wbm{{p}}_sel ? wbm{{p}}_adr_i :
+                   {% endfor %}{ADDR_WIDTH{1'b0}};
+
+assign wbs_dat_o = {% for p in ports %}wbm{{p}}_sel ? wbm{{p}}_dat_i :
+                   {% endfor %}{DATA_WIDTH{1'b0}};
+
+assign wbs_we_o = {% for p in ports %}wbm{{p}}_sel ? wbm{{p}}_we_i :
+                  {% endfor %}1'b0;
+
+assign wbs_sel_o = {% for p in ports %}wbm{{p}}_sel ? wbm{{p}}_sel_i :
+                   {% endfor %}{SELECT_WIDTH{1'b0}};
+
+assign wbs_stb_o = {% for p in ports %}wbm{{p}}_sel ? wbm{{p}}_stb_i :
+                   {% endfor %}1'b0;
+
+assign wbs_cyc_o = {% for p in ports %}wbm{{p}}_sel ? 1'b1 :
+                   {% endfor %}1'b0;
+
+// arbiter instance
+arbiter #(
+    .PORTS({{n}}),
+    .TYPE(ARB_TYPE),
+    .BLOCK("REQUEST"),
+    .LSB_PRIORITY(LSB_PRIORITY)
+)
+arb_inst (
+    .clk(clk),
+    .rst(rst),
+    .request(request),
+    .acknowledge(),
+    .grant(grant),
+    .grant_valid(grant_valid),
+    .grant_encoded()
+);
+
+endmodule
+
+""")
+    
+    output_file.write(t.render(
+        n=ports,
+        w=select_width,
+        name=name,
+        ports=range(ports)
+    ))
+    
+    print("Done")
+
+if __name__ == "__main__":
+    main()
+
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter_2.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter_2.v
new file mode 100644
index 0000000..ead4717
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter_2.v
@@ -0,0 +1,150 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1 ns / 1 ps
+
+/*
+ * Wishbone 2 port arbiter
+ */
+module wb_arbiter_2 #
+(
+    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8),      // width of word select bus (1, 2, 4, or 8)
+    parameter ARB_TYPE = "PRIORITY",              // arbitration type: "PRIORITY" or "ROUND_ROBIN"
+    parameter LSB_PRIORITY = "HIGH"               // LSB priority: "LOW", "HIGH"
+)
+(
+    input  wire                    clk,
+    input  wire                    rst,
+
+    /*
+     * Wishbone master 0 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm0_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm0_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm0_dat_o,    // DAT_O() data out
+    input  wire                    wbm0_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm0_sel_i,    // SEL_I() select input
+    input  wire                    wbm0_stb_i,    // STB_I strobe input
+    output wire                    wbm0_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm0_err_o,    // ERR_O error output
+    output wire                    wbm0_rty_o,    // RTY_O retry output
+    input  wire                    wbm0_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 1 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm1_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm1_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm1_dat_o,    // DAT_O() data out
+    input  wire                    wbm1_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm1_sel_i,    // SEL_I() select input
+    input  wire                    wbm1_stb_i,    // STB_I strobe input
+    output wire                    wbm1_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm1_err_o,    // ERR_O error output
+    output wire                    wbm1_rty_o,    // RTY_O retry output
+    input  wire                    wbm1_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone slave output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs_adr_o,     // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs_dat_i,     // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs_dat_o,     // DAT_O() data out
+    output wire                    wbs_we_o,      // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs_sel_o,     // SEL_O() select output
+    output wire                    wbs_stb_o,     // STB_O strobe output
+    input  wire                    wbs_ack_i,     // ACK_I acknowledge input
+    input  wire                    wbs_err_i,     // ERR_I error input
+    input  wire                    wbs_rty_i,     // RTY_I retry input
+    output wire                    wbs_cyc_o      // CYC_O cycle output
+);
+
+wire [1:0] request;
+wire [1:0] grant;
+
+assign request[0] = wbm0_cyc_i;
+assign request[1] = wbm1_cyc_i;
+
+wire wbm0_sel = grant[0] & grant_valid;
+wire wbm1_sel = grant[1] & grant_valid;
+
+// master 0
+assign wbm0_dat_o = wbs_dat_i;
+assign wbm0_ack_o = wbs_ack_i & wbm0_sel;
+assign wbm0_err_o = wbs_err_i & wbm0_sel;
+assign wbm0_rty_o = wbs_rty_i & wbm0_sel;
+
+// master 1
+assign wbm1_dat_o = wbs_dat_i;
+assign wbm1_ack_o = wbs_ack_i & wbm1_sel;
+assign wbm1_err_o = wbs_err_i & wbm1_sel;
+assign wbm1_rty_o = wbs_rty_i & wbm1_sel;
+
+// slave
+assign wbs_adr_o = wbm0_sel ? wbm0_adr_i :
+                   wbm1_sel ? wbm1_adr_i :
+                   {ADDR_WIDTH{1'b0}};
+
+assign wbs_dat_o = wbm0_sel ? wbm0_dat_i :
+                   wbm1_sel ? wbm1_dat_i :
+                   {DATA_WIDTH{1'b0}};
+
+assign wbs_we_o = wbm0_sel ? wbm0_we_i :
+                  wbm1_sel ? wbm1_we_i :
+                  1'b0;
+
+assign wbs_sel_o = wbm0_sel ? wbm0_sel_i :
+                   wbm1_sel ? wbm1_sel_i :
+                   {SELECT_WIDTH{1'b0}};
+
+assign wbs_stb_o = wbm0_sel ? wbm0_stb_i :
+                   wbm1_sel ? wbm1_stb_i :
+                   1'b0;
+
+assign wbs_cyc_o = wbm0_sel ? 1'b1 :
+                   wbm1_sel ? 1'b1 :
+                   1'b0;
+
+// arbiter instance
+arbiter #(
+    .PORTS(2),
+    .TYPE(ARB_TYPE),
+    .BLOCK("REQUEST"),
+    .LSB_PRIORITY(LSB_PRIORITY)
+)
+arb_inst (
+    .clk(clk),
+    .rst(rst),
+    .request(request),
+    .acknowledge(),
+    .grant(grant),
+    .grant_valid(grant_valid),
+    .grant_encoded()
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter_3.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter_3.v
new file mode 100644
index 0000000..22250e5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter_3.v
@@ -0,0 +1,178 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1 ns / 1 ps
+
+/*
+ * Wishbone 3 port arbiter
+ */
+module wb_arbiter_3 #
+(
+    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8),      // width of word select bus (1, 2, 4, or 8)
+    parameter ARB_TYPE = "PRIORITY",              // arbitration type: "PRIORITY" or "ROUND_ROBIN"
+    parameter LSB_PRIORITY = "HIGH"               // LSB priority: "LOW", "HIGH"
+)
+(
+    input  wire                    clk,
+    input  wire                    rst,
+
+    /*
+     * Wishbone master 0 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm0_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm0_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm0_dat_o,    // DAT_O() data out
+    input  wire                    wbm0_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm0_sel_i,    // SEL_I() select input
+    input  wire                    wbm0_stb_i,    // STB_I strobe input
+    output wire                    wbm0_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm0_err_o,    // ERR_O error output
+    output wire                    wbm0_rty_o,    // RTY_O retry output
+    input  wire                    wbm0_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 1 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm1_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm1_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm1_dat_o,    // DAT_O() data out
+    input  wire                    wbm1_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm1_sel_i,    // SEL_I() select input
+    input  wire                    wbm1_stb_i,    // STB_I strobe input
+    output wire                    wbm1_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm1_err_o,    // ERR_O error output
+    output wire                    wbm1_rty_o,    // RTY_O retry output
+    input  wire                    wbm1_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 2 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm2_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm2_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm2_dat_o,    // DAT_O() data out
+    input  wire                    wbm2_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm2_sel_i,    // SEL_I() select input
+    input  wire                    wbm2_stb_i,    // STB_I strobe input
+    output wire                    wbm2_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm2_err_o,    // ERR_O error output
+    output wire                    wbm2_rty_o,    // RTY_O retry output
+    input  wire                    wbm2_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone slave output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs_adr_o,     // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs_dat_i,     // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs_dat_o,     // DAT_O() data out
+    output wire                    wbs_we_o,      // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs_sel_o,     // SEL_O() select output
+    output wire                    wbs_stb_o,     // STB_O strobe output
+    input  wire                    wbs_ack_i,     // ACK_I acknowledge input
+    input  wire                    wbs_err_i,     // ERR_I error input
+    input  wire                    wbs_rty_i,     // RTY_I retry input
+    output wire                    wbs_cyc_o      // CYC_O cycle output
+);
+
+wire [2:0] request;
+wire [2:0] grant;
+
+assign request[0] = wbm0_cyc_i;
+assign request[1] = wbm1_cyc_i;
+assign request[2] = wbm2_cyc_i;
+
+wire wbm0_sel = grant[0] & grant_valid;
+wire wbm1_sel = grant[1] & grant_valid;
+wire wbm2_sel = grant[2] & grant_valid;
+
+// master 0
+assign wbm0_dat_o = wbs_dat_i;
+assign wbm0_ack_o = wbs_ack_i & wbm0_sel;
+assign wbm0_err_o = wbs_err_i & wbm0_sel;
+assign wbm0_rty_o = wbs_rty_i & wbm0_sel;
+
+// master 1
+assign wbm1_dat_o = wbs_dat_i;
+assign wbm1_ack_o = wbs_ack_i & wbm1_sel;
+assign wbm1_err_o = wbs_err_i & wbm1_sel;
+assign wbm1_rty_o = wbs_rty_i & wbm1_sel;
+
+// master 2
+assign wbm2_dat_o = wbs_dat_i;
+assign wbm2_ack_o = wbs_ack_i & wbm2_sel;
+assign wbm2_err_o = wbs_err_i & wbm2_sel;
+assign wbm2_rty_o = wbs_rty_i & wbm2_sel;
+
+// slave
+assign wbs_adr_o = wbm0_sel ? wbm0_adr_i :
+                   wbm1_sel ? wbm1_adr_i :
+                   wbm2_sel ? wbm2_adr_i :
+                   {ADDR_WIDTH{1'b0}};
+
+assign wbs_dat_o = wbm0_sel ? wbm0_dat_i :
+                   wbm1_sel ? wbm1_dat_i :
+                   wbm2_sel ? wbm2_dat_i :
+                   {DATA_WIDTH{1'b0}};
+
+assign wbs_we_o = wbm0_sel ? wbm0_we_i :
+                  wbm1_sel ? wbm1_we_i :
+                  wbm2_sel ? wbm2_we_i :
+                  1'b0;
+
+assign wbs_sel_o = wbm0_sel ? wbm0_sel_i :
+                   wbm1_sel ? wbm1_sel_i :
+                   wbm2_sel ? wbm2_sel_i :
+                   {SELECT_WIDTH{1'b0}};
+
+assign wbs_stb_o = wbm0_sel ? wbm0_stb_i :
+                   wbm1_sel ? wbm1_stb_i :
+                   wbm2_sel ? wbm2_stb_i :
+                   1'b0;
+
+assign wbs_cyc_o = wbm0_sel ? 1'b1 :
+                   wbm1_sel ? 1'b1 :
+                   wbm2_sel ? 1'b1 :
+                   1'b0;
+
+// arbiter instance
+arbiter #(
+    .PORTS(3),
+    .TYPE(ARB_TYPE),
+    .BLOCK("REQUEST"),
+    .LSB_PRIORITY(LSB_PRIORITY)
+)
+arb_inst (
+    .clk(clk),
+    .rst(rst),
+    .request(request),
+    .acknowledge(),
+    .grant(grant),
+    .grant_valid(grant_valid),
+    .grant_encoded()
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter_4.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter_4.v
new file mode 100644
index 0000000..883784a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter_4.v
@@ -0,0 +1,206 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1 ns / 1 ps
+
+/*
+ * Wishbone 4 port arbiter
+ */
+module wb_arbiter_4 #
+(
+    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8),      // width of word select bus (1, 2, 4, or 8)
+    parameter ARB_TYPE = "PRIORITY",              // arbitration type: "PRIORITY" or "ROUND_ROBIN"
+    parameter LSB_PRIORITY = "HIGH"               // LSB priority: "LOW", "HIGH"
+)
+(
+    input  wire                    clk,
+    input  wire                    rst,
+
+    /*
+     * Wishbone master 0 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm0_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm0_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm0_dat_o,    // DAT_O() data out
+    input  wire                    wbm0_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm0_sel_i,    // SEL_I() select input
+    input  wire                    wbm0_stb_i,    // STB_I strobe input
+    output wire                    wbm0_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm0_err_o,    // ERR_O error output
+    output wire                    wbm0_rty_o,    // RTY_O retry output
+    input  wire                    wbm0_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 1 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm1_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm1_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm1_dat_o,    // DAT_O() data out
+    input  wire                    wbm1_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm1_sel_i,    // SEL_I() select input
+    input  wire                    wbm1_stb_i,    // STB_I strobe input
+    output wire                    wbm1_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm1_err_o,    // ERR_O error output
+    output wire                    wbm1_rty_o,    // RTY_O retry output
+    input  wire                    wbm1_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 2 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm2_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm2_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm2_dat_o,    // DAT_O() data out
+    input  wire                    wbm2_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm2_sel_i,    // SEL_I() select input
+    input  wire                    wbm2_stb_i,    // STB_I strobe input
+    output wire                    wbm2_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm2_err_o,    // ERR_O error output
+    output wire                    wbm2_rty_o,    // RTY_O retry output
+    input  wire                    wbm2_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 3 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm3_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm3_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm3_dat_o,    // DAT_O() data out
+    input  wire                    wbm3_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm3_sel_i,    // SEL_I() select input
+    input  wire                    wbm3_stb_i,    // STB_I strobe input
+    output wire                    wbm3_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm3_err_o,    // ERR_O error output
+    output wire                    wbm3_rty_o,    // RTY_O retry output
+    input  wire                    wbm3_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone slave output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs_adr_o,     // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs_dat_i,     // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs_dat_o,     // DAT_O() data out
+    output wire                    wbs_we_o,      // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs_sel_o,     // SEL_O() select output
+    output wire                    wbs_stb_o,     // STB_O strobe output
+    input  wire                    wbs_ack_i,     // ACK_I acknowledge input
+    input  wire                    wbs_err_i,     // ERR_I error input
+    input  wire                    wbs_rty_i,     // RTY_I retry input
+    output wire                    wbs_cyc_o      // CYC_O cycle output
+);
+
+wire [3:0] request;
+wire [3:0] grant;
+
+assign request[0] = wbm0_cyc_i;
+assign request[1] = wbm1_cyc_i;
+assign request[2] = wbm2_cyc_i;
+assign request[3] = wbm3_cyc_i;
+
+wire wbm0_sel = grant[0] & grant_valid;
+wire wbm1_sel = grant[1] & grant_valid;
+wire wbm2_sel = grant[2] & grant_valid;
+wire wbm3_sel = grant[3] & grant_valid;
+
+// master 0
+assign wbm0_dat_o = wbs_dat_i;
+assign wbm0_ack_o = wbs_ack_i & wbm0_sel;
+assign wbm0_err_o = wbs_err_i & wbm0_sel;
+assign wbm0_rty_o = wbs_rty_i & wbm0_sel;
+
+// master 1
+assign wbm1_dat_o = wbs_dat_i;
+assign wbm1_ack_o = wbs_ack_i & wbm1_sel;
+assign wbm1_err_o = wbs_err_i & wbm1_sel;
+assign wbm1_rty_o = wbs_rty_i & wbm1_sel;
+
+// master 2
+assign wbm2_dat_o = wbs_dat_i;
+assign wbm2_ack_o = wbs_ack_i & wbm2_sel;
+assign wbm2_err_o = wbs_err_i & wbm2_sel;
+assign wbm2_rty_o = wbs_rty_i & wbm2_sel;
+
+// master 3
+assign wbm3_dat_o = wbs_dat_i;
+assign wbm3_ack_o = wbs_ack_i & wbm3_sel;
+assign wbm3_err_o = wbs_err_i & wbm3_sel;
+assign wbm3_rty_o = wbs_rty_i & wbm3_sel;
+
+// slave
+assign wbs_adr_o = wbm0_sel ? wbm0_adr_i :
+                   wbm1_sel ? wbm1_adr_i :
+                   wbm2_sel ? wbm2_adr_i :
+                   wbm3_sel ? wbm3_adr_i :
+                   {ADDR_WIDTH{1'b0}};
+
+assign wbs_dat_o = wbm0_sel ? wbm0_dat_i :
+                   wbm1_sel ? wbm1_dat_i :
+                   wbm2_sel ? wbm2_dat_i :
+                   wbm3_sel ? wbm3_dat_i :
+                   {DATA_WIDTH{1'b0}};
+
+assign wbs_we_o = wbm0_sel ? wbm0_we_i :
+                  wbm1_sel ? wbm1_we_i :
+                  wbm2_sel ? wbm2_we_i :
+                  wbm3_sel ? wbm3_we_i :
+                  1'b0;
+
+assign wbs_sel_o = wbm0_sel ? wbm0_sel_i :
+                   wbm1_sel ? wbm1_sel_i :
+                   wbm2_sel ? wbm2_sel_i :
+                   wbm3_sel ? wbm3_sel_i :
+                   {SELECT_WIDTH{1'b0}};
+
+assign wbs_stb_o = wbm0_sel ? wbm0_stb_i :
+                   wbm1_sel ? wbm1_stb_i :
+                   wbm2_sel ? wbm2_stb_i :
+                   wbm3_sel ? wbm3_stb_i :
+                   1'b0;
+
+assign wbs_cyc_o = wbm0_sel ? 1'b1 :
+                   wbm1_sel ? 1'b1 :
+                   wbm2_sel ? 1'b1 :
+                   wbm3_sel ? 1'b1 :
+                   1'b0;
+
+// arbiter instance
+arbiter #(
+    .PORTS(4),
+    .TYPE(ARB_TYPE),
+    .BLOCK("REQUEST"),
+    .LSB_PRIORITY(LSB_PRIORITY)
+)
+arb_inst (
+    .clk(clk),
+    .rst(rst),
+    .request(request),
+    .acknowledge(),
+    .grant(grant),
+    .grant_valid(grant_valid),
+    .grant_encoded()
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter_5.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter_5.v
new file mode 100644
index 0000000..dba2468
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter_5.v
@@ -0,0 +1,234 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1 ns / 1 ps
+
+/*
+ * Wishbone 5 port arbiter
+ */
+module wb_arbiter_5 #
+(
+    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8),      // width of word select bus (1, 2, 4, or 8)
+    parameter ARB_TYPE = "PRIORITY",              // arbitration type: "PRIORITY" or "ROUND_ROBIN"
+    parameter LSB_PRIORITY = "HIGH"               // LSB priority: "LOW", "HIGH"
+)
+(
+    input  wire                    clk,
+    input  wire                    rst,
+
+    /*
+     * Wishbone master 0 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm0_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm0_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm0_dat_o,    // DAT_O() data out
+    input  wire                    wbm0_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm0_sel_i,    // SEL_I() select input
+    input  wire                    wbm0_stb_i,    // STB_I strobe input
+    output wire                    wbm0_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm0_err_o,    // ERR_O error output
+    output wire                    wbm0_rty_o,    // RTY_O retry output
+    input  wire                    wbm0_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 1 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm1_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm1_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm1_dat_o,    // DAT_O() data out
+    input  wire                    wbm1_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm1_sel_i,    // SEL_I() select input
+    input  wire                    wbm1_stb_i,    // STB_I strobe input
+    output wire                    wbm1_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm1_err_o,    // ERR_O error output
+    output wire                    wbm1_rty_o,    // RTY_O retry output
+    input  wire                    wbm1_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 2 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm2_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm2_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm2_dat_o,    // DAT_O() data out
+    input  wire                    wbm2_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm2_sel_i,    // SEL_I() select input
+    input  wire                    wbm2_stb_i,    // STB_I strobe input
+    output wire                    wbm2_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm2_err_o,    // ERR_O error output
+    output wire                    wbm2_rty_o,    // RTY_O retry output
+    input  wire                    wbm2_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 3 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm3_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm3_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm3_dat_o,    // DAT_O() data out
+    input  wire                    wbm3_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm3_sel_i,    // SEL_I() select input
+    input  wire                    wbm3_stb_i,    // STB_I strobe input
+    output wire                    wbm3_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm3_err_o,    // ERR_O error output
+    output wire                    wbm3_rty_o,    // RTY_O retry output
+    input  wire                    wbm3_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 4 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm4_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm4_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm4_dat_o,    // DAT_O() data out
+    input  wire                    wbm4_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm4_sel_i,    // SEL_I() select input
+    input  wire                    wbm4_stb_i,    // STB_I strobe input
+    output wire                    wbm4_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm4_err_o,    // ERR_O error output
+    output wire                    wbm4_rty_o,    // RTY_O retry output
+    input  wire                    wbm4_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone slave output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs_adr_o,     // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs_dat_i,     // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs_dat_o,     // DAT_O() data out
+    output wire                    wbs_we_o,      // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs_sel_o,     // SEL_O() select output
+    output wire                    wbs_stb_o,     // STB_O strobe output
+    input  wire                    wbs_ack_i,     // ACK_I acknowledge input
+    input  wire                    wbs_err_i,     // ERR_I error input
+    input  wire                    wbs_rty_i,     // RTY_I retry input
+    output wire                    wbs_cyc_o      // CYC_O cycle output
+);
+
+wire [4:0] request;
+wire [4:0] grant;
+
+assign request[0] = wbm0_cyc_i;
+assign request[1] = wbm1_cyc_i;
+assign request[2] = wbm2_cyc_i;
+assign request[3] = wbm3_cyc_i;
+assign request[4] = wbm4_cyc_i;
+
+wire wbm0_sel = grant[0] & grant_valid;
+wire wbm1_sel = grant[1] & grant_valid;
+wire wbm2_sel = grant[2] & grant_valid;
+wire wbm3_sel = grant[3] & grant_valid;
+wire wbm4_sel = grant[4] & grant_valid;
+
+// master 0
+assign wbm0_dat_o = wbs_dat_i;
+assign wbm0_ack_o = wbs_ack_i & wbm0_sel;
+assign wbm0_err_o = wbs_err_i & wbm0_sel;
+assign wbm0_rty_o = wbs_rty_i & wbm0_sel;
+
+// master 1
+assign wbm1_dat_o = wbs_dat_i;
+assign wbm1_ack_o = wbs_ack_i & wbm1_sel;
+assign wbm1_err_o = wbs_err_i & wbm1_sel;
+assign wbm1_rty_o = wbs_rty_i & wbm1_sel;
+
+// master 2
+assign wbm2_dat_o = wbs_dat_i;
+assign wbm2_ack_o = wbs_ack_i & wbm2_sel;
+assign wbm2_err_o = wbs_err_i & wbm2_sel;
+assign wbm2_rty_o = wbs_rty_i & wbm2_sel;
+
+// master 3
+assign wbm3_dat_o = wbs_dat_i;
+assign wbm3_ack_o = wbs_ack_i & wbm3_sel;
+assign wbm3_err_o = wbs_err_i & wbm3_sel;
+assign wbm3_rty_o = wbs_rty_i & wbm3_sel;
+
+// master 4
+assign wbm4_dat_o = wbs_dat_i;
+assign wbm4_ack_o = wbs_ack_i & wbm4_sel;
+assign wbm4_err_o = wbs_err_i & wbm4_sel;
+assign wbm4_rty_o = wbs_rty_i & wbm4_sel;
+
+// slave
+assign wbs_adr_o = wbm0_sel ? wbm0_adr_i :
+                   wbm1_sel ? wbm1_adr_i :
+                   wbm2_sel ? wbm2_adr_i :
+                   wbm3_sel ? wbm3_adr_i :
+                   wbm4_sel ? wbm4_adr_i :
+                   {ADDR_WIDTH{1'b0}};
+
+assign wbs_dat_o = wbm0_sel ? wbm0_dat_i :
+                   wbm1_sel ? wbm1_dat_i :
+                   wbm2_sel ? wbm2_dat_i :
+                   wbm3_sel ? wbm3_dat_i :
+                   wbm4_sel ? wbm4_dat_i :
+                   {DATA_WIDTH{1'b0}};
+
+assign wbs_we_o = wbm0_sel ? wbm0_we_i :
+                  wbm1_sel ? wbm1_we_i :
+                  wbm2_sel ? wbm2_we_i :
+                  wbm3_sel ? wbm3_we_i :
+                  wbm4_sel ? wbm4_we_i :
+                  1'b0;
+
+assign wbs_sel_o = wbm0_sel ? wbm0_sel_i :
+                   wbm1_sel ? wbm1_sel_i :
+                   wbm2_sel ? wbm2_sel_i :
+                   wbm3_sel ? wbm3_sel_i :
+                   wbm4_sel ? wbm4_sel_i :
+                   {SELECT_WIDTH{1'b0}};
+
+assign wbs_stb_o = wbm0_sel ? wbm0_stb_i :
+                   wbm1_sel ? wbm1_stb_i :
+                   wbm2_sel ? wbm2_stb_i :
+                   wbm3_sel ? wbm3_stb_i :
+                   wbm4_sel ? wbm4_stb_i :
+                   1'b0;
+
+assign wbs_cyc_o = wbm0_sel ? 1'b1 :
+                   wbm1_sel ? 1'b1 :
+                   wbm2_sel ? 1'b1 :
+                   wbm3_sel ? 1'b1 :
+                   wbm4_sel ? 1'b1 :
+                   1'b0;
+
+// arbiter instance
+arbiter #(
+    .PORTS(5),
+    .TYPE(ARB_TYPE),
+    .BLOCK("REQUEST"),
+    .LSB_PRIORITY(LSB_PRIORITY)
+)
+arb_inst (
+    .clk(clk),
+    .rst(rst),
+    .request(request),
+    .acknowledge(),
+    .grant(grant),
+    .grant_valid(grant_valid),
+    .grant_encoded()
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter_8.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter_8.v
new file mode 100644
index 0000000..0114a11
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_arbiter_8.v
@@ -0,0 +1,318 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1 ns / 1 ps
+
+/*
+ * Wishbone 8 port arbiter
+ */
+module wb_arbiter_8 #
+(
+    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8),      // width of word select bus (1, 2, 4, or 8)
+    parameter ARB_TYPE = "PRIORITY",              // arbitration type: "PRIORITY" or "ROUND_ROBIN"
+    parameter LSB_PRIORITY = "HIGH"               // LSB priority: "LOW", "HIGH"
+)
+(
+    input  wire                    clk,
+    input  wire                    rst,
+
+    /*
+     * Wishbone master 0 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm0_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm0_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm0_dat_o,    // DAT_O() data out
+    input  wire                    wbm0_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm0_sel_i,    // SEL_I() select input
+    input  wire                    wbm0_stb_i,    // STB_I strobe input
+    output wire                    wbm0_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm0_err_o,    // ERR_O error output
+    output wire                    wbm0_rty_o,    // RTY_O retry output
+    input  wire                    wbm0_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 1 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm1_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm1_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm1_dat_o,    // DAT_O() data out
+    input  wire                    wbm1_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm1_sel_i,    // SEL_I() select input
+    input  wire                    wbm1_stb_i,    // STB_I strobe input
+    output wire                    wbm1_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm1_err_o,    // ERR_O error output
+    output wire                    wbm1_rty_o,    // RTY_O retry output
+    input  wire                    wbm1_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 2 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm2_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm2_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm2_dat_o,    // DAT_O() data out
+    input  wire                    wbm2_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm2_sel_i,    // SEL_I() select input
+    input  wire                    wbm2_stb_i,    // STB_I strobe input
+    output wire                    wbm2_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm2_err_o,    // ERR_O error output
+    output wire                    wbm2_rty_o,    // RTY_O retry output
+    input  wire                    wbm2_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 3 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm3_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm3_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm3_dat_o,    // DAT_O() data out
+    input  wire                    wbm3_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm3_sel_i,    // SEL_I() select input
+    input  wire                    wbm3_stb_i,    // STB_I strobe input
+    output wire                    wbm3_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm3_err_o,    // ERR_O error output
+    output wire                    wbm3_rty_o,    // RTY_O retry output
+    input  wire                    wbm3_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 4 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm4_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm4_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm4_dat_o,    // DAT_O() data out
+    input  wire                    wbm4_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm4_sel_i,    // SEL_I() select input
+    input  wire                    wbm4_stb_i,    // STB_I strobe input
+    output wire                    wbm4_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm4_err_o,    // ERR_O error output
+    output wire                    wbm4_rty_o,    // RTY_O retry output
+    input  wire                    wbm4_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 5 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm5_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm5_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm5_dat_o,    // DAT_O() data out
+    input  wire                    wbm5_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm5_sel_i,    // SEL_I() select input
+    input  wire                    wbm5_stb_i,    // STB_I strobe input
+    output wire                    wbm5_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm5_err_o,    // ERR_O error output
+    output wire                    wbm5_rty_o,    // RTY_O retry output
+    input  wire                    wbm5_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 6 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm6_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm6_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm6_dat_o,    // DAT_O() data out
+    input  wire                    wbm6_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm6_sel_i,    // SEL_I() select input
+    input  wire                    wbm6_stb_i,    // STB_I strobe input
+    output wire                    wbm6_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm6_err_o,    // ERR_O error output
+    output wire                    wbm6_rty_o,    // RTY_O retry output
+    input  wire                    wbm6_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone master 7 input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm7_adr_i,    // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm7_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm7_dat_o,    // DAT_O() data out
+    input  wire                    wbm7_we_i,     // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm7_sel_i,    // SEL_I() select input
+    input  wire                    wbm7_stb_i,    // STB_I strobe input
+    output wire                    wbm7_ack_o,    // ACK_O acknowledge output
+    output wire                    wbm7_err_o,    // ERR_O error output
+    output wire                    wbm7_rty_o,    // RTY_O retry output
+    input  wire                    wbm7_cyc_i,    // CYC_I cycle input
+
+    /*
+     * Wishbone slave output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs_adr_o,     // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs_dat_i,     // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs_dat_o,     // DAT_O() data out
+    output wire                    wbs_we_o,      // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs_sel_o,     // SEL_O() select output
+    output wire                    wbs_stb_o,     // STB_O strobe output
+    input  wire                    wbs_ack_i,     // ACK_I acknowledge input
+    input  wire                    wbs_err_i,     // ERR_I error input
+    input  wire                    wbs_rty_i,     // RTY_I retry input
+    output wire                    wbs_cyc_o      // CYC_O cycle output
+);
+
+wire [7:0] request;
+wire [7:0] grant;
+
+assign request[0] = wbm0_cyc_i;
+assign request[1] = wbm1_cyc_i;
+assign request[2] = wbm2_cyc_i;
+assign request[3] = wbm3_cyc_i;
+assign request[4] = wbm4_cyc_i;
+assign request[5] = wbm5_cyc_i;
+assign request[6] = wbm6_cyc_i;
+assign request[7] = wbm7_cyc_i;
+
+wire wbm0_sel = grant[0] & grant_valid;
+wire wbm1_sel = grant[1] & grant_valid;
+wire wbm2_sel = grant[2] & grant_valid;
+wire wbm3_sel = grant[3] & grant_valid;
+wire wbm4_sel = grant[4] & grant_valid;
+wire wbm5_sel = grant[5] & grant_valid;
+wire wbm6_sel = grant[6] & grant_valid;
+wire wbm7_sel = grant[7] & grant_valid;
+
+// master 0
+assign wbm0_dat_o = wbs_dat_i;
+assign wbm0_ack_o = wbs_ack_i & wbm0_sel;
+assign wbm0_err_o = wbs_err_i & wbm0_sel;
+assign wbm0_rty_o = wbs_rty_i & wbm0_sel;
+
+// master 1
+assign wbm1_dat_o = wbs_dat_i;
+assign wbm1_ack_o = wbs_ack_i & wbm1_sel;
+assign wbm1_err_o = wbs_err_i & wbm1_sel;
+assign wbm1_rty_o = wbs_rty_i & wbm1_sel;
+
+// master 2
+assign wbm2_dat_o = wbs_dat_i;
+assign wbm2_ack_o = wbs_ack_i & wbm2_sel;
+assign wbm2_err_o = wbs_err_i & wbm2_sel;
+assign wbm2_rty_o = wbs_rty_i & wbm2_sel;
+
+// master 3
+assign wbm3_dat_o = wbs_dat_i;
+assign wbm3_ack_o = wbs_ack_i & wbm3_sel;
+assign wbm3_err_o = wbs_err_i & wbm3_sel;
+assign wbm3_rty_o = wbs_rty_i & wbm3_sel;
+
+// master 4
+assign wbm4_dat_o = wbs_dat_i;
+assign wbm4_ack_o = wbs_ack_i & wbm4_sel;
+assign wbm4_err_o = wbs_err_i & wbm4_sel;
+assign wbm4_rty_o = wbs_rty_i & wbm4_sel;
+
+// master 5
+assign wbm5_dat_o = wbs_dat_i;
+assign wbm5_ack_o = wbs_ack_i & wbm5_sel;
+assign wbm5_err_o = wbs_err_i & wbm5_sel;
+assign wbm5_rty_o = wbs_rty_i & wbm5_sel;
+
+// master 6
+assign wbm6_dat_o = wbs_dat_i;
+assign wbm6_ack_o = wbs_ack_i & wbm6_sel;
+assign wbm6_err_o = wbs_err_i & wbm6_sel;
+assign wbm6_rty_o = wbs_rty_i & wbm6_sel;
+
+// master 7
+assign wbm7_dat_o = wbs_dat_i;
+assign wbm7_ack_o = wbs_ack_i & wbm7_sel;
+assign wbm7_err_o = wbs_err_i & wbm7_sel;
+assign wbm7_rty_o = wbs_rty_i & wbm7_sel;
+
+// slave
+assign wbs_adr_o = wbm0_sel ? wbm0_adr_i :
+                   wbm1_sel ? wbm1_adr_i :
+                   wbm2_sel ? wbm2_adr_i :
+                   wbm3_sel ? wbm3_adr_i :
+                   wbm4_sel ? wbm4_adr_i :
+                   wbm5_sel ? wbm5_adr_i :
+                   wbm6_sel ? wbm6_adr_i :
+                   wbm7_sel ? wbm7_adr_i :
+                   {ADDR_WIDTH{1'b0}};
+
+assign wbs_dat_o = wbm0_sel ? wbm0_dat_i :
+                   wbm1_sel ? wbm1_dat_i :
+                   wbm2_sel ? wbm2_dat_i :
+                   wbm3_sel ? wbm3_dat_i :
+                   wbm4_sel ? wbm4_dat_i :
+                   wbm5_sel ? wbm5_dat_i :
+                   wbm6_sel ? wbm6_dat_i :
+                   wbm7_sel ? wbm7_dat_i :
+                   {DATA_WIDTH{1'b0}};
+
+assign wbs_we_o = wbm0_sel ? wbm0_we_i :
+                  wbm1_sel ? wbm1_we_i :
+                  wbm2_sel ? wbm2_we_i :
+                  wbm3_sel ? wbm3_we_i :
+                  wbm4_sel ? wbm4_we_i :
+                  wbm5_sel ? wbm5_we_i :
+                  wbm6_sel ? wbm6_we_i :
+                  wbm7_sel ? wbm7_we_i :
+                  1'b0;
+
+assign wbs_sel_o = wbm0_sel ? wbm0_sel_i :
+                   wbm1_sel ? wbm1_sel_i :
+                   wbm2_sel ? wbm2_sel_i :
+                   wbm3_sel ? wbm3_sel_i :
+                   wbm4_sel ? wbm4_sel_i :
+                   wbm5_sel ? wbm5_sel_i :
+                   wbm6_sel ? wbm6_sel_i :
+                   wbm7_sel ? wbm7_sel_i :
+                   {SELECT_WIDTH{1'b0}};
+
+assign wbs_stb_o = wbm0_sel ? wbm0_stb_i :
+                   wbm1_sel ? wbm1_stb_i :
+                   wbm2_sel ? wbm2_stb_i :
+                   wbm3_sel ? wbm3_stb_i :
+                   wbm4_sel ? wbm4_stb_i :
+                   wbm5_sel ? wbm5_stb_i :
+                   wbm6_sel ? wbm6_stb_i :
+                   wbm7_sel ? wbm7_stb_i :
+                   1'b0;
+
+assign wbs_cyc_o = wbm0_sel ? 1'b1 :
+                   wbm1_sel ? 1'b1 :
+                   wbm2_sel ? 1'b1 :
+                   wbm3_sel ? 1'b1 :
+                   wbm4_sel ? 1'b1 :
+                   wbm5_sel ? 1'b1 :
+                   wbm6_sel ? 1'b1 :
+                   wbm7_sel ? 1'b1 :
+                   1'b0;
+
+// arbiter instance
+arbiter #(
+    .PORTS(8),
+    .TYPE(ARB_TYPE),
+    .BLOCK("REQUEST"),
+    .LSB_PRIORITY(LSB_PRIORITY)
+)
+arb_inst (
+    .clk(clk),
+    .rst(rst),
+    .request(request),
+    .acknowledge(),
+    .grant(grant),
+    .grant_valid(grant_valid),
+    .grant_encoded()
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_async_reg.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_async_reg.v
new file mode 100644
index 0000000..1c37832
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_async_reg.v
@@ -0,0 +1,225 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Wishbone register
+ */
+module wb_async_reg #
+(
+    parameter DATA_WIDTH = 32,                  // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                  // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8)     // width of word select bus (1, 2, 4, or 8)
+)
+(
+    // master side
+    input  wire                    wbm_clk,
+    input  wire                    wbm_rst,
+    input  wire [ADDR_WIDTH-1:0]   wbm_adr_i,   // ADR_I() address
+    input  wire [DATA_WIDTH-1:0]   wbm_dat_i,   // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm_dat_o,   // DAT_O() data out
+    input  wire                    wbm_we_i,    // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm_sel_i,   // SEL_I() select input
+    input  wire                    wbm_stb_i,   // STB_I strobe input
+    output wire                    wbm_ack_o,   // ACK_O acknowledge output
+    output wire                    wbm_err_o,   // ERR_O error output
+    output wire                    wbm_rty_o,   // RTY_O retry output
+    input  wire                    wbm_cyc_i,   // CYC_I cycle input
+
+    // slave side
+    input  wire                    wbs_clk,
+    input  wire                    wbs_rst,
+    output wire [ADDR_WIDTH-1:0]   wbs_adr_o,   // ADR_O() address
+    input  wire [DATA_WIDTH-1:0]   wbs_dat_i,   // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs_dat_o,   // DAT_O() data out
+    output wire                    wbs_we_o,    // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs_sel_o,   // SEL_O() select output
+    output wire                    wbs_stb_o,   // STB_O strobe output
+    input  wire                    wbs_ack_i,   // ACK_I acknowledge input
+    input  wire                    wbs_err_i,   // ERR_I error input
+    input  wire                    wbs_rty_i,   // RTY_I retry input
+    output wire                    wbs_cyc_o    // CYC_O cycle output
+);
+
+reg [ADDR_WIDTH-1:0] wbm_adr_i_reg = 0;
+reg [DATA_WIDTH-1:0] wbm_dat_i_reg = 0;
+reg [DATA_WIDTH-1:0] wbm_dat_o_reg = 0;
+reg wbm_we_i_reg = 0;
+reg [SELECT_WIDTH-1:0] wbm_sel_i_reg = 0;
+reg wbm_stb_i_reg = 0;
+reg wbm_ack_o_reg = 0;
+reg wbm_err_o_reg = 0;
+reg wbm_rty_o_reg = 0;
+reg wbm_cyc_i_reg = 0;
+
+reg wbm_done_sync1 = 0;
+reg wbm_done_sync2 = 0;
+reg wbm_done_sync3 = 0;
+
+reg [ADDR_WIDTH-1:0] wbs_adr_o_reg = 0;
+reg [DATA_WIDTH-1:0] wbs_dat_i_reg = 0;
+reg [DATA_WIDTH-1:0] wbs_dat_o_reg = 0;
+reg wbs_we_o_reg = 0;
+reg [SELECT_WIDTH-1:0] wbs_sel_o_reg = 0;
+reg wbs_stb_o_reg = 0;
+reg wbs_ack_i_reg = 0;
+reg wbs_err_i_reg = 0;
+reg wbs_rty_i_reg = 0;
+reg wbs_cyc_o_reg = 0;
+
+reg wbs_cyc_o_sync1 = 0;
+reg wbs_cyc_o_sync2 = 0;
+reg wbs_cyc_o_sync3 = 0;
+
+reg wbs_stb_o_sync1 = 0;
+reg wbs_stb_o_sync2 = 0;
+reg wbs_stb_o_sync3 = 0;
+
+reg wbs_done_reg = 0;
+
+assign wbm_dat_o = wbm_dat_o_reg;
+assign wbm_ack_o = wbm_ack_o_reg;
+assign wbm_err_o = wbm_err_o_reg;
+assign wbm_rty_o = wbm_rty_o_reg;
+
+assign wbs_adr_o = wbs_adr_o_reg;
+assign wbs_dat_o = wbs_dat_o_reg;
+assign wbs_we_o = wbs_we_o_reg;
+assign wbs_sel_o = wbs_sel_o_reg;
+assign wbs_stb_o = wbs_stb_o_reg;
+assign wbs_cyc_o = wbs_cyc_o_reg;
+
+// master side logic
+always @(posedge wbm_clk) begin
+    if (wbm_rst) begin
+        wbm_adr_i_reg <= 0;
+        wbm_dat_i_reg <= 0;
+        wbm_dat_o_reg <= 0;
+        wbm_we_i_reg <= 0;
+        wbm_sel_i_reg <= 0;
+        wbm_stb_i_reg <= 0;
+        wbm_ack_o_reg <= 0;
+        wbm_err_o_reg <= 0;
+        wbm_rty_o_reg <= 0;
+        wbm_cyc_i_reg <= 0;
+    end else begin
+        if (wbm_cyc_i_reg & wbm_stb_i_reg) begin
+            // cycle - hold master
+            if (wbm_done_sync2 & ~wbm_done_sync3) begin
+                // end of cycle - store slave
+                wbm_dat_o_reg <= wbs_dat_i_reg;
+                wbm_ack_o_reg <= wbs_ack_i_reg;
+                wbm_err_o_reg <= wbs_err_i_reg;
+                wbm_rty_o_reg <= wbs_rty_i_reg;
+                wbm_we_i_reg <= 0;
+                wbm_stb_i_reg <= 0;
+            end
+        end else begin
+            // idle - store master
+            wbm_adr_i_reg <= wbm_adr_i;
+            wbm_dat_i_reg <= wbm_dat_i;
+            wbm_dat_o_reg <= 0;
+            wbm_we_i_reg <= wbm_we_i & ~(wbm_ack_o | wbm_err_o | wbm_rty_o);
+            wbm_sel_i_reg <= wbm_sel_i;
+            wbm_stb_i_reg <= wbm_stb_i & ~(wbm_ack_o | wbm_err_o | wbm_rty_o);
+            wbm_ack_o_reg <= 0;
+            wbm_err_o_reg <= 0;
+            wbm_rty_o_reg <= 0;
+            wbm_cyc_i_reg <= wbm_cyc_i;
+        end
+    end
+
+    // synchronize signals
+    wbm_done_sync1 <= wbs_done_reg;
+    wbm_done_sync2 <= wbm_done_sync1;
+    wbm_done_sync3 <= wbm_done_sync2;
+end
+
+// slave side logic
+always @(posedge wbs_clk) begin
+    if (wbs_rst) begin
+        wbs_adr_o_reg <= 0;
+        wbs_dat_i_reg <= 0;
+        wbs_dat_o_reg <= 0;
+        wbs_we_o_reg <= 0;
+        wbs_sel_o_reg <= 0;
+        wbs_stb_o_reg <= 0;
+        wbs_ack_i_reg <= 0;
+        wbs_err_i_reg <= 0;
+        wbs_rty_i_reg <= 0;
+        wbs_cyc_o_reg <= 0;
+        wbs_done_reg <= 0;
+    end else begin
+        if (wbs_ack_i | wbs_err_i | wbs_rty_i) begin
+            // end of cycle - store slave
+            wbs_dat_i_reg <= wbs_dat_i;
+            wbs_ack_i_reg <= wbs_ack_i;
+            wbs_err_i_reg <= wbs_err_i;
+            wbs_rty_i_reg <= wbs_rty_i;
+            wbs_we_o_reg <= 0;
+            wbs_stb_o_reg <= 0;
+            wbs_done_reg <= 1;
+        end else if (wbs_stb_o_sync2 & ~wbs_stb_o_sync3) begin
+            // beginning of cycle - store master 
+            wbs_adr_o_reg <= wbm_adr_i_reg;
+            wbs_dat_i_reg <= 0;
+            wbs_dat_o_reg <= wbm_dat_i_reg;
+            wbs_we_o_reg <= wbm_we_i_reg;
+            wbs_sel_o_reg <= wbm_sel_i_reg;
+            wbs_stb_o_reg <= wbm_stb_i_reg;
+            wbs_ack_i_reg <= 0;
+            wbs_err_i_reg <= 0;
+            wbs_rty_i_reg <= 0;
+            wbs_cyc_o_reg <= wbm_cyc_i_reg;
+            wbs_done_reg <= 0;
+        end else if (~wbs_cyc_o_sync2 & wbs_cyc_o_sync3) begin
+            // cyc deassert
+            wbs_adr_o_reg <= 0;
+            wbs_dat_i_reg <= 0;
+            wbs_dat_o_reg <= 0;
+            wbs_we_o_reg <= 0;
+            wbs_sel_o_reg <= 0;
+            wbs_stb_o_reg <= 0;
+            wbs_ack_i_reg <= 0;
+            wbs_err_i_reg <= 0;
+            wbs_rty_i_reg <= 0;
+            wbs_cyc_o_reg <= 0;
+            wbs_done_reg <= 0;
+        end
+    end
+
+    // synchronize signals
+    wbs_cyc_o_sync1 <= wbm_cyc_i_reg;
+    wbs_cyc_o_sync2 <= wbs_cyc_o_sync1;
+    wbs_cyc_o_sync3 <= wbs_cyc_o_sync2;
+
+    wbs_stb_o_sync1 <= wbm_stb_i_reg;
+    wbs_stb_o_sync2 <= wbs_stb_o_sync1;
+    wbs_stb_o_sync3 <= wbs_stb_o_sync2;
+end
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_dp_ram.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_dp_ram.v
new file mode 100644
index 0000000..370e973
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_dp_ram.v
@@ -0,0 +1,127 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Wishbone dual port RAM
+ */
+module wb_dp_ram #
+(
+    parameter DATA_WIDTH = 32,                // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 16,                // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8)   // width of word select bus (1, 2, 4, or 8)
+)
+(
+    // port A
+    input  wire                    a_clk,
+    input  wire [ADDR_WIDTH-1:0]   a_adr_i,   // ADR_I() address
+    input  wire [DATA_WIDTH-1:0]   a_dat_i,   // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   a_dat_o,   // DAT_O() data out
+    input  wire                    a_we_i,    // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] a_sel_i,   // SEL_I() select input
+    input  wire                    a_stb_i,   // STB_I strobe input
+    output wire                    a_ack_o,   // ACK_O acknowledge output
+    input  wire                    a_cyc_i,   // CYC_I cycle input
+
+    // port B
+    input  wire                    b_clk,
+    input  wire [ADDR_WIDTH-1:0]   b_adr_i,   // ADR_I() address
+    input  wire [DATA_WIDTH-1:0]   b_dat_i,   // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   b_dat_o,   // DAT_O() data out
+    input  wire                    b_we_i,    // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] b_sel_i,   // SEL_I() select input
+    input  wire                    b_stb_i,   // STB_I strobe input
+    output wire                    b_ack_o,   // ACK_O acknowledge output
+    input  wire                    b_cyc_i    // CYC_I cycle input
+);
+
+// for interfaces that are more than one word wide, disable address lines
+parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(SELECT_WIDTH);
+// width of data port in words (1, 2, 4, or 8)
+parameter WORD_WIDTH = SELECT_WIDTH;
+// size of words (8, 16, 32, or 64 bits)
+parameter WORD_SIZE = DATA_WIDTH/WORD_WIDTH;
+
+reg [DATA_WIDTH-1:0] a_dat_o_reg = {DATA_WIDTH{1'b0}};
+reg a_ack_o_reg = 1'b0;
+
+reg [DATA_WIDTH-1:0] b_dat_o_reg = {DATA_WIDTH{1'b0}};
+reg b_ack_o_reg = 1'b0;
+
+// (* RAM_STYLE="BLOCK" *)
+reg [DATA_WIDTH-1:0] mem[(2**VALID_ADDR_WIDTH)-1:0];
+
+wire [VALID_ADDR_WIDTH-1:0] a_adr_i_valid = a_adr_i >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
+wire [VALID_ADDR_WIDTH-1:0] b_adr_i_valid = b_adr_i >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
+
+assign a_dat_o = a_dat_o_reg;
+assign a_ack_o = a_ack_o_reg;
+
+assign b_dat_o = b_dat_o_reg;
+assign b_ack_o = b_ack_o_reg;
+
+integer i, j;
+
+initial begin
+    // two nested loops for smaller number of iterations per loop
+    // workaround for synthesizer complaints about large loop counts
+    for (i = 0; i < 2**ADDR_WIDTH; i = i + 2**(ADDR_WIDTH/2)) begin
+        for (j = i; j < i + 2**(ADDR_WIDTH/2); j = j + 1) begin
+            mem[j] = 0;
+        end
+    end
+end
+
+// port A
+always @(posedge a_clk) begin
+    a_ack_o_reg <= 1'b0;
+    for (i = 0; i < WORD_WIDTH; i = i + 1) begin
+        if (a_cyc_i & a_stb_i & ~a_ack_o) begin
+            if (a_we_i & a_sel_i[i]) begin
+                mem[a_adr_i_valid][WORD_SIZE*i +: WORD_SIZE] <= a_dat_i[WORD_SIZE*i +: WORD_SIZE];
+            end
+            a_dat_o_reg[WORD_SIZE*i +: WORD_SIZE] <= mem[a_adr_i_valid][WORD_SIZE*i +: WORD_SIZE];
+            a_ack_o_reg <= 1'b1;
+        end
+    end
+end
+
+// port B
+always @(posedge b_clk) begin
+    b_ack_o_reg <= 1'b0;
+    for (i = 0; i < WORD_WIDTH; i = i + 1) begin
+        if (b_cyc_i & b_stb_i & ~b_ack_o) begin
+            if (b_we_i & b_sel_i[i]) begin
+                mem[b_adr_i_valid][WORD_SIZE*i +: WORD_SIZE] <= b_dat_i[WORD_SIZE*i +: WORD_SIZE];
+            end
+            b_dat_o_reg[WORD_SIZE*i +: WORD_SIZE] <= mem[b_adr_i_valid][WORD_SIZE*i +: WORD_SIZE];
+            b_ack_o_reg <= 1'b1;
+        end
+    end
+end
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux.py b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux.py
new file mode 100755
index 0000000..ec458f9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux.py
@@ -0,0 +1,166 @@
+#!/usr/bin/env python
+"""
+Generates a Wishbone multiplexer with the specified number of ports
+"""
+
+from __future__ import print_function
+
+import argparse
+import math
+from jinja2 import Template
+
+def main():
+    parser = argparse.ArgumentParser(description=__doc__.strip())
+    parser.add_argument('-p', '--ports',  type=int, default=2, help="number of ports")
+    parser.add_argument('-n', '--name',   type=str, help="module name")
+    parser.add_argument('-o', '--output', type=str, help="output file name")
+
+    args = parser.parse_args()
+
+    try:
+        generate(**args.__dict__)
+    except IOError as ex:
+        print(ex)
+        exit(1)
+
+def generate(ports=2, name=None, output=None):
+    if name is None:
+        name = "wb_mux_{0}".format(ports)
+
+    if output is None:
+        output = name + ".v"
+
+    print("Opening file '{0}'...".format(output))
+
+    output_file = open(output, 'w')
+
+    print("Generating {0} port Wishbone mux {1}...".format(ports, name))
+
+    select_width = int(math.ceil(math.log(ports, 2)))
+
+    t = Template(u"""/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1 ns / 1 ps
+
+/*
+ * Wishbone {{n}} port multiplexer
+ */
+module {{name}} #
+(
+    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8)       // width of word select bus (1, 2, 4, or 8)
+)
+(
+    input  wire                    clk,
+    input  wire                    rst,
+
+    /*
+     * Wishbone master input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm_adr_i,     // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm_dat_i,     // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm_dat_o,     // DAT_O() data out
+    input  wire                    wbm_we_i,      // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm_sel_i,     // SEL_I() select input
+    input  wire                    wbm_stb_i,     // STB_I strobe input
+    output wire                    wbm_ack_o,     // ACK_O acknowledge output
+    output wire                    wbm_err_o,     // ERR_O error output
+    output wire                    wbm_rty_o,     // RTY_O retry output
+    input  wire                    wbm_cyc_i,     // CYC_I cycle input
+    {%- for p in ports %}
+
+    /*
+     * Wishbone slave {{p}} output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs{{p}}_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs{{p}}_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs{{p}}_dat_o,    // DAT_O() data out
+    output wire                    wbs{{p}}_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs{{p}}_sel_o,    // SEL_O() select output
+    output wire                    wbs{{p}}_stb_o,    // STB_O strobe output
+    input  wire                    wbs{{p}}_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs{{p}}_err_i,    // ERR_I error input
+    input  wire                    wbs{{p}}_rty_i,    // RTY_I retry input
+    output wire                    wbs{{p}}_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave {{p}} address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs{{p}}_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs{{p}}_addr_msk{% if not loop.last %},{% else %} {% endif %} // Slave address prefix mask
+    {%- endfor %}
+);
+{% for p in ports %}
+wire wbs{{p}}_match = ~|((wbm_adr_i ^ wbs{{p}}_addr) & wbs{{p}}_addr_msk);
+{%- endfor %}
+{% for p in ports %}
+wire wbs{{p}}_sel = wbs{{p}}_match{% if p > 0 %} & ~({% for q in range(p) %}wbs{{q}}_match{% if not loop.last %} | {% endif %}{% endfor %}){% endif %};
+{%- endfor %}
+
+wire master_cycle = wbm_cyc_i & wbm_stb_i;
+
+wire select_error = ~({% for p in ports %}wbs{{p}}_sel{% if not loop.last %} | {% endif %}{% endfor %}) & master_cycle;
+
+// master
+assign wbm_dat_o = {% for p in ports %}wbs{{p}}_sel ? wbs{{p}}_dat_i :
+                   {% endfor %}{DATA_WIDTH{1'b0}};
+
+assign wbm_ack_o = {% for p in ports %}wbs{{p}}_ack_i{% if not loop.last %} |
+                   {% endif %}{% endfor %};
+
+assign wbm_err_o = {% for p in ports %}wbs{{p}}_err_i |
+                   {% endfor %}select_error;
+
+assign wbm_rty_o = {% for p in ports %}wbs{{p}}_rty_i{% if not loop.last %} |
+                   {% endif %}{% endfor %};
+{% for p in ports %}
+// slave {{p}}
+assign wbs{{p}}_adr_o = wbm_adr_i;
+assign wbs{{p}}_dat_o = wbm_dat_i;
+assign wbs{{p}}_we_o = wbm_we_i & wbs{{p}}_sel;
+assign wbs{{p}}_sel_o = wbm_sel_i;
+assign wbs{{p}}_stb_o = wbm_stb_i & wbs{{p}}_sel;
+assign wbs{{p}}_cyc_o = wbm_cyc_i & wbs{{p}}_sel;
+{% endfor %}
+
+endmodule
+
+""")
+    
+    output_file.write(t.render(
+        n=ports,
+        w=select_width,
+        name=name,
+        ports=range(ports)
+    ))
+    
+    print("Done")
+
+if __name__ == "__main__":
+    main()
+
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_2.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_2.v
new file mode 100644
index 0000000..4342ba4
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_2.v
@@ -0,0 +1,139 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1 ns / 1 ps
+
+/*
+ * Wishbone 2 port multiplexer
+ */
+module wb_mux_2 #
+(
+    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8)       // width of word select bus (1, 2, 4, or 8)
+)
+(
+    input  wire                    clk,
+    input  wire                    rst,
+
+    /*
+     * Wishbone master input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm_adr_i,     // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm_dat_i,     // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm_dat_o,     // DAT_O() data out
+    input  wire                    wbm_we_i,      // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm_sel_i,     // SEL_I() select input
+    input  wire                    wbm_stb_i,     // STB_I strobe input
+    output wire                    wbm_ack_o,     // ACK_O acknowledge output
+    output wire                    wbm_err_o,     // ERR_O error output
+    output wire                    wbm_rty_o,     // RTY_O retry output
+    input  wire                    wbm_cyc_i,     // CYC_I cycle input
+
+    /*
+     * Wishbone slave 0 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs0_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs0_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs0_dat_o,    // DAT_O() data out
+    output wire                    wbs0_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs0_sel_o,    // SEL_O() select output
+    output wire                    wbs0_stb_o,    // STB_O strobe output
+    input  wire                    wbs0_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs0_err_i,    // ERR_I error input
+    input  wire                    wbs0_rty_i,    // RTY_I retry input
+    output wire                    wbs0_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 0 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs0_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs0_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 1 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs1_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs1_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs1_dat_o,    // DAT_O() data out
+    output wire                    wbs1_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs1_sel_o,    // SEL_O() select output
+    output wire                    wbs1_stb_o,    // STB_O strobe output
+    input  wire                    wbs1_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs1_err_i,    // ERR_I error input
+    input  wire                    wbs1_rty_i,    // RTY_I retry input
+    output wire                    wbs1_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 1 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs1_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs1_addr_msk  // Slave address prefix mask
+);
+
+wire wbs0_match = ~|((wbm_adr_i ^ wbs0_addr) & wbs0_addr_msk);
+wire wbs1_match = ~|((wbm_adr_i ^ wbs1_addr) & wbs1_addr_msk);
+
+wire wbs0_sel = wbs0_match;
+wire wbs1_sel = wbs1_match & ~(wbs0_match);
+
+wire master_cycle = wbm_cyc_i & wbm_stb_i;
+
+wire select_error = ~(wbs0_sel | wbs1_sel) & master_cycle;
+
+// master
+assign wbm_dat_o = wbs0_sel ? wbs0_dat_i :
+                   wbs1_sel ? wbs1_dat_i :
+                   {DATA_WIDTH{1'b0}};
+
+assign wbm_ack_o = wbs0_ack_i |
+                   wbs1_ack_i;
+
+assign wbm_err_o = wbs0_err_i |
+                   wbs1_err_i |
+                   select_error;
+
+assign wbm_rty_o = wbs0_rty_i |
+                   wbs1_rty_i;
+
+// slave 0
+assign wbs0_adr_o = wbm_adr_i;
+assign wbs0_dat_o = wbm_dat_i;
+assign wbs0_we_o = wbm_we_i & wbs0_sel;
+assign wbs0_sel_o = wbm_sel_i;
+assign wbs0_stb_o = wbm_stb_i & wbs0_sel;
+assign wbs0_cyc_o = wbm_cyc_i & wbs0_sel;
+
+// slave 1
+assign wbs1_adr_o = wbm_adr_i;
+assign wbs1_dat_o = wbm_dat_i;
+assign wbs1_we_o = wbm_we_i & wbs1_sel;
+assign wbs1_sel_o = wbm_sel_i;
+assign wbs1_stb_o = wbm_stb_i & wbs1_sel;
+assign wbs1_cyc_o = wbm_cyc_i & wbs1_sel;
+
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_3.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_3.v
new file mode 100644
index 0000000..3afeb31
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_3.v
@@ -0,0 +1,173 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1 ns / 1 ps
+
+/*
+ * Wishbone 3 port multiplexer
+ */
+module wb_mux_3 #
+(
+    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8)       // width of word select bus (1, 2, 4, or 8)
+)
+(
+    input  wire                    clk,
+    input  wire                    rst,
+
+    /*
+     * Wishbone master input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm_adr_i,     // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm_dat_i,     // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm_dat_o,     // DAT_O() data out
+    input  wire                    wbm_we_i,      // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm_sel_i,     // SEL_I() select input
+    input  wire                    wbm_stb_i,     // STB_I strobe input
+    output wire                    wbm_ack_o,     // ACK_O acknowledge output
+    output wire                    wbm_err_o,     // ERR_O error output
+    output wire                    wbm_rty_o,     // RTY_O retry output
+    input  wire                    wbm_cyc_i,     // CYC_I cycle input
+
+    /*
+     * Wishbone slave 0 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs0_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs0_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs0_dat_o,    // DAT_O() data out
+    output wire                    wbs0_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs0_sel_o,    // SEL_O() select output
+    output wire                    wbs0_stb_o,    // STB_O strobe output
+    input  wire                    wbs0_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs0_err_i,    // ERR_I error input
+    input  wire                    wbs0_rty_i,    // RTY_I retry input
+    output wire                    wbs0_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 0 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs0_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs0_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 1 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs1_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs1_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs1_dat_o,    // DAT_O() data out
+    output wire                    wbs1_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs1_sel_o,    // SEL_O() select output
+    output wire                    wbs1_stb_o,    // STB_O strobe output
+    input  wire                    wbs1_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs1_err_i,    // ERR_I error input
+    input  wire                    wbs1_rty_i,    // RTY_I retry input
+    output wire                    wbs1_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 1 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs1_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs1_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 2 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs2_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs2_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs2_dat_o,    // DAT_O() data out
+    output wire                    wbs2_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs2_sel_o,    // SEL_O() select output
+    output wire                    wbs2_stb_o,    // STB_O strobe output
+    input  wire                    wbs2_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs2_err_i,    // ERR_I error input
+    input  wire                    wbs2_rty_i,    // RTY_I retry input
+    output wire                    wbs2_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 2 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs2_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs2_addr_msk  // Slave address prefix mask
+);
+
+wire wbs0_match = ~|((wbm_adr_i ^ wbs0_addr) & wbs0_addr_msk);
+wire wbs1_match = ~|((wbm_adr_i ^ wbs1_addr) & wbs1_addr_msk);
+wire wbs2_match = ~|((wbm_adr_i ^ wbs2_addr) & wbs2_addr_msk);
+
+wire wbs0_sel = wbs0_match;
+wire wbs1_sel = wbs1_match & ~(wbs0_match);
+wire wbs2_sel = wbs2_match & ~(wbs0_match | wbs1_match);
+
+wire master_cycle = wbm_cyc_i & wbm_stb_i;
+
+wire select_error = ~(wbs0_sel | wbs1_sel | wbs2_sel) & master_cycle;
+
+// master
+assign wbm_dat_o = wbs0_sel ? wbs0_dat_i :
+                   wbs1_sel ? wbs1_dat_i :
+                   wbs2_sel ? wbs2_dat_i :
+                   {DATA_WIDTH{1'b0}};
+
+assign wbm_ack_o = wbs0_ack_i |
+                   wbs1_ack_i |
+                   wbs2_ack_i;
+
+assign wbm_err_o = wbs0_err_i |
+                   wbs1_err_i |
+                   wbs2_err_i |
+                   select_error;
+
+assign wbm_rty_o = wbs0_rty_i |
+                   wbs1_rty_i |
+                   wbs2_rty_i;
+
+// slave 0
+assign wbs0_adr_o = wbm_adr_i;
+assign wbs0_dat_o = wbm_dat_i;
+assign wbs0_we_o = wbm_we_i & wbs0_sel;
+assign wbs0_sel_o = wbm_sel_i;
+assign wbs0_stb_o = wbm_stb_i & wbs0_sel;
+assign wbs0_cyc_o = wbm_cyc_i & wbs0_sel;
+
+// slave 1
+assign wbs1_adr_o = wbm_adr_i;
+assign wbs1_dat_o = wbm_dat_i;
+assign wbs1_we_o = wbm_we_i & wbs1_sel;
+assign wbs1_sel_o = wbm_sel_i;
+assign wbs1_stb_o = wbm_stb_i & wbs1_sel;
+assign wbs1_cyc_o = wbm_cyc_i & wbs1_sel;
+
+// slave 2
+assign wbs2_adr_o = wbm_adr_i;
+assign wbs2_dat_o = wbm_dat_i;
+assign wbs2_we_o = wbm_we_i & wbs2_sel;
+assign wbs2_sel_o = wbm_sel_i;
+assign wbs2_stb_o = wbm_stb_i & wbs2_sel;
+assign wbs2_cyc_o = wbm_cyc_i & wbs2_sel;
+
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_4.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_4.v
new file mode 100644
index 0000000..38b040b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_4.v
@@ -0,0 +1,207 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1 ns / 1 ps
+
+/*
+ * Wishbone 4 port multiplexer
+ */
+module wb_mux_4 #
+(
+    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8)       // width of word select bus (1, 2, 4, or 8)
+)
+(
+    input  wire                    clk,
+    input  wire                    rst,
+
+    /*
+     * Wishbone master input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm_adr_i,     // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm_dat_i,     // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm_dat_o,     // DAT_O() data out
+    input  wire                    wbm_we_i,      // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm_sel_i,     // SEL_I() select input
+    input  wire                    wbm_stb_i,     // STB_I strobe input
+    output wire                    wbm_ack_o,     // ACK_O acknowledge output
+    output wire                    wbm_err_o,     // ERR_O error output
+    output wire                    wbm_rty_o,     // RTY_O retry output
+    input  wire                    wbm_cyc_i,     // CYC_I cycle input
+
+    /*
+     * Wishbone slave 0 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs0_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs0_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs0_dat_o,    // DAT_O() data out
+    output wire                    wbs0_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs0_sel_o,    // SEL_O() select output
+    output wire                    wbs0_stb_o,    // STB_O strobe output
+    input  wire                    wbs0_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs0_err_i,    // ERR_I error input
+    input  wire                    wbs0_rty_i,    // RTY_I retry input
+    output wire                    wbs0_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 0 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs0_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs0_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 1 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs1_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs1_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs1_dat_o,    // DAT_O() data out
+    output wire                    wbs1_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs1_sel_o,    // SEL_O() select output
+    output wire                    wbs1_stb_o,    // STB_O strobe output
+    input  wire                    wbs1_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs1_err_i,    // ERR_I error input
+    input  wire                    wbs1_rty_i,    // RTY_I retry input
+    output wire                    wbs1_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 1 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs1_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs1_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 2 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs2_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs2_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs2_dat_o,    // DAT_O() data out
+    output wire                    wbs2_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs2_sel_o,    // SEL_O() select output
+    output wire                    wbs2_stb_o,    // STB_O strobe output
+    input  wire                    wbs2_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs2_err_i,    // ERR_I error input
+    input  wire                    wbs2_rty_i,    // RTY_I retry input
+    output wire                    wbs2_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 2 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs2_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs2_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 3 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs3_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs3_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs3_dat_o,    // DAT_O() data out
+    output wire                    wbs3_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs3_sel_o,    // SEL_O() select output
+    output wire                    wbs3_stb_o,    // STB_O strobe output
+    input  wire                    wbs3_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs3_err_i,    // ERR_I error input
+    input  wire                    wbs3_rty_i,    // RTY_I retry input
+    output wire                    wbs3_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 3 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs3_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs3_addr_msk  // Slave address prefix mask
+);
+
+wire wbs0_match = ~|((wbm_adr_i ^ wbs0_addr) & wbs0_addr_msk);
+wire wbs1_match = ~|((wbm_adr_i ^ wbs1_addr) & wbs1_addr_msk);
+wire wbs2_match = ~|((wbm_adr_i ^ wbs2_addr) & wbs2_addr_msk);
+wire wbs3_match = ~|((wbm_adr_i ^ wbs3_addr) & wbs3_addr_msk);
+
+wire wbs0_sel = wbs0_match;
+wire wbs1_sel = wbs1_match & ~(wbs0_match);
+wire wbs2_sel = wbs2_match & ~(wbs0_match | wbs1_match);
+wire wbs3_sel = wbs3_match & ~(wbs0_match | wbs1_match | wbs2_match);
+
+wire master_cycle = wbm_cyc_i & wbm_stb_i;
+
+wire select_error = ~(wbs0_sel | wbs1_sel | wbs2_sel | wbs3_sel) & master_cycle;
+
+// master
+assign wbm_dat_o = wbs0_sel ? wbs0_dat_i :
+                   wbs1_sel ? wbs1_dat_i :
+                   wbs2_sel ? wbs2_dat_i :
+                   wbs3_sel ? wbs3_dat_i :
+                   {DATA_WIDTH{1'b0}};
+
+assign wbm_ack_o = wbs0_ack_i |
+                   wbs1_ack_i |
+                   wbs2_ack_i |
+                   wbs3_ack_i;
+
+assign wbm_err_o = wbs0_err_i |
+                   wbs1_err_i |
+                   wbs2_err_i |
+                   wbs3_err_i |
+                   select_error;
+
+assign wbm_rty_o = wbs0_rty_i |
+                   wbs1_rty_i |
+                   wbs2_rty_i |
+                   wbs3_rty_i;
+
+// slave 0
+assign wbs0_adr_o = wbm_adr_i;
+assign wbs0_dat_o = wbm_dat_i;
+assign wbs0_we_o = wbm_we_i & wbs0_sel;
+assign wbs0_sel_o = wbm_sel_i;
+assign wbs0_stb_o = wbm_stb_i & wbs0_sel;
+assign wbs0_cyc_o = wbm_cyc_i & wbs0_sel;
+
+// slave 1
+assign wbs1_adr_o = wbm_adr_i;
+assign wbs1_dat_o = wbm_dat_i;
+assign wbs1_we_o = wbm_we_i & wbs1_sel;
+assign wbs1_sel_o = wbm_sel_i;
+assign wbs1_stb_o = wbm_stb_i & wbs1_sel;
+assign wbs1_cyc_o = wbm_cyc_i & wbs1_sel;
+
+// slave 2
+assign wbs2_adr_o = wbm_adr_i;
+assign wbs2_dat_o = wbm_dat_i;
+assign wbs2_we_o = wbm_we_i & wbs2_sel;
+assign wbs2_sel_o = wbm_sel_i;
+assign wbs2_stb_o = wbm_stb_i & wbs2_sel;
+assign wbs2_cyc_o = wbm_cyc_i & wbs2_sel;
+
+// slave 3
+assign wbs3_adr_o = wbm_adr_i;
+assign wbs3_dat_o = wbm_dat_i;
+assign wbs3_we_o = wbm_we_i & wbs3_sel;
+assign wbs3_sel_o = wbm_sel_i;
+assign wbs3_stb_o = wbm_stb_i & wbs3_sel;
+assign wbs3_cyc_o = wbm_cyc_i & wbs3_sel;
+
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_5.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_5.v
new file mode 100644
index 0000000..5c3d8c0
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_5.v
@@ -0,0 +1,241 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1 ns / 1 ps
+
+/*
+ * Wishbone 5 port multiplexer
+ */
+module wb_mux_5 #
+(
+    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8)       // width of word select bus (1, 2, 4, or 8)
+)
+(
+    input  wire                    clk,
+    input  wire                    rst,
+
+    /*
+     * Wishbone master input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm_adr_i,     // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm_dat_i,     // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm_dat_o,     // DAT_O() data out
+    input  wire                    wbm_we_i,      // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm_sel_i,     // SEL_I() select input
+    input  wire                    wbm_stb_i,     // STB_I strobe input
+    output wire                    wbm_ack_o,     // ACK_O acknowledge output
+    output wire                    wbm_err_o,     // ERR_O error output
+    output wire                    wbm_rty_o,     // RTY_O retry output
+    input  wire                    wbm_cyc_i,     // CYC_I cycle input
+
+    /*
+     * Wishbone slave 0 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs0_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs0_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs0_dat_o,    // DAT_O() data out
+    output wire                    wbs0_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs0_sel_o,    // SEL_O() select output
+    output wire                    wbs0_stb_o,    // STB_O strobe output
+    input  wire                    wbs0_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs0_err_i,    // ERR_I error input
+    input  wire                    wbs0_rty_i,    // RTY_I retry input
+    output wire                    wbs0_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 0 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs0_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs0_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 1 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs1_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs1_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs1_dat_o,    // DAT_O() data out
+    output wire                    wbs1_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs1_sel_o,    // SEL_O() select output
+    output wire                    wbs1_stb_o,    // STB_O strobe output
+    input  wire                    wbs1_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs1_err_i,    // ERR_I error input
+    input  wire                    wbs1_rty_i,    // RTY_I retry input
+    output wire                    wbs1_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 1 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs1_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs1_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 2 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs2_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs2_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs2_dat_o,    // DAT_O() data out
+    output wire                    wbs2_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs2_sel_o,    // SEL_O() select output
+    output wire                    wbs2_stb_o,    // STB_O strobe output
+    input  wire                    wbs2_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs2_err_i,    // ERR_I error input
+    input  wire                    wbs2_rty_i,    // RTY_I retry input
+    output wire                    wbs2_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 2 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs2_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs2_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 3 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs3_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs3_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs3_dat_o,    // DAT_O() data out
+    output wire                    wbs3_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs3_sel_o,    // SEL_O() select output
+    output wire                    wbs3_stb_o,    // STB_O strobe output
+    input  wire                    wbs3_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs3_err_i,    // ERR_I error input
+    input  wire                    wbs3_rty_i,    // RTY_I retry input
+    output wire                    wbs3_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 3 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs3_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs3_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 4 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs4_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs4_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs4_dat_o,    // DAT_O() data out
+    output wire                    wbs4_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs4_sel_o,    // SEL_O() select output
+    output wire                    wbs4_stb_o,    // STB_O strobe output
+    input  wire                    wbs4_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs4_err_i,    // ERR_I error input
+    input  wire                    wbs4_rty_i,    // RTY_I retry input
+    output wire                    wbs4_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 4 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs4_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs4_addr_msk  // Slave address prefix mask
+);
+
+wire wbs0_match = ~|((wbm_adr_i ^ wbs0_addr) & wbs0_addr_msk);
+wire wbs1_match = ~|((wbm_adr_i ^ wbs1_addr) & wbs1_addr_msk);
+wire wbs2_match = ~|((wbm_adr_i ^ wbs2_addr) & wbs2_addr_msk);
+wire wbs3_match = ~|((wbm_adr_i ^ wbs3_addr) & wbs3_addr_msk);
+wire wbs4_match = ~|((wbm_adr_i ^ wbs4_addr) & wbs4_addr_msk);
+
+wire wbs0_sel = wbs0_match;
+wire wbs1_sel = wbs1_match & ~(wbs0_match);
+wire wbs2_sel = wbs2_match & ~(wbs0_match | wbs1_match);
+wire wbs3_sel = wbs3_match & ~(wbs0_match | wbs1_match | wbs2_match);
+wire wbs4_sel = wbs4_match & ~(wbs0_match | wbs1_match | wbs2_match | wbs3_match);
+
+wire master_cycle = wbm_cyc_i & wbm_stb_i;
+
+wire select_error = ~(wbs0_sel | wbs1_sel | wbs2_sel | wbs3_sel | wbs4_sel) & master_cycle;
+
+// master
+assign wbm_dat_o = wbs0_sel ? wbs0_dat_i :
+                   wbs1_sel ? wbs1_dat_i :
+                   wbs2_sel ? wbs2_dat_i :
+                   wbs3_sel ? wbs3_dat_i :
+                   wbs4_sel ? wbs4_dat_i :
+                   {DATA_WIDTH{1'b0}};
+
+assign wbm_ack_o = wbs0_ack_i |
+                   wbs1_ack_i |
+                   wbs2_ack_i |
+                   wbs3_ack_i |
+                   wbs4_ack_i;
+
+assign wbm_err_o = wbs0_err_i |
+                   wbs1_err_i |
+                   wbs2_err_i |
+                   wbs3_err_i |
+                   wbs4_err_i |
+                   select_error;
+
+assign wbm_rty_o = wbs0_rty_i |
+                   wbs1_rty_i |
+                   wbs2_rty_i |
+                   wbs3_rty_i |
+                   wbs4_rty_i;
+
+// slave 0
+assign wbs0_adr_o = wbm_adr_i;
+assign wbs0_dat_o = wbm_dat_i;
+assign wbs0_we_o = wbm_we_i & wbs0_sel;
+assign wbs0_sel_o = wbm_sel_i;
+assign wbs0_stb_o = wbm_stb_i & wbs0_sel;
+assign wbs0_cyc_o = wbm_cyc_i & wbs0_sel;
+
+// slave 1
+assign wbs1_adr_o = wbm_adr_i;
+assign wbs1_dat_o = wbm_dat_i;
+assign wbs1_we_o = wbm_we_i & wbs1_sel;
+assign wbs1_sel_o = wbm_sel_i;
+assign wbs1_stb_o = wbm_stb_i & wbs1_sel;
+assign wbs1_cyc_o = wbm_cyc_i & wbs1_sel;
+
+// slave 2
+assign wbs2_adr_o = wbm_adr_i;
+assign wbs2_dat_o = wbm_dat_i;
+assign wbs2_we_o = wbm_we_i & wbs2_sel;
+assign wbs2_sel_o = wbm_sel_i;
+assign wbs2_stb_o = wbm_stb_i & wbs2_sel;
+assign wbs2_cyc_o = wbm_cyc_i & wbs2_sel;
+
+// slave 3
+assign wbs3_adr_o = wbm_adr_i;
+assign wbs3_dat_o = wbm_dat_i;
+assign wbs3_we_o = wbm_we_i & wbs3_sel;
+assign wbs3_sel_o = wbm_sel_i;
+assign wbs3_stb_o = wbm_stb_i & wbs3_sel;
+assign wbs3_cyc_o = wbm_cyc_i & wbs3_sel;
+
+// slave 4
+assign wbs4_adr_o = wbm_adr_i;
+assign wbs4_dat_o = wbm_dat_i;
+assign wbs4_we_o = wbm_we_i & wbs4_sel;
+assign wbs4_sel_o = wbm_sel_i;
+assign wbs4_stb_o = wbm_stb_i & wbs4_sel;
+assign wbs4_cyc_o = wbm_cyc_i & wbs4_sel;
+
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_6.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_6.v
new file mode 100644
index 0000000..36fc3b9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_6.v
@@ -0,0 +1,275 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1 ns / 1 ps
+
+/*
+ * Wishbone 6 port multiplexer
+ */
+module wb_mux_6 #
+(
+    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8)       // width of word select bus (1, 2, 4, or 8)
+)
+(
+    input  wire                    clk,
+    input  wire                    rst,
+
+    /*
+     * Wishbone master input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm_adr_i,     // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm_dat_i,     // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm_dat_o,     // DAT_O() data out
+    input  wire                    wbm_we_i,      // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm_sel_i,     // SEL_I() select input
+    input  wire                    wbm_stb_i,     // STB_I strobe input
+    output wire                    wbm_ack_o,     // ACK_O acknowledge output
+    output wire                    wbm_err_o,     // ERR_O error output
+    output wire                    wbm_rty_o,     // RTY_O retry output
+    input  wire                    wbm_cyc_i,     // CYC_I cycle input
+
+    /*
+     * Wishbone slave 0 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs0_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs0_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs0_dat_o,    // DAT_O() data out
+    output wire                    wbs0_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs0_sel_o,    // SEL_O() select output
+    output wire                    wbs0_stb_o,    // STB_O strobe output
+    input  wire                    wbs0_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs0_err_i,    // ERR_I error input
+    input  wire                    wbs0_rty_i,    // RTY_I retry input
+    output wire                    wbs0_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 0 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs0_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs0_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 1 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs1_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs1_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs1_dat_o,    // DAT_O() data out
+    output wire                    wbs1_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs1_sel_o,    // SEL_O() select output
+    output wire                    wbs1_stb_o,    // STB_O strobe output
+    input  wire                    wbs1_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs1_err_i,    // ERR_I error input
+    input  wire                    wbs1_rty_i,    // RTY_I retry input
+    output wire                    wbs1_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 1 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs1_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs1_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 2 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs2_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs2_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs2_dat_o,    // DAT_O() data out
+    output wire                    wbs2_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs2_sel_o,    // SEL_O() select output
+    output wire                    wbs2_stb_o,    // STB_O strobe output
+    input  wire                    wbs2_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs2_err_i,    // ERR_I error input
+    input  wire                    wbs2_rty_i,    // RTY_I retry input
+    output wire                    wbs2_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 2 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs2_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs2_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 3 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs3_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs3_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs3_dat_o,    // DAT_O() data out
+    output wire                    wbs3_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs3_sel_o,    // SEL_O() select output
+    output wire                    wbs3_stb_o,    // STB_O strobe output
+    input  wire                    wbs3_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs3_err_i,    // ERR_I error input
+    input  wire                    wbs3_rty_i,    // RTY_I retry input
+    output wire                    wbs3_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 3 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs3_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs3_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 4 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs4_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs4_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs4_dat_o,    // DAT_O() data out
+    output wire                    wbs4_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs4_sel_o,    // SEL_O() select output
+    output wire                    wbs4_stb_o,    // STB_O strobe output
+    input  wire                    wbs4_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs4_err_i,    // ERR_I error input
+    input  wire                    wbs4_rty_i,    // RTY_I retry input
+    output wire                    wbs4_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 4 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs4_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs4_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 5 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs5_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs5_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs5_dat_o,    // DAT_O() data out
+    output wire                    wbs5_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs5_sel_o,    // SEL_O() select output
+    output wire                    wbs5_stb_o,    // STB_O strobe output
+    input  wire                    wbs5_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs5_err_i,    // ERR_I error input
+    input  wire                    wbs5_rty_i,    // RTY_I retry input
+    output wire                    wbs5_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 5 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs5_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs5_addr_msk  // Slave address prefix mask
+);
+
+wire wbs0_match = ~|((wbm_adr_i ^ wbs0_addr) & wbs0_addr_msk);
+wire wbs1_match = ~|((wbm_adr_i ^ wbs1_addr) & wbs1_addr_msk);
+wire wbs2_match = ~|((wbm_adr_i ^ wbs2_addr) & wbs2_addr_msk);
+wire wbs3_match = ~|((wbm_adr_i ^ wbs3_addr) & wbs3_addr_msk);
+wire wbs4_match = ~|((wbm_adr_i ^ wbs4_addr) & wbs4_addr_msk);
+wire wbs5_match = ~|((wbm_adr_i ^ wbs5_addr) & wbs5_addr_msk);
+
+wire wbs0_sel = wbs0_match;
+wire wbs1_sel = wbs1_match & ~(wbs0_match);
+wire wbs2_sel = wbs2_match & ~(wbs0_match | wbs1_match);
+wire wbs3_sel = wbs3_match & ~(wbs0_match | wbs1_match | wbs2_match);
+wire wbs4_sel = wbs4_match & ~(wbs0_match | wbs1_match | wbs2_match | wbs3_match);
+wire wbs5_sel = wbs5_match & ~(wbs0_match | wbs1_match | wbs2_match | wbs3_match | wbs4_match);
+
+wire master_cycle = wbm_cyc_i & wbm_stb_i;
+
+wire select_error = ~(wbs0_sel | wbs1_sel | wbs2_sel | wbs3_sel | wbs4_sel | wbs5_sel) & master_cycle;
+
+// master
+assign wbm_dat_o = wbs0_sel ? wbs0_dat_i :
+                   wbs1_sel ? wbs1_dat_i :
+                   wbs2_sel ? wbs2_dat_i :
+                   wbs3_sel ? wbs3_dat_i :
+                   wbs4_sel ? wbs4_dat_i :
+                   wbs5_sel ? wbs5_dat_i :
+                   {DATA_WIDTH{1'b0}};
+
+assign wbm_ack_o = wbs0_ack_i |
+                   wbs1_ack_i |
+                   wbs2_ack_i |
+                   wbs3_ack_i |
+                   wbs4_ack_i |
+                   wbs5_ack_i;
+
+assign wbm_err_o = wbs0_err_i |
+                   wbs1_err_i |
+                   wbs2_err_i |
+                   wbs3_err_i |
+                   wbs4_err_i |
+                   wbs5_err_i |
+                   select_error;
+
+assign wbm_rty_o = wbs0_rty_i |
+                   wbs1_rty_i |
+                   wbs2_rty_i |
+                   wbs3_rty_i |
+                   wbs4_rty_i |
+                   wbs5_rty_i;
+
+// slave 0
+assign wbs0_adr_o = wbm_adr_i;
+assign wbs0_dat_o = wbm_dat_i;
+assign wbs0_we_o = wbm_we_i & wbs0_sel;
+assign wbs0_sel_o = wbm_sel_i;
+assign wbs0_stb_o = wbm_stb_i & wbs0_sel;
+assign wbs0_cyc_o = wbm_cyc_i & wbs0_sel;
+
+// slave 1
+assign wbs1_adr_o = wbm_adr_i;
+assign wbs1_dat_o = wbm_dat_i;
+assign wbs1_we_o = wbm_we_i & wbs1_sel;
+assign wbs1_sel_o = wbm_sel_i;
+assign wbs1_stb_o = wbm_stb_i & wbs1_sel;
+assign wbs1_cyc_o = wbm_cyc_i & wbs1_sel;
+
+// slave 2
+assign wbs2_adr_o = wbm_adr_i;
+assign wbs2_dat_o = wbm_dat_i;
+assign wbs2_we_o = wbm_we_i & wbs2_sel;
+assign wbs2_sel_o = wbm_sel_i;
+assign wbs2_stb_o = wbm_stb_i & wbs2_sel;
+assign wbs2_cyc_o = wbm_cyc_i & wbs2_sel;
+
+// slave 3
+assign wbs3_adr_o = wbm_adr_i;
+assign wbs3_dat_o = wbm_dat_i;
+assign wbs3_we_o = wbm_we_i & wbs3_sel;
+assign wbs3_sel_o = wbm_sel_i;
+assign wbs3_stb_o = wbm_stb_i & wbs3_sel;
+assign wbs3_cyc_o = wbm_cyc_i & wbs3_sel;
+
+// slave 4
+assign wbs4_adr_o = wbm_adr_i;
+assign wbs4_dat_o = wbm_dat_i;
+assign wbs4_we_o = wbm_we_i & wbs4_sel;
+assign wbs4_sel_o = wbm_sel_i;
+assign wbs4_stb_o = wbm_stb_i & wbs4_sel;
+assign wbs4_cyc_o = wbm_cyc_i & wbs4_sel;
+
+// slave 5
+assign wbs5_adr_o = wbm_adr_i;
+assign wbs5_dat_o = wbm_dat_i;
+assign wbs5_we_o = wbm_we_i & wbs5_sel;
+assign wbs5_sel_o = wbm_sel_i;
+assign wbs5_stb_o = wbm_stb_i & wbs5_sel;
+assign wbs5_cyc_o = wbm_cyc_i & wbs5_sel;
+
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_7.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_7.v
new file mode 100644
index 0000000..017ce9e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_7.v
@@ -0,0 +1,309 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1 ns / 1 ps
+
+/*
+ * Wishbone 7 port multiplexer
+ */
+module wb_mux_7 #
+(
+    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8)       // width of word select bus (1, 2, 4, or 8)
+)
+(
+    input  wire                    clk,
+    input  wire                    rst,
+
+    /*
+     * Wishbone master input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm_adr_i,     // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm_dat_i,     // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm_dat_o,     // DAT_O() data out
+    input  wire                    wbm_we_i,      // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm_sel_i,     // SEL_I() select input
+    input  wire                    wbm_stb_i,     // STB_I strobe input
+    output wire                    wbm_ack_o,     // ACK_O acknowledge output
+    output wire                    wbm_err_o,     // ERR_O error output
+    output wire                    wbm_rty_o,     // RTY_O retry output
+    input  wire                    wbm_cyc_i,     // CYC_I cycle input
+
+    /*
+     * Wishbone slave 0 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs0_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs0_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs0_dat_o,    // DAT_O() data out
+    output wire                    wbs0_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs0_sel_o,    // SEL_O() select output
+    output wire                    wbs0_stb_o,    // STB_O strobe output
+    input  wire                    wbs0_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs0_err_i,    // ERR_I error input
+    input  wire                    wbs0_rty_i,    // RTY_I retry input
+    output wire                    wbs0_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 0 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs0_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs0_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 1 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs1_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs1_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs1_dat_o,    // DAT_O() data out
+    output wire                    wbs1_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs1_sel_o,    // SEL_O() select output
+    output wire                    wbs1_stb_o,    // STB_O strobe output
+    input  wire                    wbs1_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs1_err_i,    // ERR_I error input
+    input  wire                    wbs1_rty_i,    // RTY_I retry input
+    output wire                    wbs1_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 1 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs1_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs1_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 2 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs2_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs2_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs2_dat_o,    // DAT_O() data out
+    output wire                    wbs2_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs2_sel_o,    // SEL_O() select output
+    output wire                    wbs2_stb_o,    // STB_O strobe output
+    input  wire                    wbs2_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs2_err_i,    // ERR_I error input
+    input  wire                    wbs2_rty_i,    // RTY_I retry input
+    output wire                    wbs2_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 2 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs2_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs2_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 3 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs3_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs3_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs3_dat_o,    // DAT_O() data out
+    output wire                    wbs3_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs3_sel_o,    // SEL_O() select output
+    output wire                    wbs3_stb_o,    // STB_O strobe output
+    input  wire                    wbs3_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs3_err_i,    // ERR_I error input
+    input  wire                    wbs3_rty_i,    // RTY_I retry input
+    output wire                    wbs3_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 3 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs3_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs3_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 4 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs4_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs4_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs4_dat_o,    // DAT_O() data out
+    output wire                    wbs4_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs4_sel_o,    // SEL_O() select output
+    output wire                    wbs4_stb_o,    // STB_O strobe output
+    input  wire                    wbs4_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs4_err_i,    // ERR_I error input
+    input  wire                    wbs4_rty_i,    // RTY_I retry input
+    output wire                    wbs4_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 4 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs4_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs4_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 5 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs5_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs5_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs5_dat_o,    // DAT_O() data out
+    output wire                    wbs5_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs5_sel_o,    // SEL_O() select output
+    output wire                    wbs5_stb_o,    // STB_O strobe output
+    input  wire                    wbs5_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs5_err_i,    // ERR_I error input
+    input  wire                    wbs5_rty_i,    // RTY_I retry input
+    output wire                    wbs5_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 5 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs5_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs5_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 6 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs6_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs6_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs6_dat_o,    // DAT_O() data out
+    output wire                    wbs6_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs6_sel_o,    // SEL_O() select output
+    output wire                    wbs6_stb_o,    // STB_O strobe output
+    input  wire                    wbs6_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs6_err_i,    // ERR_I error input
+    input  wire                    wbs6_rty_i,    // RTY_I retry input
+    output wire                    wbs6_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 6 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs6_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs6_addr_msk  // Slave address prefix mask
+);
+
+wire wbs0_match = ~|((wbm_adr_i ^ wbs0_addr) & wbs0_addr_msk);
+wire wbs1_match = ~|((wbm_adr_i ^ wbs1_addr) & wbs1_addr_msk);
+wire wbs2_match = ~|((wbm_adr_i ^ wbs2_addr) & wbs2_addr_msk);
+wire wbs3_match = ~|((wbm_adr_i ^ wbs3_addr) & wbs3_addr_msk);
+wire wbs4_match = ~|((wbm_adr_i ^ wbs4_addr) & wbs4_addr_msk);
+wire wbs5_match = ~|((wbm_adr_i ^ wbs5_addr) & wbs5_addr_msk);
+wire wbs6_match = ~|((wbm_adr_i ^ wbs6_addr) & wbs6_addr_msk);
+
+wire wbs0_sel = wbs0_match;
+wire wbs1_sel = wbs1_match & ~(wbs0_match);
+wire wbs2_sel = wbs2_match & ~(wbs0_match | wbs1_match);
+wire wbs3_sel = wbs3_match & ~(wbs0_match | wbs1_match | wbs2_match);
+wire wbs4_sel = wbs4_match & ~(wbs0_match | wbs1_match | wbs2_match | wbs3_match);
+wire wbs5_sel = wbs5_match & ~(wbs0_match | wbs1_match | wbs2_match | wbs3_match | wbs4_match);
+wire wbs6_sel = wbs6_match & ~(wbs0_match | wbs1_match | wbs2_match | wbs3_match | wbs4_match | wbs5_match);
+
+wire master_cycle = wbm_cyc_i & wbm_stb_i;
+
+wire select_error = ~(wbs0_sel | wbs1_sel | wbs2_sel | wbs3_sel | wbs4_sel | wbs5_sel | wbs6_sel) & master_cycle;
+
+// master
+assign wbm_dat_o = wbs0_sel ? wbs0_dat_i :
+                   wbs1_sel ? wbs1_dat_i :
+                   wbs2_sel ? wbs2_dat_i :
+                   wbs3_sel ? wbs3_dat_i :
+                   wbs4_sel ? wbs4_dat_i :
+                   wbs5_sel ? wbs5_dat_i :
+                   wbs6_sel ? wbs6_dat_i :
+                   {DATA_WIDTH{1'b0}};
+
+assign wbm_ack_o = wbs0_ack_i |
+                   wbs1_ack_i |
+                   wbs2_ack_i |
+                   wbs3_ack_i |
+                   wbs4_ack_i |
+                   wbs5_ack_i |
+                   wbs6_ack_i;
+
+assign wbm_err_o = wbs0_err_i |
+                   wbs1_err_i |
+                   wbs2_err_i |
+                   wbs3_err_i |
+                   wbs4_err_i |
+                   wbs5_err_i |
+                   wbs6_err_i |
+                   select_error;
+
+assign wbm_rty_o = wbs0_rty_i |
+                   wbs1_rty_i |
+                   wbs2_rty_i |
+                   wbs3_rty_i |
+                   wbs4_rty_i |
+                   wbs5_rty_i |
+                   wbs6_rty_i;
+
+// slave 0
+assign wbs0_adr_o = wbm_adr_i;
+assign wbs0_dat_o = wbm_dat_i;
+assign wbs0_we_o = wbm_we_i & wbs0_sel;
+assign wbs0_sel_o = wbm_sel_i;
+assign wbs0_stb_o = wbm_stb_i & wbs0_sel;
+assign wbs0_cyc_o = wbm_cyc_i & wbs0_sel;
+
+// slave 1
+assign wbs1_adr_o = wbm_adr_i;
+assign wbs1_dat_o = wbm_dat_i;
+assign wbs1_we_o = wbm_we_i & wbs1_sel;
+assign wbs1_sel_o = wbm_sel_i;
+assign wbs1_stb_o = wbm_stb_i & wbs1_sel;
+assign wbs1_cyc_o = wbm_cyc_i & wbs1_sel;
+
+// slave 2
+assign wbs2_adr_o = wbm_adr_i;
+assign wbs2_dat_o = wbm_dat_i;
+assign wbs2_we_o = wbm_we_i & wbs2_sel;
+assign wbs2_sel_o = wbm_sel_i;
+assign wbs2_stb_o = wbm_stb_i & wbs2_sel;
+assign wbs2_cyc_o = wbm_cyc_i & wbs2_sel;
+
+// slave 3
+assign wbs3_adr_o = wbm_adr_i;
+assign wbs3_dat_o = wbm_dat_i;
+assign wbs3_we_o = wbm_we_i & wbs3_sel;
+assign wbs3_sel_o = wbm_sel_i;
+assign wbs3_stb_o = wbm_stb_i & wbs3_sel;
+assign wbs3_cyc_o = wbm_cyc_i & wbs3_sel;
+
+// slave 4
+assign wbs4_adr_o = wbm_adr_i;
+assign wbs4_dat_o = wbm_dat_i;
+assign wbs4_we_o = wbm_we_i & wbs4_sel;
+assign wbs4_sel_o = wbm_sel_i;
+assign wbs4_stb_o = wbm_stb_i & wbs4_sel;
+assign wbs4_cyc_o = wbm_cyc_i & wbs4_sel;
+
+// slave 5
+assign wbs5_adr_o = wbm_adr_i;
+assign wbs5_dat_o = wbm_dat_i;
+assign wbs5_we_o = wbm_we_i & wbs5_sel;
+assign wbs5_sel_o = wbm_sel_i;
+assign wbs5_stb_o = wbm_stb_i & wbs5_sel;
+assign wbs5_cyc_o = wbm_cyc_i & wbs5_sel;
+
+// slave 6
+assign wbs6_adr_o = wbm_adr_i;
+assign wbs6_dat_o = wbm_dat_i;
+assign wbs6_we_o = wbm_we_i & wbs6_sel;
+assign wbs6_sel_o = wbm_sel_i;
+assign wbs6_stb_o = wbm_stb_i & wbs6_sel;
+assign wbs6_cyc_o = wbm_cyc_i & wbs6_sel;
+
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_8.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_8.v
new file mode 100644
index 0000000..41b1e09
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_mux_8.v
@@ -0,0 +1,343 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1 ns / 1 ps
+
+/*
+ * Wishbone 8 port multiplexer
+ */
+module wb_mux_8 #
+(
+    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8)       // width of word select bus (1, 2, 4, or 8)
+)
+(
+    input  wire                    clk,
+    input  wire                    rst,
+
+    /*
+     * Wishbone master input
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbm_adr_i,     // ADR_I() address input
+    input  wire [DATA_WIDTH-1:0]   wbm_dat_i,     // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm_dat_o,     // DAT_O() data out
+    input  wire                    wbm_we_i,      // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm_sel_i,     // SEL_I() select input
+    input  wire                    wbm_stb_i,     // STB_I strobe input
+    output wire                    wbm_ack_o,     // ACK_O acknowledge output
+    output wire                    wbm_err_o,     // ERR_O error output
+    output wire                    wbm_rty_o,     // RTY_O retry output
+    input  wire                    wbm_cyc_i,     // CYC_I cycle input
+
+    /*
+     * Wishbone slave 0 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs0_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs0_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs0_dat_o,    // DAT_O() data out
+    output wire                    wbs0_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs0_sel_o,    // SEL_O() select output
+    output wire                    wbs0_stb_o,    // STB_O strobe output
+    input  wire                    wbs0_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs0_err_i,    // ERR_I error input
+    input  wire                    wbs0_rty_i,    // RTY_I retry input
+    output wire                    wbs0_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 0 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs0_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs0_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 1 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs1_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs1_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs1_dat_o,    // DAT_O() data out
+    output wire                    wbs1_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs1_sel_o,    // SEL_O() select output
+    output wire                    wbs1_stb_o,    // STB_O strobe output
+    input  wire                    wbs1_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs1_err_i,    // ERR_I error input
+    input  wire                    wbs1_rty_i,    // RTY_I retry input
+    output wire                    wbs1_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 1 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs1_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs1_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 2 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs2_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs2_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs2_dat_o,    // DAT_O() data out
+    output wire                    wbs2_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs2_sel_o,    // SEL_O() select output
+    output wire                    wbs2_stb_o,    // STB_O strobe output
+    input  wire                    wbs2_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs2_err_i,    // ERR_I error input
+    input  wire                    wbs2_rty_i,    // RTY_I retry input
+    output wire                    wbs2_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 2 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs2_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs2_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 3 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs3_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs3_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs3_dat_o,    // DAT_O() data out
+    output wire                    wbs3_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs3_sel_o,    // SEL_O() select output
+    output wire                    wbs3_stb_o,    // STB_O strobe output
+    input  wire                    wbs3_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs3_err_i,    // ERR_I error input
+    input  wire                    wbs3_rty_i,    // RTY_I retry input
+    output wire                    wbs3_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 3 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs3_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs3_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 4 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs4_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs4_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs4_dat_o,    // DAT_O() data out
+    output wire                    wbs4_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs4_sel_o,    // SEL_O() select output
+    output wire                    wbs4_stb_o,    // STB_O strobe output
+    input  wire                    wbs4_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs4_err_i,    // ERR_I error input
+    input  wire                    wbs4_rty_i,    // RTY_I retry input
+    output wire                    wbs4_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 4 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs4_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs4_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 5 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs5_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs5_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs5_dat_o,    // DAT_O() data out
+    output wire                    wbs5_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs5_sel_o,    // SEL_O() select output
+    output wire                    wbs5_stb_o,    // STB_O strobe output
+    input  wire                    wbs5_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs5_err_i,    // ERR_I error input
+    input  wire                    wbs5_rty_i,    // RTY_I retry input
+    output wire                    wbs5_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 5 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs5_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs5_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 6 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs6_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs6_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs6_dat_o,    // DAT_O() data out
+    output wire                    wbs6_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs6_sel_o,    // SEL_O() select output
+    output wire                    wbs6_stb_o,    // STB_O strobe output
+    input  wire                    wbs6_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs6_err_i,    // ERR_I error input
+    input  wire                    wbs6_rty_i,    // RTY_I retry input
+    output wire                    wbs6_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 6 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs6_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs6_addr_msk, // Slave address prefix mask
+
+    /*
+     * Wishbone slave 7 output
+     */
+    output wire [ADDR_WIDTH-1:0]   wbs7_adr_o,    // ADR_O() address output
+    input  wire [DATA_WIDTH-1:0]   wbs7_dat_i,    // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs7_dat_o,    // DAT_O() data out
+    output wire                    wbs7_we_o,     // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs7_sel_o,    // SEL_O() select output
+    output wire                    wbs7_stb_o,    // STB_O strobe output
+    input  wire                    wbs7_ack_i,    // ACK_I acknowledge input
+    input  wire                    wbs7_err_i,    // ERR_I error input
+    input  wire                    wbs7_rty_i,    // RTY_I retry input
+    output wire                    wbs7_cyc_o,    // CYC_O cycle output
+
+    /*
+     * Wishbone slave 7 address configuration
+     */
+    input  wire [ADDR_WIDTH-1:0]   wbs7_addr,     // Slave address prefix
+    input  wire [ADDR_WIDTH-1:0]   wbs7_addr_msk  // Slave address prefix mask
+);
+
+wire wbs0_match = ~|((wbm_adr_i ^ wbs0_addr) & wbs0_addr_msk);
+wire wbs1_match = ~|((wbm_adr_i ^ wbs1_addr) & wbs1_addr_msk);
+wire wbs2_match = ~|((wbm_adr_i ^ wbs2_addr) & wbs2_addr_msk);
+wire wbs3_match = ~|((wbm_adr_i ^ wbs3_addr) & wbs3_addr_msk);
+wire wbs4_match = ~|((wbm_adr_i ^ wbs4_addr) & wbs4_addr_msk);
+wire wbs5_match = ~|((wbm_adr_i ^ wbs5_addr) & wbs5_addr_msk);
+wire wbs6_match = ~|((wbm_adr_i ^ wbs6_addr) & wbs6_addr_msk);
+wire wbs7_match = ~|((wbm_adr_i ^ wbs7_addr) & wbs7_addr_msk);
+
+wire wbs0_sel = wbs0_match;
+wire wbs1_sel = wbs1_match & ~(wbs0_match);
+wire wbs2_sel = wbs2_match & ~(wbs0_match | wbs1_match);
+wire wbs3_sel = wbs3_match & ~(wbs0_match | wbs1_match | wbs2_match);
+wire wbs4_sel = wbs4_match & ~(wbs0_match | wbs1_match | wbs2_match | wbs3_match);
+wire wbs5_sel = wbs5_match & ~(wbs0_match | wbs1_match | wbs2_match | wbs3_match | wbs4_match);
+wire wbs6_sel = wbs6_match & ~(wbs0_match | wbs1_match | wbs2_match | wbs3_match | wbs4_match | wbs5_match);
+wire wbs7_sel = wbs7_match & ~(wbs0_match | wbs1_match | wbs2_match | wbs3_match | wbs4_match | wbs5_match | wbs6_match);
+
+wire master_cycle = wbm_cyc_i & wbm_stb_i;
+
+wire select_error = ~(wbs0_sel | wbs1_sel | wbs2_sel | wbs3_sel | wbs4_sel | wbs5_sel | wbs6_sel | wbs7_sel) & master_cycle;
+
+// master
+assign wbm_dat_o = wbs0_sel ? wbs0_dat_i :
+                   wbs1_sel ? wbs1_dat_i :
+                   wbs2_sel ? wbs2_dat_i :
+                   wbs3_sel ? wbs3_dat_i :
+                   wbs4_sel ? wbs4_dat_i :
+                   wbs5_sel ? wbs5_dat_i :
+                   wbs6_sel ? wbs6_dat_i :
+                   wbs7_sel ? wbs7_dat_i :
+                   {DATA_WIDTH{1'b0}};
+
+assign wbm_ack_o = wbs0_ack_i |
+                   wbs1_ack_i |
+                   wbs2_ack_i |
+                   wbs3_ack_i |
+                   wbs4_ack_i |
+                   wbs5_ack_i |
+                   wbs6_ack_i |
+                   wbs7_ack_i;
+
+assign wbm_err_o = wbs0_err_i |
+                   wbs1_err_i |
+                   wbs2_err_i |
+                   wbs3_err_i |
+                   wbs4_err_i |
+                   wbs5_err_i |
+                   wbs6_err_i |
+                   wbs7_err_i |
+                   select_error;
+
+assign wbm_rty_o = wbs0_rty_i |
+                   wbs1_rty_i |
+                   wbs2_rty_i |
+                   wbs3_rty_i |
+                   wbs4_rty_i |
+                   wbs5_rty_i |
+                   wbs6_rty_i |
+                   wbs7_rty_i;
+
+// slave 0
+assign wbs0_adr_o = wbm_adr_i;
+assign wbs0_dat_o = wbm_dat_i;
+assign wbs0_we_o = wbm_we_i & wbs0_sel;
+assign wbs0_sel_o = wbm_sel_i;
+assign wbs0_stb_o = wbm_stb_i & wbs0_sel;
+assign wbs0_cyc_o = wbm_cyc_i & wbs0_sel;
+
+// slave 1
+assign wbs1_adr_o = wbm_adr_i;
+assign wbs1_dat_o = wbm_dat_i;
+assign wbs1_we_o = wbm_we_i & wbs1_sel;
+assign wbs1_sel_o = wbm_sel_i;
+assign wbs1_stb_o = wbm_stb_i & wbs1_sel;
+assign wbs1_cyc_o = wbm_cyc_i & wbs1_sel;
+
+// slave 2
+assign wbs2_adr_o = wbm_adr_i;
+assign wbs2_dat_o = wbm_dat_i;
+assign wbs2_we_o = wbm_we_i & wbs2_sel;
+assign wbs2_sel_o = wbm_sel_i;
+assign wbs2_stb_o = wbm_stb_i & wbs2_sel;
+assign wbs2_cyc_o = wbm_cyc_i & wbs2_sel;
+
+// slave 3
+assign wbs3_adr_o = wbm_adr_i;
+assign wbs3_dat_o = wbm_dat_i;
+assign wbs3_we_o = wbm_we_i & wbs3_sel;
+assign wbs3_sel_o = wbm_sel_i;
+assign wbs3_stb_o = wbm_stb_i & wbs3_sel;
+assign wbs3_cyc_o = wbm_cyc_i & wbs3_sel;
+
+// slave 4
+assign wbs4_adr_o = wbm_adr_i;
+assign wbs4_dat_o = wbm_dat_i;
+assign wbs4_we_o = wbm_we_i & wbs4_sel;
+assign wbs4_sel_o = wbm_sel_i;
+assign wbs4_stb_o = wbm_stb_i & wbs4_sel;
+assign wbs4_cyc_o = wbm_cyc_i & wbs4_sel;
+
+// slave 5
+assign wbs5_adr_o = wbm_adr_i;
+assign wbs5_dat_o = wbm_dat_i;
+assign wbs5_we_o = wbm_we_i & wbs5_sel;
+assign wbs5_sel_o = wbm_sel_i;
+assign wbs5_stb_o = wbm_stb_i & wbs5_sel;
+assign wbs5_cyc_o = wbm_cyc_i & wbs5_sel;
+
+// slave 6
+assign wbs6_adr_o = wbm_adr_i;
+assign wbs6_dat_o = wbm_dat_i;
+assign wbs6_we_o = wbm_we_i & wbs6_sel;
+assign wbs6_sel_o = wbm_sel_i;
+assign wbs6_stb_o = wbm_stb_i & wbs6_sel;
+assign wbs6_cyc_o = wbm_cyc_i & wbs6_sel;
+
+// slave 7
+assign wbs7_adr_o = wbm_adr_i;
+assign wbs7_dat_o = wbm_dat_i;
+assign wbs7_we_o = wbm_we_i & wbs7_sel;
+assign wbs7_sel_o = wbm_sel_i;
+assign wbs7_stb_o = wbm_stb_i & wbs7_sel;
+assign wbs7_cyc_o = wbm_cyc_i & wbs7_sel;
+
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_ram.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_ram.v
new file mode 100644
index 0000000..c167520
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_ram.v
@@ -0,0 +1,94 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Wishbone RAM
+ */
+module wb_ram #
+(
+    parameter DATA_WIDTH = 32,              // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 16,              // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8) // width of word select bus (1, 2, 4, or 8)
+)
+(
+    input  wire                    clk,
+
+    input  wire [ADDR_WIDTH-1:0]   adr_i,   // ADR_I() address
+    input  wire [DATA_WIDTH-1:0]   dat_i,   // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   dat_o,   // DAT_O() data out
+    input  wire                    we_i,    // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] sel_i,   // SEL_I() select input
+    input  wire                    stb_i,   // STB_I strobe input
+    output wire                    ack_o,   // ACK_O acknowledge output
+    input  wire                    cyc_i    // CYC_I cycle input
+);
+
+// for interfaces that are more than one word wide, disable address lines
+parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(SELECT_WIDTH);
+// width of data port in words (1, 2, 4, or 8)
+parameter WORD_WIDTH = SELECT_WIDTH;
+// size of words (8, 16, 32, or 64 bits)
+parameter WORD_SIZE = DATA_WIDTH/WORD_WIDTH;
+
+reg [DATA_WIDTH-1:0] dat_o_reg = {DATA_WIDTH{1'b0}};
+reg ack_o_reg = 1'b0;
+
+// (* RAM_STYLE="BLOCK" *)
+reg [DATA_WIDTH-1:0] mem[(2**VALID_ADDR_WIDTH)-1:0];
+
+wire [VALID_ADDR_WIDTH-1:0] adr_i_valid = adr_i >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
+
+assign dat_o = dat_o_reg;
+assign ack_o = ack_o_reg;
+
+integer i, j;
+
+initial begin
+    // two nested loops for smaller number of iterations per loop
+    // workaround for synthesizer complaints about large loop counts
+    for (i = 0; i < 2**ADDR_WIDTH; i = i + 2**(ADDR_WIDTH/2)) begin
+        for (j = i; j < i + 2**(ADDR_WIDTH/2); j = j + 1) begin
+            mem[j] = 0;
+        end
+    end
+end
+
+always @(posedge clk) begin
+    ack_o_reg <= 1'b0;
+    for (i = 0; i < WORD_WIDTH; i = i + 1) begin
+        if (cyc_i & stb_i & ~ack_o) begin
+            if (we_i & sel_i[i]) begin
+                mem[adr_i_valid][WORD_SIZE*i +: WORD_SIZE] <= dat_i[WORD_SIZE*i +: WORD_SIZE];
+            end
+            dat_o_reg[WORD_SIZE*i +: WORD_SIZE] <= mem[adr_i_valid][WORD_SIZE*i +: WORD_SIZE];
+            ack_o_reg <= 1'b1;
+        end
+    end
+end
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_reg.v b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_reg.v
new file mode 100644
index 0000000..c26d912
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/rtl/wb_reg.v
@@ -0,0 +1,131 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Wishbone register
+ */
+module wb_reg #
+(
+    parameter DATA_WIDTH = 32,                  // width of data bus in bits (8, 16, 32, or 64)
+    parameter ADDR_WIDTH = 32,                  // width of address bus in bits
+    parameter SELECT_WIDTH = (DATA_WIDTH/8)     // width of word select bus (1, 2, 4, or 8)
+)
+(
+    input  wire                    clk,
+    input  wire                    rst,
+
+    // master side
+    input  wire [ADDR_WIDTH-1:0]   wbm_adr_i,   // ADR_I() address
+    input  wire [DATA_WIDTH-1:0]   wbm_dat_i,   // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbm_dat_o,   // DAT_O() data out
+    input  wire                    wbm_we_i,    // WE_I write enable input
+    input  wire [SELECT_WIDTH-1:0] wbm_sel_i,   // SEL_I() select input
+    input  wire                    wbm_stb_i,   // STB_I strobe input
+    output wire                    wbm_ack_o,   // ACK_O acknowledge output
+    output wire                    wbm_err_o,   // ERR_O error output
+    output wire                    wbm_rty_o,   // RTY_O retry output
+    input  wire                    wbm_cyc_i,   // CYC_I cycle input
+
+    // slave side
+    output wire [ADDR_WIDTH-1:0]   wbs_adr_o,   // ADR_O() address
+    input  wire [DATA_WIDTH-1:0]   wbs_dat_i,   // DAT_I() data in
+    output wire [DATA_WIDTH-1:0]   wbs_dat_o,   // DAT_O() data out
+    output wire                    wbs_we_o,    // WE_O write enable output
+    output wire [SELECT_WIDTH-1:0] wbs_sel_o,   // SEL_O() select output
+    output wire                    wbs_stb_o,   // STB_O strobe output
+    input  wire                    wbs_ack_i,   // ACK_I acknowledge input
+    input  wire                    wbs_err_i,   // ERR_I error input
+    input  wire                    wbs_rty_i,   // RTY_I retry input
+    output wire                    wbs_cyc_o    // CYC_O cycle output
+);
+
+reg [DATA_WIDTH-1:0] wbm_dat_o_reg = 0;
+reg wbm_ack_o_reg = 0;
+reg wbm_err_o_reg = 0;
+reg wbm_rty_o_reg = 0;
+
+reg [ADDR_WIDTH-1:0] wbs_adr_o_reg = 0;
+reg [DATA_WIDTH-1:0] wbs_dat_o_reg = 0;
+reg wbs_we_o_reg = 0;
+reg [SELECT_WIDTH-1:0] wbs_sel_o_reg = 0;
+reg wbs_stb_o_reg = 0;
+reg wbs_cyc_o_reg = 0;
+
+assign wbm_dat_o = wbm_dat_o_reg;
+assign wbm_ack_o = wbm_ack_o_reg;
+assign wbm_err_o = wbm_err_o_reg;
+assign wbm_rty_o = wbm_rty_o_reg;
+
+assign wbs_adr_o = wbs_adr_o_reg;
+assign wbs_dat_o = wbs_dat_o_reg;
+assign wbs_we_o = wbs_we_o_reg;
+assign wbs_sel_o = wbs_sel_o_reg;
+assign wbs_stb_o = wbs_stb_o_reg;
+assign wbs_cyc_o = wbs_cyc_o_reg;
+
+always @(posedge clk) begin
+    if (rst) begin
+        wbm_dat_o_reg <= 0;
+        wbm_ack_o_reg <= 0;
+        wbm_err_o_reg <= 0;
+        wbm_rty_o_reg <= 0;
+        wbs_adr_o_reg <= 0;
+        wbs_dat_o_reg <= 0;
+        wbs_we_o_reg <= 0;
+        wbs_sel_o_reg <= 0;
+        wbs_stb_o_reg <= 0;
+        wbs_cyc_o_reg <= 0;
+    end else begin
+        if (wbs_cyc_o_reg & wbs_stb_o_reg) begin
+            // cycle - hold values
+            if (wbs_ack_i | wbs_err_i | wbs_rty_i) begin
+                // end of cycle - pass through slave to master
+                wbm_dat_o_reg <= wbs_dat_i;
+                wbm_ack_o_reg <= wbs_ack_i;
+                wbm_err_o_reg <= wbs_err_i;
+                wbm_rty_o_reg <= wbs_rty_i;
+                wbs_we_o_reg <= 0;
+                wbs_stb_o_reg <= 0;
+            end
+        end else begin
+            // idle - pass through master to slave
+            wbm_dat_o_reg <= 0;
+            wbm_ack_o_reg <= 0;
+            wbm_err_o_reg <= 0;
+            wbm_rty_o_reg <= 0;
+            wbs_adr_o_reg <= wbm_adr_i;
+            wbs_dat_o_reg <= wbm_dat_i;
+            wbs_we_o_reg <= wbm_we_i & ~(wbm_ack_o | wbm_err_o | wbm_rty_o);
+            wbs_sel_o_reg <= wbm_sel_i;
+            wbs_stb_o_reg <= wbm_stb_i & ~(wbm_ack_o | wbm_err_o | wbm_rty_o);
+            wbs_cyc_o_reg <= wbm_cyc_i;
+        end
+    end
+end
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/axis_ep.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/axis_ep.py
new file mode 100644
index 0000000..de4528e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/axis_ep.py
@@ -0,0 +1,512 @@
+"""
+
+Copyright (c) 2014-2018 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+
+skip_asserts = False
+
+class AXIStreamFrame(object):
+    def __init__(self, data=b'', keep=None, id=None, dest=None, user=None, last_cycle_user=None):
+        self.B = 0
+        self.N = 8
+        self.M = 1
+        self.WL = 8
+        self.data = b''
+        self.keep = None
+        self.id = 0
+        self.dest = 0
+        self.user = None
+        self.last_cycle_user = None
+
+        if type(data) in (bytes, bytearray):
+            self.data = bytearray(data)
+            self.keep = keep
+            self.id = id
+            self.dest = dest
+            self.user = user
+            self.last_cycle_user = last_cycle_user
+        elif type(data) is AXIStreamFrame:
+            self.N = data.N
+            self.WL = data.WL
+            if type(data.data) is bytearray:
+                self.data = bytearray(data.data)
+            else:
+                self.data = list(data.data)
+            if data.keep is not None:
+                self.keep = list(data.keep)
+            if data.id is not None:
+                if type(data.id) in (int, bool):
+                    self.id = data.id
+                else:
+                    self.id = list(data.id)
+            if data.dest is not None:
+                if type(data.dest) in (int, bool):
+                    self.dest = data.dest
+                else:
+                    self.dest = list(data.dest)
+            if data.user is not None:
+                if type(data.user) in (int, bool):
+                    self.user = data.user
+                else:
+                    self.user = list(data.user)
+            self.last_cycle_user = data.last_cycle_user
+        else:
+            self.data = list(data)
+            self.keep = keep
+            self.id = id
+            self.dest = dest
+            self.user = user
+            self.last_cycle_user = last_cycle_user
+
+    def build(self):
+        if self.data is None:
+            return
+
+        f = list(self.data)
+        tdata = []
+        tkeep = []
+        tid = []
+        tdest = []
+        tuser = []
+        i = 0
+
+        while len(f) > 0:
+            if self.B == 0:
+                data = 0
+                keep = 0
+                for j in range(self.M):
+                    data = data | (f.pop(0) << (j*self.WL))
+                    keep = keep | (1 << j)
+                    if len(f) == 0: break
+                tdata.append(data)
+
+                if self.keep is None:
+                    tkeep.append(keep)
+                else:
+                    tkeep.append(self.keep[i])
+            else:
+                # multiple tdata signals
+                data = 0
+                tdata.append(f.pop(0))
+                tkeep.append(0)
+
+            if self.id is None:
+                tid.append(0)
+            elif type(self.id) is int:
+                tid.append(self.id)
+            else:
+                tid.append(self.id[i])
+
+            if self.dest is None:
+                tdest.append(0)
+            elif type(self.dest) is int:
+                tdest.append(self.dest)
+            else:
+                tdest.append(self.dest[i])
+
+            if self.user is None:
+                tuser.append(0)
+            elif type(self.user) is int:
+                tuser.append(self.user)
+            else:
+                tuser.append(self.user[i])
+            i += 1
+
+        if self.last_cycle_user:
+            tuser[-1] = self.last_cycle_user
+
+        return tdata, tkeep, tid, tdest, tuser
+
+    def parse(self, tdata, tkeep, tid, tdest, tuser):
+        if tdata is None or tkeep is None or tuser is None:
+            return
+        if len(tdata) != len(tkeep) or len(tdata) != len(tid) or len(tdata) != len(tdest) or len(tdata) != len(tuser):
+            raise Exception("Invalid data")
+
+        self.data = []
+        self.keep = []
+        self.id = []
+        self.dest = []
+        self.user = []
+
+        if self.B == 0:
+            mask = 2**self.WL-1
+
+            for i in range(len(tdata)):
+                for j in range(self.M):
+                    if tkeep[i] & (1 << j):
+                        self.data.append((tdata[i] >> (j*self.WL)) & mask)
+                self.keep.append(tkeep[i])
+                self.id.append(tid[i])
+                self.dest.append(tdest[i])
+                self.user.append(tuser[i])
+        else:
+            for i in range(len(tdata)):
+                self.data.append(tdata[i])
+                self.keep.append(tkeep[i])
+                self.id.append(tid[i])
+                self.dest.append(tdest[i])
+                self.user.append(tuser[i])
+
+        if self.WL == 8:
+            self.data = bytearray(self.data)
+
+        self.last_cycle_user = self.user[-1]
+
+    def __eq__(self, other):
+        if not isinstance(other, AXIStreamFrame):
+            return False
+        if self.data != other.data:
+            return False
+        if self.keep is not None and other.keep is not None:
+            if self.keep != other.keep:
+                return False
+        if self.id is not None and other.id is not None:
+            if type(self.id) in (int, bool) and type(other.id) is list:
+                for k in other.id:
+                    if self.id != k:
+                        return False
+            elif type(other.id) in (int, bool) and type(self.id) is list:
+                for k in self.id:
+                    if other.id != k:
+                        return False
+            elif self.id != other.id:
+                return False
+        if self.dest is not None and other.dest is not None:
+            if type(self.dest) in (int, bool) and type(other.dest) is list:
+                for k in other.dest:
+                    if self.dest != k:
+                        return False
+            elif type(other.dest) in (int, bool) and type(self.dest) is list:
+                for k in self.dest:
+                    if other.dest != k:
+                        return False
+            elif self.dest != other.dest:
+                return False
+        if self.last_cycle_user is not None and other.last_cycle_user is not None:
+            if self.last_cycle_user != other.last_cycle_user:
+                return False
+            if self.user is not None and other.user is not None:
+                if type(self.user) in (int, bool) and type(other.user) is list:
+                    for k in other.user[:-1]:
+                        if self.user != k:
+                            return False
+                elif type(other.user) in (int, bool) and type(self.user) is list:
+                    for k in self.user[:-1]:
+                        if other.user != k:
+                            return False
+                elif self.user != other.user:
+                    return False
+        else:
+            if self.user is not None and other.user is not None:
+                if type(self.user) in (int, bool) and type(other.user) is list:
+                    for k in other.user:
+                        if self.user != k:
+                            return False
+                elif type(other.user) in (int, bool) and type(self.user) is list:
+                    for k in self.user:
+                        if other.user != k:
+                            return False
+                elif self.user != other.user:
+                    return False
+        return True
+
+    def __repr__(self):
+        return (
+                ('AXIStreamFrame(data=%s, ' % repr(self.data)) +
+                ('keep=%s, ' % repr(self.keep)) +
+                ('id=%s, ' % repr(self.id)) +
+                ('dest=%s, ' % repr(self.dest)) +
+                ('user=%s, ' % repr(self.user)) +
+                ('last_cycle_user=%s)' % repr(self.last_cycle_user))
+            )
+
+    def __iter__(self):
+        return self.data.__iter__()
+
+
+class AXIStreamSource(object):
+    def __init__(self):
+        self.has_logic = False
+        self.queue = []
+
+    def send(self, frame):
+        self.queue.append(AXIStreamFrame(frame))
+
+    def write(self, data):
+        self.send(data)
+
+    def count(self):
+        return len(self.queue)
+
+    def empty(self):
+        return self.count() == 0
+
+    def create_logic(self,
+                clk,
+                rst,
+                tdata=None,
+                tkeep=Signal(bool(True)),
+                tvalid=Signal(bool(False)),
+                tready=Signal(bool(True)),
+                tlast=Signal(bool(False)),
+                tid=Signal(intbv(0)),
+                tdest=Signal(intbv(0)),
+                tuser=Signal(intbv(0)),
+                pause=0,
+                name=None
+            ):
+
+        assert not self.has_logic
+
+        self.has_logic = True
+
+        tready_int = Signal(bool(False))
+        tvalid_int = Signal(bool(False))
+
+        @always_comb
+        def pause_logic():
+            tready_int.next = tready and not pause
+            tvalid.next = tvalid_int and not pause
+
+        @instance
+        def logic():
+            frame = AXIStreamFrame()
+            data = []
+            keep = []
+            id = []
+            dest = []
+            user = []
+            B = 0
+            N = len(tdata)
+            M = len(tkeep)
+            WL = int((len(tdata)+M-1)/M)
+
+            if type(tdata) is list or type(tdata) is tuple:
+                # multiple tdata signals
+                B = len(tdata)
+                N = [len(b) for b in tdata]
+                M = 1
+                WL = [1]*B
+
+            while True:
+                yield clk.posedge, rst.posedge
+
+                if rst:
+                    if B > 0:
+                        for s in tdata:
+                            s.next = 0
+                    else:
+                        tdata.next = 0
+                    tkeep.next = 0
+                    tid.next = 0
+                    tdest.next = 0
+                    tuser.next = False
+                    tvalid_int.next = False
+                    tlast.next = False
+                else:
+                    if tready_int and tvalid:
+                        if len(data) > 0:
+                            if B > 0:
+                                l = data.pop(0)
+                                for i in range(B):
+                                    tdata[i].next = l[i]
+                            else:
+                                tdata.next = data.pop(0)
+                            tkeep.next = keep.pop(0)
+                            tid.next = id.pop(0)
+                            tdest.next = dest.pop(0)
+                            tuser.next = user.pop(0)
+                            tvalid_int.next = True
+                            tlast.next = len(data) == 0
+                        else:
+                            tvalid_int.next = False
+                            tlast.next = False
+                    if (tlast and tready_int and tvalid) or not tvalid_int:
+                        if len(self.queue) > 0:
+                            frame = self.queue.pop(0)
+                            frame.B = B
+                            frame.N = N
+                            frame.M = M
+                            frame.WL = WL
+                            data, keep, id, dest, user = frame.build()
+                            if name is not None:
+                                print("[%s] Sending frame %s" % (name, repr(frame)))
+                            if B > 0:
+                                l = data.pop(0)
+                                for i in range(B):
+                                    tdata[i].next = l[i]
+                            else:
+                                tdata.next = data.pop(0)
+                            tkeep.next = keep.pop(0)
+                            tid.next = id.pop(0)
+                            tdest.next = dest.pop(0)
+                            tuser.next = user.pop(0)
+                            tvalid_int.next = True
+                            tlast.next = len(data) == 0
+
+        return instances()
+
+
+class AXIStreamSink(object):
+    def __init__(self):
+        self.has_logic = False
+        self.queue = []
+        self.read_queue = []
+
+    def recv(self):
+        if len(self.queue) > 0:
+            return self.queue.pop(0)
+        return None
+
+    def read(self, count=-1):
+        while len(self.queue) > 0:
+            self.read_queue.extend(self.queue.pop(0).data)
+        if count < 0:
+            count = len(self.read_queue)
+        data = self.read_queue[:count]
+        del self.read_queue[:count]
+        return data
+
+    def count(self):
+        return len(self.queue)
+
+    def empty(self):
+        return self.count() == 0
+
+    def create_logic(self,
+                clk,
+                rst,
+                tdata=None,
+                tkeep=Signal(bool(True)),
+                tvalid=Signal(bool(False)),
+                tready=Signal(bool(True)),
+                tlast=Signal(bool(True)),
+                tid=Signal(intbv(0)),
+                tdest=Signal(intbv(0)),
+                tuser=Signal(intbv(0)),
+                pause=0,
+                name=None
+            ):
+
+        assert not self.has_logic
+
+        self.has_logic = True
+
+        tready_int = Signal(bool(False))
+        tvalid_int = Signal(bool(False))
+
+        @always_comb
+        def pause_logic():
+            tready.next = tready_int and not pause
+            tvalid_int.next = tvalid and not pause
+
+        @instance
+        def logic():
+            frame = AXIStreamFrame()
+            data = []
+            keep = []
+            id = []
+            dest = []
+            user = []
+            B = 0
+            N = len(tdata)
+            M = len(tkeep)
+            WL = int((len(tdata)+M-1)/M)
+            first = True
+
+            if type(tdata) is list or type(tdata) is tuple:
+                # multiple tdata signals
+                B = len(tdata)
+                N = [len(b) for b in tdata]
+                M = 1
+                WL = [1]*B
+
+            while True:
+                yield clk.posedge, rst.posedge
+
+                if rst:
+                    tready_int.next = False
+                    frame = AXIStreamFrame()
+                    data = []
+                    keep = []
+                    id = []
+                    dest = []
+                    user = []
+                    first = True
+                else:
+                    tready_int.next = True
+
+                    if tvalid_int:
+
+                        if not skip_asserts:
+                            # zero tkeep not allowed
+                            assert int(tkeep) != 0
+                            # tkeep must be contiguous
+                            # i.e. 0b00011110 allowed, but 0b00011010 not allowed
+                            b = int(tkeep)
+                            while b & 1 == 0:
+                                b = b >> 1
+                            while b & 1 == 1:
+                                b = b >> 1
+                            assert b == 0
+                            # tkeep must not have gaps across cycles
+                            if not first:
+                                # not first cycle; lowest bit must be set
+                                assert int(tkeep) & 1
+                            if not tlast:
+                                # not last cycle; highest bit must be set
+                                assert int(tkeep) & (1 << len(tkeep)-1)
+
+                        if B > 0:
+                            l = []
+                            for i in range(B):
+                                l.append(int(tdata[i]))
+                            data.append(l)
+                        else:
+                            data.append(int(tdata))
+                        keep.append(int(tkeep))
+                        id.append(int(tid))
+                        dest.append(int(tdest))
+                        user.append(int(tuser))
+                        first = False
+                        if tlast:
+                            frame.B = B
+                            frame.N = N
+                            frame.M = M
+                            frame.WL = WL
+                            frame.parse(data, keep, id, dest, user)
+                            self.queue.append(frame)
+                            if name is not None:
+                                print("[%s] Got frame %s" % (name, repr(frame)))
+                            frame = AXIStreamFrame()
+                            data = []
+                            keep = []
+                            id = []
+                            dest = []
+                            user = []
+                            first = True
+
+        return instances()
+
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_arbiter.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_arbiter.py
new file mode 100755
index 0000000..afb89f7
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_arbiter.py
@@ -0,0 +1,176 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2014-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+module = 'arbiter'
+testbench = 'test_%s' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("../rtl/priority_encoder.v")
+srcs.append("%s.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    PORTS = 32
+    TYPE = "PRIORITY"
+    BLOCK = "REQUEST"
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    request = Signal(intbv(0)[PORTS:])
+    acknowledge = Signal(intbv(0)[PORTS:])
+
+    # Outputs
+    grant = Signal(intbv(0)[PORTS:])
+    grant_valid = Signal(bool(0))
+    grant_encoded = Signal(intbv(0)[5:])
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        clk=clk,
+        rst=rst,
+        current_test=current_test,
+
+        request=request,
+        acknowledge=acknowledge,
+
+        grant=grant,
+        grant_valid=grant_valid,
+        grant_encoded=grant_encoded
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        yield clk.posedge
+
+        print("test 1: one bit")
+        current_test.next = 1
+
+        yield clk.posedge
+
+        for i in range(32):
+            l = [i]
+            k = 0
+            for y in l:
+                k = k | 1 << y
+            request.next = k
+            yield clk.posedge
+            request.next = 0
+            yield clk.posedge
+
+            assert grant == 1 << i
+            assert grant_encoded == i
+
+            yield clk.posedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        print("test 2: two bits")
+        current_test.next = 2
+
+        for i in range(32):
+            for j in range(32):
+                l = [i, j]
+                k = 0
+                for y in l:
+                    k = k | 1 << y
+                request.next = k
+                yield clk.posedge
+                request.next = 0
+                yield clk.posedge
+
+                assert grant == 1 << max(l)
+                assert grant_encoded == max(l)
+
+                request.next = 0
+
+                yield clk.posedge
+
+        print("test 3: five bits")
+        current_test.next = 3
+
+        for i in range(32):
+            l = [(i*x) % 32 for x in [1,2,3,4,5]]
+            k = 0
+            for y in l:
+                k = k | 1 << y
+            request.next = k
+            yield clk.posedge
+            request.next = 0
+            yield clk.posedge
+
+            assert grant == 1 << max(l)
+            assert grant_encoded == max(l)
+
+            prev = int(grant_encoded)
+
+            yield clk.posedge
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    os.chdir(os.path.dirname(os.path.abspath(__file__)))
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
+
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_arbiter.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_arbiter.v
new file mode 100644
index 0000000..ce9481a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_arbiter.v
@@ -0,0 +1,87 @@
+/*
+
+Copyright (c) 2014-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for arbiter
+ */
+module test_arbiter;
+
+// Parameters
+localparam PORTS = 32;
+localparam TYPE = "PRIORITY";
+localparam BLOCK = "REQUEST";
+
+// Inputs
+reg clk = 0;
+reg rst = 0;
+reg [7:0] current_test = 0;
+
+reg [PORTS-1:0] request = 0;
+reg [PORTS-1:0] acknowledge = 0;
+
+// Outputs
+wire [PORTS-1:0] grant;
+wire grant_valid;
+wire [$clog2(PORTS)-1:0] grant_encoded;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(
+        clk,
+        rst,
+        current_test,
+        request,
+        acknowledge
+    );
+    $to_myhdl(
+        grant,
+        grant_valid,
+        grant_encoded
+    );
+
+    // dump file
+    $dumpfile("test_arbiter.lxt");
+    $dumpvars(0, test_arbiter);
+end
+
+arbiter #(
+    .PORTS(PORTS),
+    .TYPE(TYPE),
+    .BLOCK(BLOCK)
+)
+UUT (
+    .clk(clk),
+    .rst(rst),
+    .request(request),
+    .acknowledge(acknowledge),
+    .grant(grant),
+    .grant_valid(grant_valid),
+    .grant_encoded(grant_encoded)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_arbiter_rr.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_arbiter_rr.py
new file mode 100755
index 0000000..671001f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_arbiter_rr.py
@@ -0,0 +1,236 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2014-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+module = 'arbiter'
+testbench = 'test_%s' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("../rtl/priority_encoder.v")
+srcs.append("%s_rr.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    PORTS = 32
+    TYPE = "ROUND_ROBIN"
+    BLOCK = "REQUEST"
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    request = Signal(intbv(0)[PORTS:])
+    acknowledge = Signal(intbv(0)[PORTS:])
+
+    # Outputs
+    grant = Signal(intbv(0)[PORTS:])
+    grant_valid = Signal(bool(0))
+    grant_encoded = Signal(intbv(0)[5:])
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        clk=clk,
+        rst=rst,
+        current_test=current_test,
+
+        request=request,
+        acknowledge=acknowledge,
+
+        grant=grant,
+        grant_valid=grant_valid,
+        grant_encoded=grant_encoded
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        yield clk.posedge
+
+        prev = 0
+
+        print("test 1: one bit")
+        current_test.next = 1
+
+        yield clk.posedge
+
+        for i in range(32):
+            l = [i]
+            k = 0
+            for y in l:
+                k = k | 1 << y
+            request.next = k
+            yield clk.posedge
+            request.next = 0
+            yield clk.posedge
+
+            # emulate round robin
+            l2 = [x for x in l if x < prev]
+            if len(l2) == 0:
+                l2 = l
+            g = max(l2)
+
+            assert grant == 1 << g
+            assert grant_encoded == g
+
+            prev = int(grant_encoded)
+
+            yield clk.posedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        print("test 2: cycle")
+        current_test.next = 2
+
+        for i in range(32):
+            l = [0, 5, 10, 15, 20, 25, 30]
+            k = 0
+            for y in l:
+                k = k | 1 << y
+            request.next = k
+            yield clk.posedge
+            request.next = 0
+            yield clk.posedge
+
+            # emulate round robin
+            l2 = [x for x in l if x < prev]
+            if len(l2) == 0:
+                l2 = l
+            g = max(l2)
+
+            assert grant == 1 << g
+            assert grant_encoded == g
+
+            prev = int(grant_encoded)
+
+            yield clk.posedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        print("test 3: two bits")
+        current_test.next = 3
+
+        for i in range(32):
+            for j in range(32):
+                l = [i, j]
+                k = 0
+                for y in l:
+                    k = k | 1 << y
+                request.next = k
+                yield clk.posedge
+                request.next = 0
+                yield clk.posedge
+
+                # emulate round robin
+                l2 = [x for x in l if x < prev]
+                if len(l2) == 0:
+                    l2 = l
+                g = max(l2)
+
+                assert grant == 1 << g
+                assert grant_encoded == g
+
+                prev = int(grant_encoded)
+
+                yield clk.posedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        print("test 4: five bits")
+        current_test.next = 4
+
+        for i in range(32):
+            l = [(i*x) % 32 for x in [1,2,3,4,5]]
+            k = 0
+            for y in l:
+                k = k | 1 << y
+            request.next = k
+            yield clk.posedge
+            request.next = 0
+            yield clk.posedge
+
+            # emulate round robin
+            l2 = [x for x in l if x < prev]
+            if len(l2) == 0:
+                l2 = l
+            g = max(l2)
+
+            assert grant == 1 << g
+            assert grant_encoded == g
+
+            prev = int(grant_encoded)
+
+            yield clk.posedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    os.chdir(os.path.dirname(os.path.abspath(__file__)))
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
+
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_arbiter_rr.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_arbiter_rr.v
new file mode 100644
index 0000000..31c8824
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_arbiter_rr.v
@@ -0,0 +1,87 @@
+/*
+
+Copyright (c) 2014-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for arbiter
+ */
+module test_arbiter_rr;
+
+// Parameters
+localparam PORTS = 32;
+localparam TYPE = "ROUND_ROBIN";
+localparam BLOCK = "REQUEST";
+
+// Inputs
+reg clk = 0;
+reg rst = 0;
+reg [7:0] current_test = 0;
+
+reg [PORTS-1:0] request = 0;
+reg [PORTS-1:0] acknowledge = 0;
+
+// Outputs
+wire [PORTS-1:0] grant;
+wire grant_valid;
+wire [$clog2(PORTS)-1:0] grant_encoded;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(
+        clk,
+        rst,
+        current_test,
+        request,
+        acknowledge
+    );
+    $to_myhdl(
+        grant,
+        grant_valid,
+        grant_encoded
+    );
+
+    // dump file
+    $dumpfile("test_arbiter_rr.lxt");
+    $dumpvars(0, test_arbiter_rr);
+end
+
+arbiter #(
+    .PORTS(PORTS),
+    .TYPE(TYPE),
+    .BLOCK(BLOCK)
+)
+UUT (
+    .clk(clk),
+    .rst(rst),
+    .request(request),
+    .acknowledge(acknowledge),
+    .grant(grant),
+    .grant_valid(grant_valid),
+    .grant_encoded(grant_encoded)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32.py
new file mode 100755
index 0000000..30d658d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32.py
@@ -0,0 +1,362 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+import struct
+
+import axis_ep
+import wb
+
+module = 'axis_wb_master'
+testbench = 'test_%s_8_32' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("%s.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    IMPLICIT_FRAMING = 0
+    COUNT_SIZE = 16
+    AXIS_DATA_WIDTH = 8
+    AXIS_KEEP_WIDTH = (AXIS_DATA_WIDTH/8)
+    WB_DATA_WIDTH = 32
+    WB_ADDR_WIDTH = 32
+    WB_SELECT_WIDTH = (WB_DATA_WIDTH/8)
+    READ_REQ = 0xA1
+    WRITE_REQ = 0xA2
+    READ_RESP = 0xA3
+    WRITE_RESP = 0xA4
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    input_axis_tdata = Signal(intbv(0)[AXIS_DATA_WIDTH:])
+    input_axis_tkeep = Signal(intbv(1)[AXIS_KEEP_WIDTH:])
+    input_axis_tvalid = Signal(bool(0))
+    input_axis_tlast = Signal(bool(0))
+    input_axis_tuser = Signal(bool(0))
+    output_axis_tready = Signal(bool(0))
+    wb_dat_i = Signal(intbv(0)[WB_DATA_WIDTH:])
+    wb_ack_i = Signal(bool(0))
+    wb_err_i = Signal(bool(0))
+
+    # Outputs
+    input_axis_tready = Signal(bool(0))
+    output_axis_tdata = Signal(intbv(0)[AXIS_DATA_WIDTH:])
+    output_axis_tkeep = Signal(intbv(1)[AXIS_KEEP_WIDTH:])
+    output_axis_tvalid = Signal(bool(0))
+    output_axis_tlast = Signal(bool(0))
+    output_axis_tuser = Signal(bool(0))
+    wb_adr_o = Signal(intbv(0)[WB_ADDR_WIDTH:])
+    wb_dat_o = Signal(intbv(0)[WB_DATA_WIDTH:])
+    wb_we_o = Signal(bool(0))
+    wb_sel_o = Signal(intbv(0)[WB_SELECT_WIDTH:])
+    wb_stb_o = Signal(bool(0))
+    wb_cyc_o = Signal(bool(0))
+    busy = Signal(bool(0))
+
+    # sources and sinks
+    source_pause = Signal(bool(0))
+    sink_pause = Signal(bool(0))
+
+    source = axis_ep.AXIStreamSource()
+
+    source_logic = source.create_logic(
+        clk,
+        rst,
+        tdata=input_axis_tdata,
+        tkeep=input_axis_tkeep,
+        tvalid=input_axis_tvalid,
+        tready=input_axis_tready,
+        tlast=input_axis_tlast,
+        tuser=input_axis_tuser,
+        pause=source_pause,
+        name='source'
+    )
+
+    sink = axis_ep.AXIStreamSink()
+
+    sink_logic = sink.create_logic(
+        clk,
+        rst,
+        tdata=output_axis_tdata,
+        tkeep=output_axis_tkeep,
+        tvalid=output_axis_tvalid,
+        tready=output_axis_tready,
+        tlast=output_axis_tlast,
+        tuser=output_axis_tuser,
+        pause=sink_pause,
+        name='sink'
+    )
+
+    # WB RAM model
+    wb_ram_inst = wb.WBRam(2**16)
+
+    wb_ram_port0 = wb_ram_inst.create_port(
+        clk,
+        adr_i=wb_adr_o,
+        dat_i=wb_dat_o,
+        dat_o=wb_dat_i,
+        we_i=wb_we_o,
+        sel_i=wb_sel_o,
+        stb_i=wb_stb_o,
+        ack_o=wb_ack_i,
+        cyc_i=wb_cyc_o,
+        latency=1,
+        asynchronous=False,
+        name='port0'
+    )
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        clk=clk,
+        rst=rst,
+        current_test=current_test,
+
+        input_axis_tdata=input_axis_tdata,
+        input_axis_tkeep=input_axis_tkeep,
+        input_axis_tvalid=input_axis_tvalid,
+        input_axis_tready=input_axis_tready,
+        input_axis_tlast=input_axis_tlast,
+        input_axis_tuser=input_axis_tuser,
+
+        output_axis_tdata=output_axis_tdata,
+        output_axis_tkeep=output_axis_tkeep,
+        output_axis_tvalid=output_axis_tvalid,
+        output_axis_tready=output_axis_tready,
+        output_axis_tlast=output_axis_tlast,
+        output_axis_tuser=output_axis_tuser,
+
+        wb_adr_o=wb_adr_o,
+        wb_dat_i=wb_dat_i,
+        wb_dat_o=wb_dat_o,
+        wb_we_o=wb_we_o,
+        wb_sel_o=wb_sel_o,
+        wb_stb_o=wb_stb_o,
+        wb_ack_i=wb_ack_i,
+        wb_err_i=wb_err_i,
+        wb_cyc_o=wb_cyc_o,
+
+        busy=busy
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        # testbench stimulus
+
+        yield clk.posedge
+        print("test 1: test write")
+        current_test.next = 1
+
+        source.write(bytearray(b'\xA2'+struct.pack('>IH', 0, 4)+b'\x11\x22\x33\x44'))
+        yield clk.posedge
+
+        yield input_axis_tvalid.negedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(0, 4) == b'\x11\x22\x33\x44'
+
+        rx_data = bytearray(sink.read())
+        print(repr(rx_data))
+        assert rx_data == b'\xA4'+struct.pack('>IH', 0, 4)
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 2: test read")
+        current_test.next = 2
+
+        source.write(bytearray(b'\xA1'+struct.pack('>IH', 0, 4)))
+        yield clk.posedge
+
+        yield input_axis_tvalid.negedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        rx_data = bytearray(sink.read())
+        print(repr(rx_data))
+        assert rx_data == b'\xA3'+struct.pack('>IH', 0, 4)+b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 3: various writes")
+        current_test.next = 3
+
+        for length in range(1,9):
+            for offset in range(4,8):
+                wb_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*16)
+                source.write(bytearray(b'\xA2'+struct.pack('>IH', 256*(16*offset+length)+offset, length)+b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]))
+                yield clk.posedge
+
+                yield input_axis_tvalid.negedge
+
+                yield delay(200)
+
+                yield clk.posedge
+
+                data = wb_ram_inst.read_mem(256*(16*offset+length), 32)
+                for i in range(0, len(data), 16):
+                    print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset-1, 1) == b'\xAA'
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset+length, 1) == b'\xAA'
+
+                rx_data = bytearray(sink.read())
+                print(repr(rx_data))
+                assert rx_data == b'\xA4'+struct.pack('>IH', 256*(16*offset+length)+offset, length)
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 4: various reads")
+        current_test.next = 4
+
+        for length in range(1,9):
+            for offset in range(4,8):
+                source.write(bytearray(b'\xA1'+struct.pack('>IH', 256*(16*offset+length)+offset, length)))
+                yield clk.posedge
+
+                yield input_axis_tvalid.negedge
+
+                yield delay(200)
+
+                yield clk.posedge
+
+                rx_data = bytearray(sink.read())
+                print(repr(rx_data))
+                assert rx_data == b'\xA3'+struct.pack('>IH', 256*(16*offset+length)+offset, length)+b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 5: test leading padding")
+        current_test.next = 5
+
+        source.write(bytearray(b'\xA2'+struct.pack('>IH', 4, 1)+b'\xAA'))
+        source.write(bytearray(b'\x00'*8+b'\xA2'+struct.pack('>IH', 5, 1)+b'\xBB'))
+        source.write(bytearray(b'\x00'*8+b'\xA1'+struct.pack('>IH', 4, 1)))
+        source.write(bytearray(b'\xA2'+struct.pack('>IH', 6, 1)+b'\xCC'))
+        yield clk.posedge
+
+        yield input_axis_tvalid.negedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(4, 3) == b'\xAA\x00\xCC'
+
+        rx_data = bytearray(sink.read())
+        print(repr(rx_data))
+        assert rx_data == b'\xA4'+struct.pack('>IH', 4, 1)+b'\xA4'+struct.pack('>IH', 6, 1)
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 6: test trailing padding")
+        current_test.next = 6
+
+        source.write(bytearray(b'\xA2'+struct.pack('>IH', 7, 1)+b'\xAA'))
+        source.write(bytearray(b'\xA2'+struct.pack('>IH', 8, 1)+b'\xBB'+b'\x00'*8))
+        source.write(bytearray(b'\xA1'+struct.pack('>IH', 7, 1)+b'\x00'*8))
+        source.write(bytearray(b'\xA1'+struct.pack('>IH', 7, 1)+b'\x00'*1))
+        source.write(bytearray(b'\xA2'+struct.pack('>IH', 9, 1)+b'\xCC'))
+        yield clk.posedge
+
+        yield input_axis_tvalid.negedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(7, 3) == b'\xAA\xBB\xCC'
+
+        rx_data = bytearray(sink.read())
+        print(repr(rx_data))
+        assert rx_data == b'\xA4'+struct.pack('>IH', 7, 1)+\
+                            b'\xA4'+struct.pack('>IH', 8, 1)+\
+                            b'\xA3'+struct.pack('>IH', 7, 1)+b'\xAA'+\
+                            b'\xA3'+struct.pack('>IH', 7, 1)+b'\xAA'+\
+                            b'\xA4'+struct.pack('>IH', 9, 1)
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32.v
new file mode 100644
index 0000000..934d19c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32.v
@@ -0,0 +1,154 @@
+/*
+
+Copyright (c) 2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for axis_wb_master
+ */
+module test_axis_wb_master_8_32;
+
+// Parameters
+parameter IMPLICIT_FRAMING = 0;
+parameter COUNT_SIZE = 16;
+parameter AXIS_DATA_WIDTH = 8;
+parameter AXIS_KEEP_WIDTH = (AXIS_DATA_WIDTH/8);
+parameter WB_DATA_WIDTH = 32;
+parameter WB_ADDR_WIDTH = 32;
+parameter WB_SELECT_WIDTH = (WB_DATA_WIDTH/8);
+parameter READ_REQ = 8'hA1;
+parameter WRITE_REQ = 8'hA2;
+parameter READ_RESP = 8'hA3;
+parameter WRITE_RESP = 8'hA4;
+
+// Inputs
+reg clk = 0;
+reg rst = 0;
+reg [7:0] current_test = 0;
+
+reg [AXIS_DATA_WIDTH-1:0] input_axis_tdata = 0;
+reg [AXIS_KEEP_WIDTH-1:0] input_axis_tkeep = 0;
+reg input_axis_tvalid = 0;
+reg input_axis_tlast = 0;
+reg input_axis_tuser = 0;
+reg output_axis_tready = 0;
+reg [WB_DATA_WIDTH-1:0] wb_dat_i = 0;
+reg wb_ack_i = 0;
+reg wb_err_i = 0;
+
+// Outputs
+wire input_axis_tready;
+wire [AXIS_DATA_WIDTH-1:0] output_axis_tdata;
+wire [AXIS_KEEP_WIDTH-1:0] output_axis_tkeep;
+wire output_axis_tvalid;
+wire output_axis_tlast;
+wire output_axis_tuser;
+wire [WB_ADDR_WIDTH-1:0] wb_adr_o;
+wire [WB_DATA_WIDTH-1:0] wb_dat_o;
+wire wb_we_o;
+wire [WB_SELECT_WIDTH-1:0] wb_sel_o;
+wire wb_stb_o;
+wire wb_cyc_o;
+wire busy;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(
+        clk,
+        rst,
+        current_test,
+        input_axis_tdata,
+        input_axis_tkeep,
+        input_axis_tvalid,
+        input_axis_tlast,
+        input_axis_tuser,
+        output_axis_tready,
+        wb_dat_i,
+        wb_ack_i,
+        wb_err_i
+    );
+    $to_myhdl(
+        input_axis_tready,
+        output_axis_tdata,
+        output_axis_tkeep,
+        output_axis_tvalid,
+        output_axis_tlast,
+        output_axis_tuser,
+        wb_adr_o,
+        wb_dat_o,
+        wb_we_o,
+        wb_sel_o,
+        wb_stb_o,
+        wb_cyc_o,
+        busy
+    );
+
+    // dump file
+    $dumpfile("test_axis_wb_master_8_32.lxt");
+    $dumpvars(0, test_axis_wb_master_8_32);
+end
+
+axis_wb_master #(
+    .IMPLICIT_FRAMING(IMPLICIT_FRAMING),
+    .COUNT_SIZE(COUNT_SIZE),
+    .AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
+    .AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
+    .WB_DATA_WIDTH(WB_DATA_WIDTH),
+    .WB_ADDR_WIDTH(WB_ADDR_WIDTH),
+    .WB_SELECT_WIDTH(WB_SELECT_WIDTH),
+    .READ_REQ(READ_REQ),
+    .WRITE_REQ(WRITE_REQ),
+    .READ_RESP(READ_RESP),
+    .WRITE_RESP(WRITE_RESP)
+)
+UUT (
+    .clk(clk),
+    .rst(rst),
+    .input_axis_tdata(input_axis_tdata),
+    .input_axis_tkeep(input_axis_tkeep),
+    .input_axis_tvalid(input_axis_tvalid),
+    .input_axis_tready(input_axis_tready),
+    .input_axis_tlast(input_axis_tlast),
+    .input_axis_tuser(input_axis_tuser),
+    .output_axis_tdata(output_axis_tdata),
+    .output_axis_tkeep(output_axis_tkeep),
+    .output_axis_tvalid(output_axis_tvalid),
+    .output_axis_tready(output_axis_tready),
+    .output_axis_tlast(output_axis_tlast),
+    .output_axis_tuser(output_axis_tuser),
+    .wb_adr_o(wb_adr_o),
+    .wb_dat_i(wb_dat_i),
+    .wb_dat_o(wb_dat_o),
+    .wb_we_o(wb_we_o),
+    .wb_sel_o(wb_sel_o),
+    .wb_stb_o(wb_stb_o),
+    .wb_ack_i(wb_ack_i),
+    .wb_err_i(wb_err_i),
+    .wb_cyc_o(wb_cyc_o),
+    .busy(busy)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32_16.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32_16.py
new file mode 100755
index 0000000..f98d260
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32_16.py
@@ -0,0 +1,362 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+import struct
+
+import axis_ep
+import wb
+
+module = 'axis_wb_master'
+testbench = 'test_%s_8_32_16' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("%s.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    IMPLICIT_FRAMING = 0
+    COUNT_SIZE = 16
+    AXIS_DATA_WIDTH = 8
+    AXIS_KEEP_WIDTH = (AXIS_DATA_WIDTH/8)
+    WB_DATA_WIDTH = 32
+    WB_ADDR_WIDTH = 31
+    WB_SELECT_WIDTH = 2
+    READ_REQ = 0xA1
+    WRITE_REQ = 0xA2
+    READ_RESP = 0xA3
+    WRITE_RESP = 0xA4
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    input_axis_tdata = Signal(intbv(0)[AXIS_DATA_WIDTH:])
+    input_axis_tkeep = Signal(intbv(1)[AXIS_KEEP_WIDTH:])
+    input_axis_tvalid = Signal(bool(0))
+    input_axis_tlast = Signal(bool(0))
+    input_axis_tuser = Signal(bool(0))
+    output_axis_tready = Signal(bool(0))
+    wb_dat_i = Signal(intbv(0)[WB_DATA_WIDTH:])
+    wb_ack_i = Signal(bool(0))
+    wb_err_i = Signal(bool(0))
+
+    # Outputs
+    input_axis_tready = Signal(bool(0))
+    output_axis_tdata = Signal(intbv(0)[AXIS_DATA_WIDTH:])
+    output_axis_tkeep = Signal(intbv(1)[AXIS_KEEP_WIDTH:])
+    output_axis_tvalid = Signal(bool(0))
+    output_axis_tlast = Signal(bool(0))
+    output_axis_tuser = Signal(bool(0))
+    wb_adr_o = Signal(intbv(0)[WB_ADDR_WIDTH:])
+    wb_dat_o = Signal(intbv(0)[WB_DATA_WIDTH:])
+    wb_we_o = Signal(bool(0))
+    wb_sel_o = Signal(intbv(0)[WB_SELECT_WIDTH:])
+    wb_stb_o = Signal(bool(0))
+    wb_cyc_o = Signal(bool(0))
+    busy = Signal(bool(0))
+
+    # sources and sinks
+    source_pause = Signal(bool(0))
+    sink_pause = Signal(bool(0))
+
+    source = axis_ep.AXIStreamSource()
+
+    source_logic = source.create_logic(
+        clk,
+        rst,
+        tdata=input_axis_tdata,
+        tkeep=input_axis_tkeep,
+        tvalid=input_axis_tvalid,
+        tready=input_axis_tready,
+        tlast=input_axis_tlast,
+        tuser=input_axis_tuser,
+        pause=source_pause,
+        name='source'
+    )
+
+    sink = axis_ep.AXIStreamSink()
+
+    sink_logic = sink.create_logic(
+        clk,
+        rst,
+        tdata=output_axis_tdata,
+        tkeep=output_axis_tkeep,
+        tvalid=output_axis_tvalid,
+        tready=output_axis_tready,
+        tlast=output_axis_tlast,
+        tuser=output_axis_tuser,
+        pause=sink_pause,
+        name='sink'
+    )
+
+    # WB RAM model
+    wb_ram_inst = wb.WBRam(2**16)
+
+    wb_ram_port0 = wb_ram_inst.create_port(
+        clk,
+        adr_i=wb_adr_o,
+        dat_i=wb_dat_o,
+        dat_o=wb_dat_i,
+        we_i=wb_we_o,
+        sel_i=wb_sel_o,
+        stb_i=wb_stb_o,
+        ack_o=wb_ack_i,
+        cyc_i=wb_cyc_o,
+        latency=1,
+        asynchronous=False,
+        name='port0'
+    )
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        clk=clk,
+        rst=rst,
+        current_test=current_test,
+
+        input_axis_tdata=input_axis_tdata,
+        input_axis_tkeep=input_axis_tkeep,
+        input_axis_tvalid=input_axis_tvalid,
+        input_axis_tready=input_axis_tready,
+        input_axis_tlast=input_axis_tlast,
+        input_axis_tuser=input_axis_tuser,
+
+        output_axis_tdata=output_axis_tdata,
+        output_axis_tkeep=output_axis_tkeep,
+        output_axis_tvalid=output_axis_tvalid,
+        output_axis_tready=output_axis_tready,
+        output_axis_tlast=output_axis_tlast,
+        output_axis_tuser=output_axis_tuser,
+
+        wb_adr_o=wb_adr_o,
+        wb_dat_i=wb_dat_i,
+        wb_dat_o=wb_dat_o,
+        wb_we_o=wb_we_o,
+        wb_sel_o=wb_sel_o,
+        wb_stb_o=wb_stb_o,
+        wb_ack_i=wb_ack_i,
+        wb_err_i=wb_err_i,
+        wb_cyc_o=wb_cyc_o,
+
+        busy=busy
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        # testbench stimulus
+
+        yield clk.posedge
+        print("test 1: test write")
+        current_test.next = 1
+
+        source.write(bytearray(b'\xA2'+struct.pack('>IH', 0, 4)+b'\x11\x22\x33\x44'))
+        yield clk.posedge
+
+        yield input_axis_tvalid.negedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(0, 4) == b'\x11\x22\x33\x44'
+
+        rx_data = bytearray(sink.read())
+        print(repr(rx_data))
+        assert rx_data == b'\xA4'+struct.pack('>IH', 0, 4)
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 2: test read")
+        current_test.next = 2
+
+        source.write(bytearray(b'\xA1'+struct.pack('>IH', 0, 4)))
+        yield clk.posedge
+
+        yield input_axis_tvalid.negedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        rx_data = bytearray(sink.read())
+        print(repr(rx_data))
+        assert rx_data == b'\xA3'+struct.pack('>IH', 0, 4)+b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 3: various writes")
+        current_test.next = 3
+
+        for length in range(1,9):
+            for offset in range(4,8):
+                wb_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*32)
+                source.write(bytearray(b'\xA2'+struct.pack('>IH', 256*(16*offset+length)+offset, length)+b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]))
+                yield clk.posedge
+
+                yield input_axis_tvalid.negedge
+
+                yield delay(200)
+
+                yield clk.posedge
+
+                data = wb_ram_inst.read_mem(256*(16*offset+length), 32)
+                for i in range(0, len(data), 16):
+                    print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset-2, 1) == b'\xAA'
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset+length+1, 1) == b'\xAA'
+
+                rx_data = bytearray(sink.read())
+                print(repr(rx_data))
+                assert rx_data == b'\xA4'+struct.pack('>IH', 256*(16*offset+length)+offset, length)
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 4: various reads")
+        current_test.next = 4
+
+        for length in range(1,9):
+            for offset in range(4,8):
+                source.write(bytearray(b'\xA1'+struct.pack('>IH', 256*(16*offset+length)+offset, length)))
+                yield clk.posedge
+
+                yield input_axis_tvalid.negedge
+
+                yield delay(200)
+
+                yield clk.posedge
+
+                rx_data = bytearray(sink.read())
+                print(repr(rx_data))
+                assert rx_data == b'\xA3'+struct.pack('>IH', 256*(16*offset+length)+offset, length)+b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 5: test leading padding")
+        current_test.next = 5
+
+        source.write(bytearray(b'\xA2'+struct.pack('>IH', 4, 2)+b'\xAA\xBB'))
+        source.write(bytearray(b'\x00'*8+b'\xA2'+struct.pack('>IH', 6, 2)+b'\xCC\xDD'))
+        source.write(bytearray(b'\x00'*8+b'\xA1'+struct.pack('>IH', 4, 2)))
+        source.write(bytearray(b'\xA2'+struct.pack('>IH', 8, 2)+b'\xEE\xFF'))
+        yield clk.posedge
+
+        yield input_axis_tvalid.negedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(4, 6) == b'\xAA\xBB\x00\x00\xEE\xFF'
+
+        rx_data = bytearray(sink.read())
+        print(repr(rx_data))
+        assert rx_data == b'\xA4'+struct.pack('>IH', 4, 2)+b'\xA4'+struct.pack('>IH', 8, 2)
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 6: test trailing padding")
+        current_test.next = 6
+
+        source.write(bytearray(b'\xA2'+struct.pack('>IH', 10, 2)+b'\xAA\xBB'))
+        source.write(bytearray(b'\xA2'+struct.pack('>IH', 12, 2)+b'\xCC\xDD'+b'\x00'*8))
+        source.write(bytearray(b'\xA1'+struct.pack('>IH', 10, 2)+b'\x00'*8))
+        source.write(bytearray(b'\xA1'+struct.pack('>IH', 10, 2)+b'\x00'*1))
+        source.write(bytearray(b'\xA2'+struct.pack('>IH', 14, 2)+b'\xEE\xFF'))
+        yield clk.posedge
+
+        yield input_axis_tvalid.negedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(10, 6) == b'\xAA\xBB\xCC\xDD\xEE\xFF'
+
+        rx_data = bytearray(sink.read())
+        print(repr(rx_data))
+        assert rx_data == b'\xA4'+struct.pack('>IH', 10, 2)+\
+                            b'\xA4'+struct.pack('>IH', 12, 2)+\
+                            b'\xA3'+struct.pack('>IH', 10, 2)+b'\xAA\xBB'+\
+                            b'\xA3'+struct.pack('>IH', 10, 2)+b'\xAA\xBB'+\
+                            b'\xA4'+struct.pack('>IH', 14, 2)
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32_16.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32_16.v
new file mode 100644
index 0000000..2f3fb60
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32_16.v
@@ -0,0 +1,154 @@
+/*
+
+Copyright (c) 2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for axis_wb_master
+ */
+module test_axis_wb_master_8_32_16;
+
+// Parameters
+parameter IMPLICIT_FRAMING = 0;
+parameter COUNT_SIZE = 16;
+parameter AXIS_DATA_WIDTH = 8;
+parameter AXIS_KEEP_WIDTH = (AXIS_DATA_WIDTH/8);
+parameter WB_DATA_WIDTH = 32;
+parameter WB_ADDR_WIDTH = 31;
+parameter WB_SELECT_WIDTH = 2;
+parameter READ_REQ = 8'hA1;
+parameter WRITE_REQ = 8'hA2;
+parameter READ_RESP = 8'hA3;
+parameter WRITE_RESP = 8'hA4;
+
+// Inputs
+reg clk = 0;
+reg rst = 0;
+reg [7:0] current_test = 0;
+
+reg [AXIS_DATA_WIDTH-1:0] input_axis_tdata = 0;
+reg [AXIS_KEEP_WIDTH-1:0] input_axis_tkeep = 0;
+reg input_axis_tvalid = 0;
+reg input_axis_tlast = 0;
+reg input_axis_tuser = 0;
+reg output_axis_tready = 0;
+reg [WB_DATA_WIDTH-1:0] wb_dat_i = 0;
+reg wb_ack_i = 0;
+reg wb_err_i = 0;
+
+// Outputs
+wire input_axis_tready;
+wire [AXIS_DATA_WIDTH-1:0] output_axis_tdata;
+wire [AXIS_KEEP_WIDTH-1:0] output_axis_tkeep;
+wire output_axis_tvalid;
+wire output_axis_tlast;
+wire output_axis_tuser;
+wire [WB_ADDR_WIDTH-1:0] wb_adr_o;
+wire [WB_DATA_WIDTH-1:0] wb_dat_o;
+wire wb_we_o;
+wire [WB_SELECT_WIDTH-1:0] wb_sel_o;
+wire wb_stb_o;
+wire wb_cyc_o;
+wire busy;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(
+        clk,
+        rst,
+        current_test,
+        input_axis_tdata,
+        input_axis_tkeep,
+        input_axis_tvalid,
+        input_axis_tlast,
+        input_axis_tuser,
+        output_axis_tready,
+        wb_dat_i,
+        wb_ack_i,
+        wb_err_i
+    );
+    $to_myhdl(
+        input_axis_tready,
+        output_axis_tdata,
+        output_axis_tkeep,
+        output_axis_tvalid,
+        output_axis_tlast,
+        output_axis_tuser,
+        wb_adr_o,
+        wb_dat_o,
+        wb_we_o,
+        wb_sel_o,
+        wb_stb_o,
+        wb_cyc_o,
+        busy
+    );
+
+    // dump file
+    $dumpfile("test_axis_wb_master_8_32_16.lxt");
+    $dumpvars(0, test_axis_wb_master_8_32_16);
+end
+
+axis_wb_master #(
+    .IMPLICIT_FRAMING(IMPLICIT_FRAMING),
+    .COUNT_SIZE(COUNT_SIZE),
+    .AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
+    .AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
+    .WB_DATA_WIDTH(WB_DATA_WIDTH),
+    .WB_ADDR_WIDTH(WB_ADDR_WIDTH),
+    .WB_SELECT_WIDTH(WB_SELECT_WIDTH),
+    .READ_REQ(READ_REQ),
+    .WRITE_REQ(WRITE_REQ),
+    .READ_RESP(READ_RESP),
+    .WRITE_RESP(WRITE_RESP)
+)
+UUT (
+    .clk(clk),
+    .rst(rst),
+    .input_axis_tdata(input_axis_tdata),
+    .input_axis_tkeep(input_axis_tkeep),
+    .input_axis_tvalid(input_axis_tvalid),
+    .input_axis_tready(input_axis_tready),
+    .input_axis_tlast(input_axis_tlast),
+    .input_axis_tuser(input_axis_tuser),
+    .output_axis_tdata(output_axis_tdata),
+    .output_axis_tkeep(output_axis_tkeep),
+    .output_axis_tvalid(output_axis_tvalid),
+    .output_axis_tready(output_axis_tready),
+    .output_axis_tlast(output_axis_tlast),
+    .output_axis_tuser(output_axis_tuser),
+    .wb_adr_o(wb_adr_o),
+    .wb_dat_i(wb_dat_i),
+    .wb_dat_o(wb_dat_o),
+    .wb_we_o(wb_we_o),
+    .wb_sel_o(wb_sel_o),
+    .wb_stb_o(wb_stb_o),
+    .wb_ack_i(wb_ack_i),
+    .wb_err_i(wb_err_i),
+    .wb_cyc_o(wb_cyc_o),
+    .busy(busy)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32_imp.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32_imp.py
new file mode 100755
index 0000000..b0b8b42
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32_imp.py
@@ -0,0 +1,357 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+import struct
+
+import axis_ep
+import wb
+
+module = 'axis_wb_master'
+testbench = 'test_%s_8_32_imp' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("%s.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    IMPLICIT_FRAMING = 0
+    COUNT_SIZE = 16
+    AXIS_DATA_WIDTH = 8
+    AXIS_KEEP_WIDTH = (AXIS_DATA_WIDTH/8)
+    WB_DATA_WIDTH = 32
+    WB_ADDR_WIDTH = 32
+    WB_SELECT_WIDTH = (WB_DATA_WIDTH/8)
+    READ_REQ = 0xA1
+    WRITE_REQ = 0xA2
+    READ_RESP = 0xA3
+    WRITE_RESP = 0xA4
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    input_axis_tdata = Signal(intbv(0)[AXIS_DATA_WIDTH:])
+    input_axis_tkeep = Signal(intbv(1)[AXIS_KEEP_WIDTH:])
+    input_axis_tvalid = Signal(bool(0))
+    input_axis_tlast = Signal(bool(0))
+    input_axis_tuser = Signal(bool(0))
+    output_axis_tready = Signal(bool(0))
+    wb_dat_i = Signal(intbv(0)[WB_DATA_WIDTH:])
+    wb_ack_i = Signal(bool(0))
+    wb_err_i = Signal(bool(0))
+
+    # Outputs
+    input_axis_tready = Signal(bool(0))
+    output_axis_tdata = Signal(intbv(0)[AXIS_DATA_WIDTH:])
+    output_axis_tkeep = Signal(intbv(1)[AXIS_KEEP_WIDTH:])
+    output_axis_tvalid = Signal(bool(0))
+    output_axis_tlast = Signal(bool(0))
+    output_axis_tuser = Signal(bool(0))
+    wb_adr_o = Signal(intbv(0)[WB_ADDR_WIDTH:])
+    wb_dat_o = Signal(intbv(0)[WB_DATA_WIDTH:])
+    wb_we_o = Signal(bool(0))
+    wb_sel_o = Signal(intbv(0)[WB_SELECT_WIDTH:])
+    wb_stb_o = Signal(bool(0))
+    wb_cyc_o = Signal(bool(0))
+    busy = Signal(bool(0))
+
+    # sources and sinks
+    source_pause = Signal(bool(0))
+    sink_pause = Signal(bool(0))
+
+    source = axis_ep.AXIStreamSource()
+
+    source_logic = source.create_logic(
+        clk,
+        rst,
+        tdata=input_axis_tdata,
+        tkeep=input_axis_tkeep,
+        tvalid=input_axis_tvalid,
+        tready=input_axis_tready,
+        tlast=input_axis_tlast,
+        tuser=input_axis_tuser,
+        pause=source_pause,
+        name='source'
+    )
+
+    sink = axis_ep.AXIStreamSink()
+
+    sink_logic = sink.create_logic(
+        clk,
+        rst,
+        tdata=output_axis_tdata,
+        tkeep=output_axis_tkeep,
+        tvalid=output_axis_tvalid,
+        tready=output_axis_tready,
+        tlast=output_axis_tlast,
+        tuser=output_axis_tuser,
+        pause=sink_pause,
+        name='sink'
+    )
+
+    # WB RAM model
+    wb_ram_inst = wb.WBRam(2**16)
+
+    wb_ram_port0 = wb_ram_inst.create_port(
+        clk,
+        adr_i=wb_adr_o,
+        dat_i=wb_dat_o,
+        dat_o=wb_dat_i,
+        we_i=wb_we_o,
+        sel_i=wb_sel_o,
+        stb_i=wb_stb_o,
+        ack_o=wb_ack_i,
+        cyc_i=wb_cyc_o,
+        latency=1,
+        asynchronous=False,
+        name='port0'
+    )
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        clk=clk,
+        rst=rst,
+        current_test=current_test,
+
+        input_axis_tdata=input_axis_tdata,
+        input_axis_tkeep=input_axis_tkeep,
+        input_axis_tvalid=input_axis_tvalid,
+        input_axis_tready=input_axis_tready,
+        input_axis_tlast=input_axis_tlast,
+        input_axis_tuser=input_axis_tuser,
+
+        output_axis_tdata=output_axis_tdata,
+        output_axis_tkeep=output_axis_tkeep,
+        output_axis_tvalid=output_axis_tvalid,
+        output_axis_tready=output_axis_tready,
+        output_axis_tlast=output_axis_tlast,
+        output_axis_tuser=output_axis_tuser,
+
+        wb_adr_o=wb_adr_o,
+        wb_dat_i=wb_dat_i,
+        wb_dat_o=wb_dat_o,
+        wb_we_o=wb_we_o,
+        wb_sel_o=wb_sel_o,
+        wb_stb_o=wb_stb_o,
+        wb_ack_i=wb_ack_i,
+        wb_err_i=wb_err_i,
+        wb_cyc_o=wb_cyc_o,
+
+        busy=busy
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        # testbench stimulus
+
+        yield clk.posedge
+        print("test 1: test write")
+        current_test.next = 1
+
+        source.send(bytearray(b'\xA2'+struct.pack('>IH', 0, 4)+b'\x11\x22\x33\x44'))
+        yield clk.posedge
+
+        yield input_axis_tvalid.negedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(0, 4) == b'\x11\x22\x33\x44'
+
+        rx_data = bytearray(sink.read())
+        print(repr(rx_data))
+        assert rx_data == b'\xA4'+struct.pack('>IH', 0, 4)
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 2: test read")
+        current_test.next = 2
+
+        source.send(bytearray(b'\xA1'+struct.pack('>IH', 0, 4)))
+        yield clk.posedge
+
+        yield input_axis_tvalid.negedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        rx_data = bytearray(sink.read())
+        print(repr(rx_data))
+        assert rx_data == b'\xA3'+struct.pack('>IH', 0, 4)+b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 3: various writes")
+        current_test.next = 3
+
+        for length in range(1,9):
+            for offset in range(4,8):
+                wb_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*16)
+                source.send(bytearray(b'\xA2'+struct.pack('>IH', 256*(16*offset+length)+offset, length)+b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]))
+                yield clk.posedge
+
+                yield input_axis_tvalid.negedge
+
+                yield delay(200)
+
+                yield clk.posedge
+
+                data = wb_ram_inst.read_mem(256*(16*offset+length), 32)
+                for i in range(0, len(data), 16):
+                    print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset-1, 1) == b'\xAA'
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset+length, 1) == b'\xAA'
+
+                rx_data = bytearray(sink.read())
+                print(repr(rx_data))
+                assert rx_data == b'\xA4'+struct.pack('>IH', 256*(16*offset+length)+offset, length)
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 4: various reads")
+        current_test.next = 4
+
+        for length in range(1,9):
+            for offset in range(4,8):
+                source.send(bytearray(b'\xA1'+struct.pack('>IH', 256*(16*offset+length)+offset, length)))
+                yield clk.posedge
+
+                yield input_axis_tvalid.negedge
+
+                yield delay(200)
+
+                yield clk.posedge
+
+                rx_data = bytearray(sink.read())
+                print(repr(rx_data))
+                assert rx_data == b'\xA3'+struct.pack('>IH', 256*(16*offset+length)+offset, length)+b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 5: test leading padding")
+        current_test.next = 5
+
+        source.send(bytearray(b'\xA2'+struct.pack('>IH', 4, 1)+b'\xAA'))
+        source.send(bytearray(b'\x00'*8+b'\xA2'+struct.pack('>IH', 5, 1)+b'\xBB'))
+        source.send(bytearray(b'\x00'*8+b'\xA1'+struct.pack('>IH', 4, 1)))
+        source.send(bytearray(b'\xA2'+struct.pack('>IH', 6, 1)+b'\xCC'))
+        yield clk.posedge
+
+        yield input_axis_tvalid.negedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(4, 3) == b'\xAA\xBB\xCC'
+
+        rx_data = bytearray(sink.read())
+        print(repr(rx_data))
+        assert rx_data == b'\xA4'+struct.pack('>IH', 4, 1)+b'\xA4'+struct.pack('>IH', 5, 1)+b'\xA3'+struct.pack('>IH', 4, 1)+b'\xAA'+b'\xA4'+struct.pack('>IH', 6, 1)
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 6: test trailing padding")
+        current_test.next = 6
+
+        source.send(bytearray(b'\xA2'+struct.pack('>IH', 7, 1)+b'\xAA'))
+        source.send(bytearray(b'\xA2'+struct.pack('>IH', 8, 1)+b'\xBB'+b'\x00'*8))
+        source.send(bytearray(b'\xA1'+struct.pack('>IH', 7, 1)+b'\x00'*8))
+        source.send(bytearray(b'\xA2'+struct.pack('>IH', 9, 1)+b'\xCC'))
+        yield clk.posedge
+
+        yield input_axis_tvalid.negedge
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(7, 3) == b'\xAA\xBB\xCC'
+
+        rx_data = bytearray(sink.read())
+        print(repr(rx_data))
+        assert rx_data == b'\xA4'+struct.pack('>IH', 7, 1)+b'\xA4'+struct.pack('>IH', 8, 1)+b'\xA3'+struct.pack('>IH', 7, 1)+b'\xAA'+b'\xA4'+struct.pack('>IH', 9, 1)
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32_imp.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32_imp.v
new file mode 100644
index 0000000..2ce0b2b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_axis_wb_master_8_32_imp.v
@@ -0,0 +1,154 @@
+/*
+
+Copyright (c) 2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for axis_wb_master
+ */
+module test_axis_wb_master_8_32_imp;
+
+// Parameters
+parameter IMPLICIT_FRAMING = 1;
+parameter COUNT_SIZE = 16;
+parameter AXIS_DATA_WIDTH = 8;
+parameter AXIS_KEEP_WIDTH = (AXIS_DATA_WIDTH/8);
+parameter WB_DATA_WIDTH = 32;
+parameter WB_ADDR_WIDTH = 32;
+parameter WB_SELECT_WIDTH = (WB_DATA_WIDTH/8);
+parameter READ_REQ = 8'hA1;
+parameter WRITE_REQ = 8'hA2;
+parameter READ_RESP = 8'hA3;
+parameter WRITE_RESP = 8'hA4;
+
+// Inputs
+reg clk = 0;
+reg rst = 0;
+reg [7:0] current_test = 0;
+
+reg [AXIS_DATA_WIDTH-1:0] input_axis_tdata = 0;
+reg [AXIS_KEEP_WIDTH-1:0] input_axis_tkeep = 0;
+reg input_axis_tvalid = 0;
+reg input_axis_tlast = 0;
+reg input_axis_tuser = 0;
+reg output_axis_tready = 0;
+reg [WB_DATA_WIDTH-1:0] wb_dat_i = 0;
+reg wb_ack_i = 0;
+reg wb_err_i = 0;
+
+// Outputs
+wire input_axis_tready;
+wire [AXIS_DATA_WIDTH-1:0] output_axis_tdata;
+wire [AXIS_KEEP_WIDTH-1:0] output_axis_tkeep;
+wire output_axis_tvalid;
+wire output_axis_tlast;
+wire output_axis_tuser;
+wire [WB_ADDR_WIDTH-1:0] wb_adr_o;
+wire [WB_DATA_WIDTH-1:0] wb_dat_o;
+wire wb_we_o;
+wire [WB_SELECT_WIDTH-1:0] wb_sel_o;
+wire wb_stb_o;
+wire wb_cyc_o;
+wire busy;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(
+        clk,
+        rst,
+        current_test,
+        input_axis_tdata,
+        input_axis_tkeep,
+        input_axis_tvalid,
+        input_axis_tlast,
+        input_axis_tuser,
+        output_axis_tready,
+        wb_dat_i,
+        wb_ack_i,
+        wb_err_i
+    );
+    $to_myhdl(
+        input_axis_tready,
+        output_axis_tdata,
+        output_axis_tkeep,
+        output_axis_tvalid,
+        output_axis_tlast,
+        output_axis_tuser,
+        wb_adr_o,
+        wb_dat_o,
+        wb_we_o,
+        wb_sel_o,
+        wb_stb_o,
+        wb_cyc_o,
+        busy
+    );
+
+    // dump file
+    $dumpfile("test_axis_wb_master_8_32_imp.lxt");
+    $dumpvars(0, test_axis_wb_master_8_32_imp);
+end
+
+axis_wb_master #(
+    .IMPLICIT_FRAMING(IMPLICIT_FRAMING),
+    .COUNT_SIZE(COUNT_SIZE),
+    .AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
+    .AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
+    .WB_DATA_WIDTH(WB_DATA_WIDTH),
+    .WB_ADDR_WIDTH(WB_ADDR_WIDTH),
+    .WB_SELECT_WIDTH(WB_SELECT_WIDTH),
+    .READ_REQ(READ_REQ),
+    .WRITE_REQ(WRITE_REQ),
+    .READ_RESP(READ_RESP),
+    .WRITE_RESP(WRITE_RESP)
+)
+UUT (
+    .clk(clk),
+    .rst(rst),
+    .input_axis_tdata(input_axis_tdata),
+    .input_axis_tkeep(input_axis_tkeep),
+    .input_axis_tvalid(input_axis_tvalid),
+    .input_axis_tready(input_axis_tready),
+    .input_axis_tlast(input_axis_tlast),
+    .input_axis_tuser(input_axis_tuser),
+    .output_axis_tdata(output_axis_tdata),
+    .output_axis_tkeep(output_axis_tkeep),
+    .output_axis_tvalid(output_axis_tvalid),
+    .output_axis_tready(output_axis_tready),
+    .output_axis_tlast(output_axis_tlast),
+    .output_axis_tuser(output_axis_tuser),
+    .wb_adr_o(wb_adr_o),
+    .wb_dat_i(wb_dat_i),
+    .wb_dat_o(wb_dat_o),
+    .wb_we_o(wb_we_o),
+    .wb_sel_o(wb_sel_o),
+    .wb_stb_o(wb_stb_o),
+    .wb_ack_i(wb_ack_i),
+    .wb_err_i(wb_err_i),
+    .wb_cyc_o(wb_cyc_o),
+    .busy(busy)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_priority_encoder.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_priority_encoder.py
new file mode 100755
index 0000000..747e96e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_priority_encoder.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2014-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+module = 'priority_encoder'
+testbench = 'test_%s' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("%s.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    WIDTH = 32
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    input_unencoded = Signal(intbv(0)[WIDTH:])
+
+    # Outputs
+    output_valid = Signal(bool(0))
+    output_encoded = Signal(intbv(0)[5:])
+    output_unencoded = Signal(intbv(0)[WIDTH:])
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        clk=clk,
+        rst=rst,
+        current_test=current_test,
+
+        input_unencoded=input_unencoded,
+
+        output_valid=output_valid,
+        output_encoded=output_encoded,
+        output_unencoded=output_unencoded
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        yield clk.posedge
+
+        print("test 1: one bit")
+        current_test.next = 1
+
+        for i in range(32):
+            input_unencoded.next = 1 << i
+
+            yield clk.posedge
+
+            assert output_encoded == i
+            assert output_unencoded == 1 << i
+
+        yield delay(100)
+
+        yield clk.posedge
+
+        print("test 2: two bits")
+        current_test.next = 2
+
+        for i in range(32):
+            for j in range(32):
+
+                input_unencoded.next = (1 << i) | (1 << j)
+
+                yield clk.posedge
+
+                assert output_encoded == max(i,j)
+                assert output_unencoded == 1 << max(i,j)
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    os.chdir(os.path.dirname(os.path.abspath(__file__)))
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
+
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_priority_encoder.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_priority_encoder.v
new file mode 100644
index 0000000..8d6787e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_priority_encoder.v
@@ -0,0 +1,78 @@
+/*
+
+Copyright (c) 2014-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for priority_encoder
+ */
+module test_priority_encoder;
+
+// Parameters
+localparam WIDTH = 32;
+
+// Inputs
+reg clk = 0;
+reg rst = 0;
+reg [7:0] current_test = 0;
+
+reg [WIDTH-1:0] input_unencoded = 0;
+
+// Outputs
+wire output_valid;
+wire [$clog2(WIDTH)-1:0] output_encoded;
+wire [WIDTH-1:0] output_unencoded;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(
+        clk,
+        rst,
+        current_test,
+        input_unencoded
+    );
+    $to_myhdl(
+        output_valid,
+        output_encoded,
+        output_unencoded
+    );
+
+    // dump file
+    $dumpfile("test_priority_encoder.lxt");
+    $dumpvars(0, test_priority_encoder);
+end
+
+priority_encoder #(
+    .WIDTH(WIDTH)
+)
+UUT (
+    .input_unencoded(input_unencoded),
+    .output_valid(output_valid),
+    .output_encoded(output_encoded),
+    .output_unencoded(output_unencoded)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb.py
new file mode 100755
index 0000000..ef3e62f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb.py
@@ -0,0 +1,257 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+import wb
+
+def bench():
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    port0_adr_i = Signal(intbv(0)[32:])
+    port0_dat_i = Signal(intbv(0)[32:])
+    port0_we_i = Signal(bool(0))
+    port0_sel_i = Signal(intbv(0)[4:])
+    port0_stb_i = Signal(bool(0))
+    port0_cyc_i = Signal(bool(0))
+
+    # Outputs
+    port0_dat_o = Signal(intbv(0)[32:])
+    port0_ack_o = Signal(bool(0))
+
+    # WB master
+    wb_master_inst = wb.WBMaster()
+
+    wb_master_logic = wb_master_inst.create_logic(
+        clk,
+        adr_o=port0_adr_i,
+        dat_i=port0_dat_o,
+        dat_o=port0_dat_i,
+        we_o=port0_we_i,
+        sel_o=port0_sel_i,
+        stb_o=port0_stb_i,
+        ack_i=port0_ack_o,
+        cyc_o=port0_cyc_i,
+        name='master'
+    )
+
+    # WB RAM model
+    wb_ram_inst = wb.WBRam(2**16)
+
+    wb_ram_port0 = wb_ram_inst.create_port(
+        clk,
+        adr_i=port0_adr_i,
+        dat_i=port0_dat_i,
+        dat_o=port0_dat_o,
+        we_i=port0_we_i,
+        sel_i=port0_sel_i,
+        stb_i=port0_stb_i,
+        ack_o=port0_ack_o,
+        cyc_i=port0_cyc_i,
+        latency=1,
+        asynchronous=False,
+        name='port0'
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        yield clk.posedge
+        print("test 1: baseline")
+        current_test.next = 1
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 2: direct write")
+        current_test.next = 2
+
+        wb_ram_inst.write_mem(0, b'test')
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(0,4) == b'test'
+
+        yield clk.posedge
+        print("test 3: write via port0")
+        current_test.next = 3
+
+        wb_master_inst.init_write(4, b'\x11\x22\x33\x44')
+
+        yield wb_master_inst.wait()
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(4,4) == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 4: read via port0")
+        current_test.next = 4
+
+        wb_master_inst.init_read(4, 4)
+
+        yield wb_master_inst.wait()
+        yield clk.posedge
+
+        data = wb_master_inst.get_read_data()
+        assert data[0] == 4
+        assert data[1] == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 5: various writes")
+        current_test.next = 5
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wb_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*32)
+                wb_master_inst.init_write(256*(16*offset+length)+offset, b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length])
+
+                yield wb_master_inst.wait()
+                yield clk.posedge
+
+                data = wb_ram_inst.read_mem(256*(16*offset+length), 32)
+                for i in range(0, len(data), 16):
+                    print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset-1, 1) == b'\xAA'
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset+length, 1) == b'\xAA'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 6: various reads")
+        current_test.next = 6
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wb_master_inst.init_read(256*(16*offset+length)+offset, length)
+
+                yield wb_master_inst.wait()
+                yield clk.posedge
+
+                data = wb_master_inst.get_read_data()
+                assert data[0] == 256*(16*offset+length)+offset
+                assert data[1] == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 7: write words")
+        current_test.next = 7
+
+        for offset in range(4):
+            wb_master_inst.init_write_words((0x4000+offset*64+0)/2+offset, [0x1234])
+            wb_master_inst.init_write_dwords((0x4000+offset*64+16)/4+offset, [0x12345678])
+            wb_master_inst.init_write_qwords((0x4000+offset*64+32)/8+offset, [0x1234567887654321])
+
+            yield wb_master_inst.wait()
+            yield clk.posedge
+
+            data = wb_ram_inst.read_mem(0x4000+offset*64, 64)
+            for i in range(0, len(data), 16):
+                print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+            assert wb_ram_inst.read_mem((0x4000+offset*64+0)+offset*2, 2) == b'\x34\x12'
+            assert wb_ram_inst.read_mem((0x4000+offset*64+16)+offset*4, 4) == b'\x78\x56\x34\x12'
+            assert wb_ram_inst.read_mem((0x4000+offset*64+32)+offset*8, 8) == b'\x21\x43\x65\x87\x78\x56\x34\x12'
+
+            assert wb_ram_inst.read_words((0x4000+offset*64+0)/2+offset, 1)[0] == 0x1234
+            assert wb_ram_inst.read_dwords((0x4000+offset*64+16)/4+offset, 1)[0] == 0x12345678
+            assert wb_ram_inst.read_qwords((0x4000+offset*64+32)/8+offset, 1)[0] == 0x1234567887654321
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 8: read words")
+        current_test.next = 8
+
+        for offset in range(4):
+            wb_master_inst.init_read_words((0x4000+offset*64+0)/2+offset, 1)
+            wb_master_inst.init_read_dwords((0x4000+offset*64+16)/4+offset, 1)
+            wb_master_inst.init_read_qwords((0x4000+offset*64+32)/8+offset, 1)
+
+            yield wb_master_inst.wait()
+            yield clk.posedge
+
+            data = wb_master_inst.get_read_data_words()
+            assert data[0] == (0x4000+offset*64+0)/2+offset
+            assert data[1][0] == 0x1234
+
+            data = wb_master_inst.get_read_data_dwords()
+            assert data[0] == (0x4000+offset*64+16)/4+offset
+            assert data[1][0] == 0x12345678
+
+            data = wb_master_inst.get_read_data_qwords()
+            assert data[0] == (0x4000+offset*64+32)/8+offset
+            assert data[1][0] == 0x1234567887654321
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    os.chdir(os.path.dirname(os.path.abspath(__file__)))
+    #sim = Simulation(bench())
+    traceSignals.name = os.path.basename(__file__).rsplit('.',1)[0]
+    sim = Simulation(traceSignals(bench))
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
+
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_16.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_16.py
new file mode 100755
index 0000000..8496d2a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_16.py
@@ -0,0 +1,257 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+import wb
+
+def bench():
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    port0_adr_i = Signal(intbv(0)[32:])
+    port0_dat_i = Signal(intbv(0)[32:])
+    port0_we_i = Signal(bool(0))
+    port0_sel_i = Signal(intbv(0)[2:])
+    port0_stb_i = Signal(bool(0))
+    port0_cyc_i = Signal(bool(0))
+
+    # Outputs
+    port0_dat_o = Signal(intbv(0)[32:])
+    port0_ack_o = Signal(bool(0))
+
+    # WB master
+    wb_master_inst = wb.WBMaster()
+
+    wb_master_logic = wb_master_inst.create_logic(
+        clk,
+        adr_o=port0_adr_i,
+        dat_i=port0_dat_o,
+        dat_o=port0_dat_i,
+        we_o=port0_we_i,
+        sel_o=port0_sel_i,
+        stb_o=port0_stb_i,
+        ack_i=port0_ack_o,
+        cyc_o=port0_cyc_i,
+        name='master'
+    )
+
+    # WB RAM model
+    wb_ram_inst = wb.WBRam(2**16)
+
+    wb_ram_port0 = wb_ram_inst.create_port(
+        clk,
+        adr_i=port0_adr_i,
+        dat_i=port0_dat_i,
+        dat_o=port0_dat_o,
+        we_i=port0_we_i,
+        sel_i=port0_sel_i,
+        stb_i=port0_stb_i,
+        ack_o=port0_ack_o,
+        cyc_i=port0_cyc_i,
+        latency=1,
+        asynchronous=False,
+        name='port0'
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        yield clk.posedge
+        print("test 1: baseline")
+        current_test.next = 1
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 2: direct write")
+        current_test.next = 2
+
+        wb_ram_inst.write_mem(0, b'test')
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(0,4) == b'test'
+
+        yield clk.posedge
+        print("test 3: write via port0")
+        current_test.next = 3
+
+        wb_master_inst.init_write(4, b'\x11\x22\x33\x44')
+
+        yield wb_master_inst.wait()
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(4,4) == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 4: read via port0")
+        current_test.next = 4
+
+        wb_master_inst.init_read(4, 4)
+
+        yield wb_master_inst.wait()
+        yield clk.posedge
+
+        data = wb_master_inst.get_read_data()
+        assert data[0] == 4
+        assert data[1] == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 5: various writes")
+        current_test.next = 5
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wb_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*32)
+                wb_master_inst.init_write(256*(16*offset+length)+offset, b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length])
+
+                yield wb_master_inst.wait()
+                yield clk.posedge
+
+                data = wb_ram_inst.read_mem(256*(16*offset+length), 32)
+                for i in range(0, len(data), 16):
+                    print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset-2, 1) == b'\xAA'
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset+length+1, 1) == b'\xAA'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 6: various reads")
+        current_test.next = 6
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wb_master_inst.init_read(256*(16*offset+length)+offset, length)
+
+                yield wb_master_inst.wait()
+                yield clk.posedge
+
+                data = wb_master_inst.get_read_data()
+                assert data[0] == 256*(16*offset+length)+offset
+                assert data[1] == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 7: write words")
+        current_test.next = 7
+
+        for offset in range(4):
+            wb_master_inst.init_write_words((0x4000+offset*64+0)/2+offset, [0x1234])
+            wb_master_inst.init_write_dwords((0x4000+offset*64+16)/4+offset, [0x12345678])
+            wb_master_inst.init_write_qwords((0x4000+offset*64+32)/8+offset, [0x1234567887654321])
+
+            yield wb_master_inst.wait()
+            yield clk.posedge
+
+            data = wb_ram_inst.read_mem(0x4000+offset*64, 64)
+            for i in range(0, len(data), 16):
+                print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+            assert wb_ram_inst.read_mem((0x4000+offset*64+0)+offset*2, 2) == b'\x34\x12'
+            assert wb_ram_inst.read_mem((0x4000+offset*64+16)+offset*4, 4) == b'\x78\x56\x34\x12'
+            assert wb_ram_inst.read_mem((0x4000+offset*64+32)+offset*8, 8) == b'\x21\x43\x65\x87\x78\x56\x34\x12'
+
+            assert wb_ram_inst.read_words((0x4000+offset*64+0)/2+offset, 1)[0] == 0x1234
+            assert wb_ram_inst.read_dwords((0x4000+offset*64+16)/4+offset, 1)[0] == 0x12345678
+            assert wb_ram_inst.read_qwords((0x4000+offset*64+32)/8+offset, 1)[0] == 0x1234567887654321
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 8: read words")
+        current_test.next = 8
+
+        for offset in range(4):
+            wb_master_inst.init_read_words((0x4000+offset*64+0)/2+offset, 1)
+            wb_master_inst.init_read_dwords((0x4000+offset*64+16)/4+offset, 1)
+            wb_master_inst.init_read_qwords((0x4000+offset*64+32)/8+offset, 1)
+
+            yield wb_master_inst.wait()
+            yield clk.posedge
+
+            data = wb_master_inst.get_read_data_words()
+            assert data[0] == (0x4000+offset*64+0)/2+offset
+            assert data[1][0] == 0x1234
+
+            data = wb_master_inst.get_read_data_dwords()
+            assert data[0] == (0x4000+offset*64+16)/4+offset
+            assert data[1][0] == 0x12345678
+
+            data = wb_master_inst.get_read_data_qwords()
+            assert data[0] == (0x4000+offset*64+32)/8+offset
+            assert data[1][0] == 0x1234567887654321
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    os.chdir(os.path.dirname(os.path.abspath(__file__)))
+    #sim = Simulation(bench())
+    traceSignals.name = os.path.basename(__file__).rsplit('.',1)[0]
+    sim = Simulation(traceSignals(bench))
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
+
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_16_32.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_16_32.py
new file mode 100755
index 0000000..3b32b46
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_16_32.py
@@ -0,0 +1,242 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+import wb
+
+module = 'wb_adapter'
+testbench = 'test_%s_16_32' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("../rtl/priority_encoder.v")
+srcs.append("%s.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    ADDR_WIDTH = 32
+    WBM_DATA_WIDTH = 16
+    WBM_SELECT_WIDTH = 2
+    WBS_DATA_WIDTH = 32
+    WBS_SELECT_WIDTH = 4
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    wbm_adr_i = Signal(intbv(0)[ADDR_WIDTH:])
+    wbm_dat_i = Signal(intbv(0)[WBM_DATA_WIDTH:])
+    wbm_we_i = Signal(bool(0))
+    wbm_sel_i = Signal(intbv(0)[WBM_SELECT_WIDTH:])
+    wbm_stb_i = Signal(bool(0))
+    wbm_cyc_i = Signal(bool(0))
+    wbs_dat_i = Signal(intbv(0)[WBS_DATA_WIDTH:])
+    wbs_ack_i = Signal(bool(0))
+    wbs_err_i = Signal(bool(0))
+    wbs_rty_i = Signal(bool(0))
+
+    # Outputs
+    wbm_dat_o = Signal(intbv(0)[WBM_DATA_WIDTH:])
+    wbm_ack_o = Signal(bool(0))
+    wbm_err_o = Signal(bool(0))
+    wbm_rty_o = Signal(bool(0))
+    wbs_adr_o = Signal(intbv(0)[ADDR_WIDTH:])
+    wbs_dat_o = Signal(intbv(0)[WBS_DATA_WIDTH:])
+    wbs_we_o = Signal(bool(0))
+    wbs_sel_o = Signal(intbv(0)[WBS_SELECT_WIDTH:])
+    wbs_stb_o = Signal(bool(0))
+    wbs_cyc_o = Signal(bool(0))
+
+    # WB master
+    wbm_inst = wb.WBMaster()
+
+    wbm_logic = wbm_inst.create_logic(
+        clk,
+        adr_o=wbm_adr_i,
+        dat_i=wbm_dat_o,
+        dat_o=wbm_dat_i,
+        we_o=wbm_we_i,
+        sel_o=wbm_sel_i,
+        stb_o=wbm_stb_i,
+        ack_i=wbm_ack_o,
+        cyc_o=wbm_cyc_i,
+        name='master'
+    )
+
+    # WB RAM model
+    wb_ram_inst = wb.WBRam(2**16)
+
+    wb_ram_port0 = wb_ram_inst.create_port(
+        clk,
+        adr_i=wbs_adr_o,
+        dat_i=wbs_dat_o,
+        dat_o=wbs_dat_i,
+        we_i=wbs_we_o,
+        sel_i=wbs_sel_o,
+        stb_i=wbs_stb_o,
+        ack_o=wbs_ack_i,
+        cyc_i=wbs_cyc_o,
+        latency=1,
+        asynchronous=False,
+        name='slave'
+    )
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        clk=clk,
+        rst=rst,
+        current_test=current_test,
+        wbm_adr_i=wbm_adr_i,
+        wbm_dat_i=wbm_dat_i,
+        wbm_dat_o=wbm_dat_o,
+        wbm_we_i=wbm_we_i,
+        wbm_sel_i=wbm_sel_i,
+        wbm_stb_i=wbm_stb_i,
+        wbm_ack_o=wbm_ack_o,
+        wbm_err_o=wbm_err_o,
+        wbm_rty_o=wbm_rty_o,
+        wbm_cyc_i=wbm_cyc_i,
+        wbs_adr_o=wbs_adr_o,
+        wbs_dat_i=wbs_dat_i,
+        wbs_dat_o=wbs_dat_o,
+        wbs_we_o=wbs_we_o,
+        wbs_sel_o=wbs_sel_o,
+        wbs_stb_o=wbs_stb_o,
+        wbs_ack_i=wbs_ack_i,
+        wbs_err_i=wbs_err_i,
+        wbs_rty_i=wbs_rty_i,
+        wbs_cyc_o=wbs_cyc_o
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        yield clk.posedge
+        print("test 1: write")
+        current_test.next = 1
+
+        wbm_inst.init_write(4, b'\x11\x22\x33\x44')
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(4,4) == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 2: read")
+        current_test.next = 2
+
+        wbm_inst.init_read(4, 4)
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        data = wbm_inst.get_read_data()
+        assert data[0] == 4
+        assert data[1] == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 3: various writes")
+        current_test.next = 3
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wb_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*32)
+                wbm_inst.init_write(256*(16*offset+length)+offset, b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length])
+
+                yield wbm_inst.wait()
+                yield clk.posedge
+
+                data = wb_ram_inst.read_mem(256*(16*offset+length), 32)
+                for i in range(0, len(data), 16):
+                    print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset-1, 1) == b'\xAA'
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset+length, 1) == b'\xAA'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 4: various reads")
+        current_test.next = 4
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wbm_inst.init_read(256*(16*offset+length)+offset, length)
+
+                yield wbm_inst.wait()
+                yield clk.posedge
+
+                data = wbm_inst.get_read_data()
+                assert data[0] == 256*(16*offset+length)+offset
+                assert data[1] == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_16_32.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_16_32.v
new file mode 100644
index 0000000..cb658f8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_16_32.v
@@ -0,0 +1,136 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for wb_adapter
+ */
+module test_wb_adapter_16_32;
+
+// Parameters
+parameter ADDR_WIDTH = 32;
+parameter WBM_DATA_WIDTH = 16;
+parameter WBM_SELECT_WIDTH = 2;
+parameter WBS_DATA_WIDTH = 32;
+parameter WBS_SELECT_WIDTH = 4;
+
+// Inputs
+reg clk = 0;
+reg rst = 0;
+reg [7:0] current_test = 0;
+
+reg [ADDR_WIDTH-1:0] wbm_adr_i = 0;
+reg [WBM_DATA_WIDTH-1:0] wbm_dat_i = 0;
+reg wbm_we_i = 0;
+reg [WBM_SELECT_WIDTH-1:0] wbm_sel_i = 0;
+reg wbm_stb_i = 0;
+reg wbm_cyc_i = 0;
+reg [WBS_DATA_WIDTH-1:0] wbs_dat_i = 0;
+reg wbs_ack_i = 0;
+reg wbs_err_i = 0;
+reg wbs_rty_i = 0;
+
+// Outputs
+wire [WBM_DATA_WIDTH-1:0] wbm_dat_o;
+wire wbm_ack_o;
+wire wbm_err_o;
+wire wbm_rty_o;
+wire [ADDR_WIDTH-1:0] wbs_adr_o;
+wire [WBS_DATA_WIDTH-1:0] wbs_dat_o;
+wire wbs_we_o;
+wire [WBS_SELECT_WIDTH-1:0] wbs_sel_o;
+wire wbs_stb_o;
+wire wbs_cyc_o;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(
+        clk,
+        rst,
+        current_test,
+        wbm_adr_i,
+        wbm_dat_i,
+        wbm_we_i,
+        wbm_sel_i,
+        wbm_stb_i,
+        wbm_cyc_i,
+        wbs_dat_i,
+        wbs_ack_i,
+        wbs_err_i,
+        wbs_rty_i
+    );
+    $to_myhdl(
+        wbm_dat_o,
+        wbm_ack_o,
+        wbm_err_o,
+        wbm_rty_o,
+        wbs_adr_o,
+        wbs_dat_o,
+        wbs_we_o,
+        wbs_sel_o,
+        wbs_stb_o,
+        wbs_cyc_o
+    );
+
+    // dump file
+    $dumpfile("test_wb_adapter_16_32.lxt");
+    $dumpvars(0, test_wb_adapter_16_32);
+end
+
+wb_adapter #(
+    .ADDR_WIDTH(ADDR_WIDTH),
+    .WBM_DATA_WIDTH(WBM_DATA_WIDTH),
+    .WBM_SELECT_WIDTH(WBM_SELECT_WIDTH),
+    .WBS_DATA_WIDTH(WBS_DATA_WIDTH),
+    .WBS_SELECT_WIDTH(WBS_SELECT_WIDTH)
+)
+UUT (
+    .clk(clk),
+    .rst(rst),
+    .wbm_adr_i(wbm_adr_i),
+    .wbm_dat_i(wbm_dat_i),
+    .wbm_dat_o(wbm_dat_o),
+    .wbm_we_i(wbm_we_i),
+    .wbm_sel_i(wbm_sel_i),
+    .wbm_stb_i(wbm_stb_i),
+    .wbm_ack_o(wbm_ack_o),
+    .wbm_err_o(wbm_err_o),
+    .wbm_rty_o(wbm_rty_o),
+    .wbm_cyc_i(wbm_cyc_i),
+    .wbs_adr_o(wbs_adr_o),
+    .wbs_dat_i(wbs_dat_i),
+    .wbs_dat_o(wbs_dat_o),
+    .wbs_we_o(wbs_we_o),
+    .wbs_sel_o(wbs_sel_o),
+    .wbs_stb_o(wbs_stb_o),
+    .wbs_ack_i(wbs_ack_i),
+    .wbs_err_i(wbs_err_i),
+    .wbs_rty_i(wbs_rty_i),
+    .wbs_cyc_o(wbs_cyc_o)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_32_16.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_32_16.py
new file mode 100755
index 0000000..a2cb1b1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_32_16.py
@@ -0,0 +1,242 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+import wb
+
+module = 'wb_adapter'
+testbench = 'test_%s_32_16' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("../rtl/priority_encoder.v")
+srcs.append("%s.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    ADDR_WIDTH = 32
+    WBM_DATA_WIDTH = 32
+    WBM_SELECT_WIDTH = 4
+    WBS_DATA_WIDTH = 16
+    WBS_SELECT_WIDTH = 2
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    wbm_adr_i = Signal(intbv(0)[ADDR_WIDTH:])
+    wbm_dat_i = Signal(intbv(0)[WBM_DATA_WIDTH:])
+    wbm_we_i = Signal(bool(0))
+    wbm_sel_i = Signal(intbv(0)[WBM_SELECT_WIDTH:])
+    wbm_stb_i = Signal(bool(0))
+    wbm_cyc_i = Signal(bool(0))
+    wbs_dat_i = Signal(intbv(0)[WBS_DATA_WIDTH:])
+    wbs_ack_i = Signal(bool(0))
+    wbs_err_i = Signal(bool(0))
+    wbs_rty_i = Signal(bool(0))
+
+    # Outputs
+    wbm_dat_o = Signal(intbv(0)[WBM_DATA_WIDTH:])
+    wbm_ack_o = Signal(bool(0))
+    wbm_err_o = Signal(bool(0))
+    wbm_rty_o = Signal(bool(0))
+    wbs_adr_o = Signal(intbv(0)[ADDR_WIDTH:])
+    wbs_dat_o = Signal(intbv(0)[WBS_DATA_WIDTH:])
+    wbs_we_o = Signal(bool(0))
+    wbs_sel_o = Signal(intbv(0)[WBS_SELECT_WIDTH:])
+    wbs_stb_o = Signal(bool(0))
+    wbs_cyc_o = Signal(bool(0))
+
+    # WB master
+    wbm_inst = wb.WBMaster()
+
+    wbm_logic = wbm_inst.create_logic(
+        clk,
+        adr_o=wbm_adr_i,
+        dat_i=wbm_dat_o,
+        dat_o=wbm_dat_i,
+        we_o=wbm_we_i,
+        sel_o=wbm_sel_i,
+        stb_o=wbm_stb_i,
+        ack_i=wbm_ack_o,
+        cyc_o=wbm_cyc_i,
+        name='master'
+    )
+
+    # WB RAM model
+    wb_ram_inst = wb.WBRam(2**16)
+
+    wb_ram_port0 = wb_ram_inst.create_port(
+        clk,
+        adr_i=wbs_adr_o,
+        dat_i=wbs_dat_o,
+        dat_o=wbs_dat_i,
+        we_i=wbs_we_o,
+        sel_i=wbs_sel_o,
+        stb_i=wbs_stb_o,
+        ack_o=wbs_ack_i,
+        cyc_i=wbs_cyc_o,
+        latency=1,
+        asynchronous=False,
+        name='slave'
+    )
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        clk=clk,
+        rst=rst,
+        current_test=current_test,
+        wbm_adr_i=wbm_adr_i,
+        wbm_dat_i=wbm_dat_i,
+        wbm_dat_o=wbm_dat_o,
+        wbm_we_i=wbm_we_i,
+        wbm_sel_i=wbm_sel_i,
+        wbm_stb_i=wbm_stb_i,
+        wbm_ack_o=wbm_ack_o,
+        wbm_err_o=wbm_err_o,
+        wbm_rty_o=wbm_rty_o,
+        wbm_cyc_i=wbm_cyc_i,
+        wbs_adr_o=wbs_adr_o,
+        wbs_dat_i=wbs_dat_i,
+        wbs_dat_o=wbs_dat_o,
+        wbs_we_o=wbs_we_o,
+        wbs_sel_o=wbs_sel_o,
+        wbs_stb_o=wbs_stb_o,
+        wbs_ack_i=wbs_ack_i,
+        wbs_err_i=wbs_err_i,
+        wbs_rty_i=wbs_rty_i,
+        wbs_cyc_o=wbs_cyc_o
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        yield clk.posedge
+        print("test 1: write")
+        current_test.next = 1
+
+        wbm_inst.init_write(4, b'\x11\x22\x33\x44')
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(4,4) == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 2: read")
+        current_test.next = 2
+
+        wbm_inst.init_read(4, 4)
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        data = wbm_inst.get_read_data()
+        assert data[0] == 4
+        assert data[1] == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 3: various writes")
+        current_test.next = 3
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wb_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*32)
+                wbm_inst.init_write(256*(16*offset+length)+offset, b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length])
+
+                yield wbm_inst.wait()
+                yield clk.posedge
+
+                data = wb_ram_inst.read_mem(256*(16*offset+length), 32)
+                for i in range(0, len(data), 16):
+                    print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset-1, 1) == b'\xAA'
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset+length, 1) == b'\xAA'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 4: various reads")
+        current_test.next = 4
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wbm_inst.init_read(256*(16*offset+length)+offset, length)
+
+                yield wbm_inst.wait()
+                yield clk.posedge
+
+                data = wbm_inst.get_read_data()
+                assert data[0] == 256*(16*offset+length)+offset
+                assert data[1] == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_32_16.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_32_16.v
new file mode 100644
index 0000000..9267962
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_32_16.v
@@ -0,0 +1,136 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for wb_adapter
+ */
+module test_wb_adapter_32_16;
+
+// Parameters
+parameter ADDR_WIDTH = 32;
+parameter WBM_DATA_WIDTH = 32;
+parameter WBM_SELECT_WIDTH = 4;
+parameter WBS_DATA_WIDTH = 16;
+parameter WBS_SELECT_WIDTH = 2;
+
+// Inputs
+reg clk = 0;
+reg rst = 0;
+reg [7:0] current_test = 0;
+
+reg [ADDR_WIDTH-1:0] wbm_adr_i = 0;
+reg [WBM_DATA_WIDTH-1:0] wbm_dat_i = 0;
+reg wbm_we_i = 0;
+reg [WBM_SELECT_WIDTH-1:0] wbm_sel_i = 0;
+reg wbm_stb_i = 0;
+reg wbm_cyc_i = 0;
+reg [WBS_DATA_WIDTH-1:0] wbs_dat_i = 0;
+reg wbs_ack_i = 0;
+reg wbs_err_i = 0;
+reg wbs_rty_i = 0;
+
+// Outputs
+wire [WBM_DATA_WIDTH-1:0] wbm_dat_o;
+wire wbm_ack_o;
+wire wbm_err_o;
+wire wbm_rty_o;
+wire [ADDR_WIDTH-1:0] wbs_adr_o;
+wire [WBS_DATA_WIDTH-1:0] wbs_dat_o;
+wire wbs_we_o;
+wire [WBS_SELECT_WIDTH-1:0] wbs_sel_o;
+wire wbs_stb_o;
+wire wbs_cyc_o;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(
+        clk,
+        rst,
+        current_test,
+        wbm_adr_i,
+        wbm_dat_i,
+        wbm_we_i,
+        wbm_sel_i,
+        wbm_stb_i,
+        wbm_cyc_i,
+        wbs_dat_i,
+        wbs_ack_i,
+        wbs_err_i,
+        wbs_rty_i
+    );
+    $to_myhdl(
+        wbm_dat_o,
+        wbm_ack_o,
+        wbm_err_o,
+        wbm_rty_o,
+        wbs_adr_o,
+        wbs_dat_o,
+        wbs_we_o,
+        wbs_sel_o,
+        wbs_stb_o,
+        wbs_cyc_o
+    );
+
+    // dump file
+    $dumpfile("test_wb_adapter_32_16.lxt");
+    $dumpvars(0, test_wb_adapter_32_16);
+end
+
+wb_adapter #(
+    .ADDR_WIDTH(ADDR_WIDTH),
+    .WBM_DATA_WIDTH(WBM_DATA_WIDTH),
+    .WBM_SELECT_WIDTH(WBM_SELECT_WIDTH),
+    .WBS_DATA_WIDTH(WBS_DATA_WIDTH),
+    .WBS_SELECT_WIDTH(WBS_SELECT_WIDTH)
+)
+UUT (
+    .clk(clk),
+    .rst(rst),
+    .wbm_adr_i(wbm_adr_i),
+    .wbm_dat_i(wbm_dat_i),
+    .wbm_dat_o(wbm_dat_o),
+    .wbm_we_i(wbm_we_i),
+    .wbm_sel_i(wbm_sel_i),
+    .wbm_stb_i(wbm_stb_i),
+    .wbm_ack_o(wbm_ack_o),
+    .wbm_err_o(wbm_err_o),
+    .wbm_rty_o(wbm_rty_o),
+    .wbm_cyc_i(wbm_cyc_i),
+    .wbs_adr_o(wbs_adr_o),
+    .wbs_dat_i(wbs_dat_i),
+    .wbs_dat_o(wbs_dat_o),
+    .wbs_we_o(wbs_we_o),
+    .wbs_sel_o(wbs_sel_o),
+    .wbs_stb_o(wbs_stb_o),
+    .wbs_ack_i(wbs_ack_i),
+    .wbs_err_i(wbs_err_i),
+    .wbs_rty_i(wbs_rty_i),
+    .wbs_cyc_o(wbs_cyc_o)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_32_8.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_32_8.py
new file mode 100755
index 0000000..c03b030
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_32_8.py
@@ -0,0 +1,242 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+import wb
+
+module = 'wb_adapter'
+testbench = 'test_%s_32_8' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("../rtl/priority_encoder.v")
+srcs.append("%s.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    ADDR_WIDTH = 32
+    WBM_DATA_WIDTH = 32
+    WBM_SELECT_WIDTH = 4
+    WBS_DATA_WIDTH = 8
+    WBS_SELECT_WIDTH = 1
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    wbm_adr_i = Signal(intbv(0)[ADDR_WIDTH:])
+    wbm_dat_i = Signal(intbv(0)[WBM_DATA_WIDTH:])
+    wbm_we_i = Signal(bool(0))
+    wbm_sel_i = Signal(intbv(0)[WBM_SELECT_WIDTH:])
+    wbm_stb_i = Signal(bool(0))
+    wbm_cyc_i = Signal(bool(0))
+    wbs_dat_i = Signal(intbv(0)[WBS_DATA_WIDTH:])
+    wbs_ack_i = Signal(bool(0))
+    wbs_err_i = Signal(bool(0))
+    wbs_rty_i = Signal(bool(0))
+
+    # Outputs
+    wbm_dat_o = Signal(intbv(0)[WBM_DATA_WIDTH:])
+    wbm_ack_o = Signal(bool(0))
+    wbm_err_o = Signal(bool(0))
+    wbm_rty_o = Signal(bool(0))
+    wbs_adr_o = Signal(intbv(0)[ADDR_WIDTH:])
+    wbs_dat_o = Signal(intbv(0)[WBS_DATA_WIDTH:])
+    wbs_we_o = Signal(bool(0))
+    wbs_sel_o = Signal(intbv(0)[WBS_SELECT_WIDTH:])
+    wbs_stb_o = Signal(bool(0))
+    wbs_cyc_o = Signal(bool(0))
+
+    # WB master
+    wbm_inst = wb.WBMaster()
+
+    wbm_logic = wbm_inst.create_logic(
+        clk,
+        adr_o=wbm_adr_i,
+        dat_i=wbm_dat_o,
+        dat_o=wbm_dat_i,
+        we_o=wbm_we_i,
+        sel_o=wbm_sel_i,
+        stb_o=wbm_stb_i,
+        ack_i=wbm_ack_o,
+        cyc_o=wbm_cyc_i,
+        name='master'
+    )
+
+    # WB RAM model
+    wb_ram_inst = wb.WBRam(2**16)
+
+    wb_ram_port0 = wb_ram_inst.create_port(
+        clk,
+        adr_i=wbs_adr_o,
+        dat_i=wbs_dat_o,
+        dat_o=wbs_dat_i,
+        we_i=wbs_we_o,
+        sel_i=wbs_sel_o,
+        stb_i=wbs_stb_o,
+        ack_o=wbs_ack_i,
+        cyc_i=wbs_cyc_o,
+        latency=1,
+        asynchronous=False,
+        name='slave'
+    )
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        clk=clk,
+        rst=rst,
+        current_test=current_test,
+        wbm_adr_i=wbm_adr_i,
+        wbm_dat_i=wbm_dat_i,
+        wbm_dat_o=wbm_dat_o,
+        wbm_we_i=wbm_we_i,
+        wbm_sel_i=wbm_sel_i,
+        wbm_stb_i=wbm_stb_i,
+        wbm_ack_o=wbm_ack_o,
+        wbm_err_o=wbm_err_o,
+        wbm_rty_o=wbm_rty_o,
+        wbm_cyc_i=wbm_cyc_i,
+        wbs_adr_o=wbs_adr_o,
+        wbs_dat_i=wbs_dat_i,
+        wbs_dat_o=wbs_dat_o,
+        wbs_we_o=wbs_we_o,
+        wbs_sel_o=wbs_sel_o,
+        wbs_stb_o=wbs_stb_o,
+        wbs_ack_i=wbs_ack_i,
+        wbs_err_i=wbs_err_i,
+        wbs_rty_i=wbs_rty_i,
+        wbs_cyc_o=wbs_cyc_o
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        yield clk.posedge
+        print("test 1: write")
+        current_test.next = 1
+
+        wbm_inst.init_write(4, b'\x11\x22\x33\x44')
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(4,4) == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 2: read")
+        current_test.next = 2
+
+        wbm_inst.init_read(4, 4)
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        data = wbm_inst.get_read_data()
+        assert data[0] == 4
+        assert data[1] == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 3: various writes")
+        current_test.next = 3
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wb_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*16)
+                wbm_inst.init_write(256*(16*offset+length)+offset, b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length])
+
+                yield wbm_inst.wait()
+                yield clk.posedge
+
+                data = wb_ram_inst.read_mem(256*(16*offset+length), 32)
+                for i in range(0, len(data), 16):
+                    print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset-1, 1) == b'\xAA'
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset+length, 1) == b'\xAA'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 4: various reads")
+        current_test.next = 4
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wbm_inst.init_read(256*(16*offset+length)+offset, length)
+
+                yield wbm_inst.wait()
+                yield clk.posedge
+
+                data = wbm_inst.get_read_data()
+                assert data[0] == 256*(16*offset+length)+offset
+                assert data[1] == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_32_8.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_32_8.v
new file mode 100644
index 0000000..f4b1960
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_32_8.v
@@ -0,0 +1,136 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for wb_adapter
+ */
+module test_wb_adapter_32_8;
+
+// Parameters
+parameter ADDR_WIDTH = 32;
+parameter WBM_DATA_WIDTH = 32;
+parameter WBM_SELECT_WIDTH = 4;
+parameter WBS_DATA_WIDTH = 8;
+parameter WBS_SELECT_WIDTH = 1;
+
+// Inputs
+reg clk = 0;
+reg rst = 0;
+reg [7:0] current_test = 0;
+
+reg [ADDR_WIDTH-1:0] wbm_adr_i = 0;
+reg [WBM_DATA_WIDTH-1:0] wbm_dat_i = 0;
+reg wbm_we_i = 0;
+reg [WBM_SELECT_WIDTH-1:0] wbm_sel_i = 0;
+reg wbm_stb_i = 0;
+reg wbm_cyc_i = 0;
+reg [WBS_DATA_WIDTH-1:0] wbs_dat_i = 0;
+reg wbs_ack_i = 0;
+reg wbs_err_i = 0;
+reg wbs_rty_i = 0;
+
+// Outputs
+wire [WBM_DATA_WIDTH-1:0] wbm_dat_o;
+wire wbm_ack_o;
+wire wbm_err_o;
+wire wbm_rty_o;
+wire [ADDR_WIDTH-1:0] wbs_adr_o;
+wire [WBS_DATA_WIDTH-1:0] wbs_dat_o;
+wire wbs_we_o;
+wire [WBS_SELECT_WIDTH-1:0] wbs_sel_o;
+wire wbs_stb_o;
+wire wbs_cyc_o;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(
+        clk,
+        rst,
+        current_test,
+        wbm_adr_i,
+        wbm_dat_i,
+        wbm_we_i,
+        wbm_sel_i,
+        wbm_stb_i,
+        wbm_cyc_i,
+        wbs_dat_i,
+        wbs_ack_i,
+        wbs_err_i,
+        wbs_rty_i
+    );
+    $to_myhdl(
+        wbm_dat_o,
+        wbm_ack_o,
+        wbm_err_o,
+        wbm_rty_o,
+        wbs_adr_o,
+        wbs_dat_o,
+        wbs_we_o,
+        wbs_sel_o,
+        wbs_stb_o,
+        wbs_cyc_o
+    );
+
+    // dump file
+    $dumpfile("test_wb_adapter_32_8.lxt");
+    $dumpvars(0, test_wb_adapter_32_8);
+end
+
+wb_adapter #(
+    .ADDR_WIDTH(ADDR_WIDTH),
+    .WBM_DATA_WIDTH(WBM_DATA_WIDTH),
+    .WBM_SELECT_WIDTH(WBM_SELECT_WIDTH),
+    .WBS_DATA_WIDTH(WBS_DATA_WIDTH),
+    .WBS_SELECT_WIDTH(WBS_SELECT_WIDTH)
+)
+UUT (
+    .clk(clk),
+    .rst(rst),
+    .wbm_adr_i(wbm_adr_i),
+    .wbm_dat_i(wbm_dat_i),
+    .wbm_dat_o(wbm_dat_o),
+    .wbm_we_i(wbm_we_i),
+    .wbm_sel_i(wbm_sel_i),
+    .wbm_stb_i(wbm_stb_i),
+    .wbm_ack_o(wbm_ack_o),
+    .wbm_err_o(wbm_err_o),
+    .wbm_rty_o(wbm_rty_o),
+    .wbm_cyc_i(wbm_cyc_i),
+    .wbs_adr_o(wbs_adr_o),
+    .wbs_dat_i(wbs_dat_i),
+    .wbs_dat_o(wbs_dat_o),
+    .wbs_we_o(wbs_we_o),
+    .wbs_sel_o(wbs_sel_o),
+    .wbs_stb_o(wbs_stb_o),
+    .wbs_ack_i(wbs_ack_i),
+    .wbs_err_i(wbs_err_i),
+    .wbs_rty_i(wbs_rty_i),
+    .wbs_cyc_o(wbs_cyc_o)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_8_32.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_8_32.py
new file mode 100755
index 0000000..8b5c026
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_8_32.py
@@ -0,0 +1,242 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+import wb
+
+module = 'wb_adapter'
+testbench = 'test_%s_8_32' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("../rtl/priority_encoder.v")
+srcs.append("%s.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    ADDR_WIDTH = 32
+    WBM_DATA_WIDTH = 8
+    WBM_SELECT_WIDTH = 1
+    WBS_DATA_WIDTH = 32
+    WBS_SELECT_WIDTH = 4
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    wbm_adr_i = Signal(intbv(0)[ADDR_WIDTH:])
+    wbm_dat_i = Signal(intbv(0)[WBM_DATA_WIDTH:])
+    wbm_we_i = Signal(bool(0))
+    wbm_sel_i = Signal(intbv(0)[WBM_SELECT_WIDTH:])
+    wbm_stb_i = Signal(bool(0))
+    wbm_cyc_i = Signal(bool(0))
+    wbs_dat_i = Signal(intbv(0)[WBS_DATA_WIDTH:])
+    wbs_ack_i = Signal(bool(0))
+    wbs_err_i = Signal(bool(0))
+    wbs_rty_i = Signal(bool(0))
+
+    # Outputs
+    wbm_dat_o = Signal(intbv(0)[WBM_DATA_WIDTH:])
+    wbm_ack_o = Signal(bool(0))
+    wbm_err_o = Signal(bool(0))
+    wbm_rty_o = Signal(bool(0))
+    wbs_adr_o = Signal(intbv(0)[ADDR_WIDTH:])
+    wbs_dat_o = Signal(intbv(0)[WBS_DATA_WIDTH:])
+    wbs_we_o = Signal(bool(0))
+    wbs_sel_o = Signal(intbv(0)[WBS_SELECT_WIDTH:])
+    wbs_stb_o = Signal(bool(0))
+    wbs_cyc_o = Signal(bool(0))
+
+    # WB master
+    wbm_inst = wb.WBMaster()
+
+    wbm_logic = wbm_inst.create_logic(
+        clk,
+        adr_o=wbm_adr_i,
+        dat_i=wbm_dat_o,
+        dat_o=wbm_dat_i,
+        we_o=wbm_we_i,
+        sel_o=wbm_sel_i,
+        stb_o=wbm_stb_i,
+        ack_i=wbm_ack_o,
+        cyc_o=wbm_cyc_i,
+        name='master'
+    )
+
+    # WB RAM model
+    wb_ram_inst = wb.WBRam(2**16)
+
+    wb_ram_port0 = wb_ram_inst.create_port(
+        clk,
+        adr_i=wbs_adr_o,
+        dat_i=wbs_dat_o,
+        dat_o=wbs_dat_i,
+        we_i=wbs_we_o,
+        sel_i=wbs_sel_o,
+        stb_i=wbs_stb_o,
+        ack_o=wbs_ack_i,
+        cyc_i=wbs_cyc_o,
+        latency=1,
+        asynchronous=False,
+        name='slave'
+    )
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        clk=clk,
+        rst=rst,
+        current_test=current_test,
+        wbm_adr_i=wbm_adr_i,
+        wbm_dat_i=wbm_dat_i,
+        wbm_dat_o=wbm_dat_o,
+        wbm_we_i=wbm_we_i,
+        wbm_sel_i=wbm_sel_i,
+        wbm_stb_i=wbm_stb_i,
+        wbm_ack_o=wbm_ack_o,
+        wbm_err_o=wbm_err_o,
+        wbm_rty_o=wbm_rty_o,
+        wbm_cyc_i=wbm_cyc_i,
+        wbs_adr_o=wbs_adr_o,
+        wbs_dat_i=wbs_dat_i,
+        wbs_dat_o=wbs_dat_o,
+        wbs_we_o=wbs_we_o,
+        wbs_sel_o=wbs_sel_o,
+        wbs_stb_o=wbs_stb_o,
+        wbs_ack_i=wbs_ack_i,
+        wbs_err_i=wbs_err_i,
+        wbs_rty_i=wbs_rty_i,
+        wbs_cyc_o=wbs_cyc_o
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        yield clk.posedge
+        print("test 1: write")
+        current_test.next = 1
+
+        wbm_inst.init_write(4, b'\x11\x22\x33\x44')
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(4,4) == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 2: read")
+        current_test.next = 2
+
+        wbm_inst.init_read(4, 4)
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        data = wbm_inst.get_read_data()
+        assert data[0] == 4
+        assert data[1] == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 3: various writes")
+        current_test.next = 3
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wb_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*16)
+                wbm_inst.init_write(256*(16*offset+length)+offset, b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length])
+
+                yield wbm_inst.wait()
+                yield clk.posedge
+
+                data = wb_ram_inst.read_mem(256*(16*offset+length), 32)
+                for i in range(0, len(data), 16):
+                    print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset-1, 1) == b'\xAA'
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset+length, 1) == b'\xAA'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 4: various reads")
+        current_test.next = 4
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wbm_inst.init_read(256*(16*offset+length)+offset, length)
+
+                yield wbm_inst.wait()
+                yield clk.posedge
+
+                data = wbm_inst.get_read_data()
+                assert data[0] == 256*(16*offset+length)+offset
+                assert data[1] == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_8_32.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_8_32.v
new file mode 100644
index 0000000..6f5a627
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_adapter_8_32.v
@@ -0,0 +1,136 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for wb_adapter
+ */
+module test_wb_adapter_8_32;
+
+// Parameters
+parameter ADDR_WIDTH = 32;
+parameter WBM_DATA_WIDTH = 8;
+parameter WBM_SELECT_WIDTH = 1;
+parameter WBS_DATA_WIDTH = 32;
+parameter WBS_SELECT_WIDTH = 4;
+
+// Inputs
+reg clk = 0;
+reg rst = 0;
+reg [7:0] current_test = 0;
+
+reg [ADDR_WIDTH-1:0] wbm_adr_i = 0;
+reg [WBM_DATA_WIDTH-1:0] wbm_dat_i = 0;
+reg wbm_we_i = 0;
+reg [WBM_SELECT_WIDTH-1:0] wbm_sel_i = 0;
+reg wbm_stb_i = 0;
+reg wbm_cyc_i = 0;
+reg [WBS_DATA_WIDTH-1:0] wbs_dat_i = 0;
+reg wbs_ack_i = 0;
+reg wbs_err_i = 0;
+reg wbs_rty_i = 0;
+
+// Outputs
+wire [WBM_DATA_WIDTH-1:0] wbm_dat_o;
+wire wbm_ack_o;
+wire wbm_err_o;
+wire wbm_rty_o;
+wire [ADDR_WIDTH-1:0] wbs_adr_o;
+wire [WBS_DATA_WIDTH-1:0] wbs_dat_o;
+wire wbs_we_o;
+wire [WBS_SELECT_WIDTH-1:0] wbs_sel_o;
+wire wbs_stb_o;
+wire wbs_cyc_o;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(
+        clk,
+        rst,
+        current_test,
+        wbm_adr_i,
+        wbm_dat_i,
+        wbm_we_i,
+        wbm_sel_i,
+        wbm_stb_i,
+        wbm_cyc_i,
+        wbs_dat_i,
+        wbs_ack_i,
+        wbs_err_i,
+        wbs_rty_i
+    );
+    $to_myhdl(
+        wbm_dat_o,
+        wbm_ack_o,
+        wbm_err_o,
+        wbm_rty_o,
+        wbs_adr_o,
+        wbs_dat_o,
+        wbs_we_o,
+        wbs_sel_o,
+        wbs_stb_o,
+        wbs_cyc_o
+    );
+
+    // dump file
+    $dumpfile("test_wb_adapter_8_32.lxt");
+    $dumpvars(0, test_wb_adapter_8_32);
+end
+
+wb_adapter #(
+    .ADDR_WIDTH(ADDR_WIDTH),
+    .WBM_DATA_WIDTH(WBM_DATA_WIDTH),
+    .WBM_SELECT_WIDTH(WBM_SELECT_WIDTH),
+    .WBS_DATA_WIDTH(WBS_DATA_WIDTH),
+    .WBS_SELECT_WIDTH(WBS_SELECT_WIDTH)
+)
+UUT (
+    .clk(clk),
+    .rst(rst),
+    .wbm_adr_i(wbm_adr_i),
+    .wbm_dat_i(wbm_dat_i),
+    .wbm_dat_o(wbm_dat_o),
+    .wbm_we_i(wbm_we_i),
+    .wbm_sel_i(wbm_sel_i),
+    .wbm_stb_i(wbm_stb_i),
+    .wbm_ack_o(wbm_ack_o),
+    .wbm_err_o(wbm_err_o),
+    .wbm_rty_o(wbm_rty_o),
+    .wbm_cyc_i(wbm_cyc_i),
+    .wbs_adr_o(wbs_adr_o),
+    .wbs_dat_i(wbs_dat_i),
+    .wbs_dat_o(wbs_dat_o),
+    .wbs_we_o(wbs_we_o),
+    .wbs_sel_o(wbs_sel_o),
+    .wbs_stb_o(wbs_stb_o),
+    .wbs_ack_i(wbs_ack_i),
+    .wbs_err_i(wbs_err_i),
+    .wbs_rty_i(wbs_rty_i),
+    .wbs_cyc_o(wbs_cyc_o)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_arbiter_2.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_arbiter_2.py
new file mode 100755
index 0000000..f4b5448
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_arbiter_2.py
@@ -0,0 +1,315 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+import wb
+
+module = 'wb_arbiter_2'
+testbench = 'test_%s' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("../rtl/arbiter.v")
+srcs.append("../rtl/priority_encoder.v")
+srcs.append("%s.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    DATA_WIDTH = 32
+    ADDR_WIDTH = 32
+    SELECT_WIDTH = (DATA_WIDTH/8)
+    ARB_TYPE = "PRIORITY"
+    LSB_PRIORITY = "HIGH"
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    wbm0_adr_i = Signal(intbv(0)[ADDR_WIDTH:])
+    wbm0_dat_i = Signal(intbv(0)[DATA_WIDTH:])
+    wbm0_we_i = Signal(bool(0))
+    wbm0_sel_i = Signal(intbv(0)[SELECT_WIDTH:])
+    wbm0_stb_i = Signal(bool(0))
+    wbm0_cyc_i = Signal(bool(0))
+    wbm1_adr_i = Signal(intbv(0)[ADDR_WIDTH:])
+    wbm1_dat_i = Signal(intbv(0)[DATA_WIDTH:])
+    wbm1_we_i = Signal(bool(0))
+    wbm1_sel_i = Signal(intbv(0)[SELECT_WIDTH:])
+    wbm1_stb_i = Signal(bool(0))
+    wbm1_cyc_i = Signal(bool(0))
+    wbs_dat_i = Signal(intbv(0)[DATA_WIDTH:])
+    wbs_ack_i = Signal(bool(0))
+    wbs_err_i = Signal(bool(0))
+    wbs_rty_i = Signal(bool(0))
+
+    # Outputs
+    wbm0_dat_o = Signal(intbv(0)[DATA_WIDTH:])
+    wbm0_ack_o = Signal(bool(0))
+    wbm0_err_o = Signal(bool(0))
+    wbm0_rty_o = Signal(bool(0))
+    wbm1_dat_o = Signal(intbv(0)[DATA_WIDTH:])
+    wbm1_ack_o = Signal(bool(0))
+    wbm1_err_o = Signal(bool(0))
+    wbm1_rty_o = Signal(bool(0))
+    wbs_adr_o = Signal(intbv(0)[ADDR_WIDTH:])
+    wbs_dat_o = Signal(intbv(0)[DATA_WIDTH:])
+    wbs_we_o = Signal(bool(0))
+    wbs_sel_o = Signal(intbv(0)[SELECT_WIDTH:])
+    wbs_stb_o = Signal(bool(0))
+    wbs_cyc_o = Signal(bool(0))
+
+    # WB master
+    wbm0_inst = wb.WBMaster()
+
+    wbm0_logic = wbm0_inst.create_logic(
+        clk,
+        adr_o=wbm0_adr_i,
+        dat_i=wbm0_dat_o,
+        dat_o=wbm0_dat_i,
+        we_o=wbm0_we_i,
+        sel_o=wbm0_sel_i,
+        stb_o=wbm0_stb_i,
+        ack_i=wbm0_ack_o,
+        cyc_o=wbm0_cyc_i,
+        name='master0'
+    )
+
+    # WB master
+    wbm1_inst = wb.WBMaster()
+
+    wbm1_logic = wbm1_inst.create_logic(
+        clk,
+        adr_o=wbm1_adr_i,
+        dat_i=wbm1_dat_o,
+        dat_o=wbm1_dat_i,
+        we_o=wbm1_we_i,
+        sel_o=wbm1_sel_i,
+        stb_o=wbm1_stb_i,
+        ack_i=wbm1_ack_o,
+        cyc_o=wbm1_cyc_i,
+        name='master1'
+    )
+
+    # WB RAM model
+    wb_ram_inst = wb.WBRam(2**16)
+
+    wb_ram_port0 = wb_ram_inst.create_port(
+        clk,
+        adr_i=wbs_adr_o,
+        dat_i=wbs_dat_o,
+        dat_o=wbs_dat_i,
+        we_i=wbs_we_o,
+        sel_i=wbs_sel_o,
+        stb_i=wbs_stb_o,
+        ack_o=wbs_ack_i,
+        cyc_i=wbs_cyc_o,
+        latency=1,
+        asynchronous=False,
+        name='slave'
+    )
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        clk=clk,
+        rst=rst,
+        current_test=current_test,
+
+        wbm0_adr_i=wbm0_adr_i,
+        wbm0_dat_i=wbm0_dat_i,
+        wbm0_dat_o=wbm0_dat_o,
+        wbm0_we_i=wbm0_we_i,
+        wbm0_sel_i=wbm0_sel_i,
+        wbm0_stb_i=wbm0_stb_i,
+        wbm0_ack_o=wbm0_ack_o,
+        wbm0_err_o=wbm0_err_o,
+        wbm0_rty_o=wbm0_rty_o,
+        wbm0_cyc_i=wbm0_cyc_i,
+
+        wbm1_adr_i=wbm1_adr_i,
+        wbm1_dat_i=wbm1_dat_i,
+        wbm1_dat_o=wbm1_dat_o,
+        wbm1_we_i=wbm1_we_i,
+        wbm1_sel_i=wbm1_sel_i,
+        wbm1_stb_i=wbm1_stb_i,
+        wbm1_ack_o=wbm1_ack_o,
+        wbm1_err_o=wbm1_err_o,
+        wbm1_rty_o=wbm1_rty_o,
+        wbm1_cyc_i=wbm1_cyc_i,
+
+        wbs_adr_o=wbs_adr_o,
+        wbs_dat_i=wbs_dat_i,
+        wbs_dat_o=wbs_dat_o,
+        wbs_we_o=wbs_we_o,
+        wbs_sel_o=wbs_sel_o,
+        wbs_stb_o=wbs_stb_o,
+        wbs_ack_i=wbs_ack_i,
+        wbs_err_i=wbs_err_i,
+        wbs_rty_i=wbs_rty_i,
+        wbs_cyc_o=wbs_cyc_o
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        # testbench stimulus
+
+        yield clk.posedge
+        print("test 1: master 0")
+        current_test.next = 1
+
+        wbm0_inst.init_write(0x00000000, b'\x11\x22\x33\x44')
+
+        yield wbm0_inst.wait()
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0x00000000, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(0,4) == b'\x11\x22\x33\x44'
+
+        wbm0_inst.init_read(0x00000000, 4)
+
+        yield wbm0_inst.wait()
+        yield clk.posedge
+
+        data = wbm0_inst.get_read_data()
+        assert data[0] == 0x00000000
+        assert data[1] == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 2: master 1")
+        current_test.next = 2
+
+        wbm1_inst.init_write(0x00001000, b'\x11\x22\x33\x44')
+
+        yield wbm1_inst.wait()
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0x00001000, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(0,4) == b'\x11\x22\x33\x44'
+
+        wbm1_inst.init_read(0x00001000, 4)
+
+        yield wbm0_inst.wait()
+        yield wbm1_inst.wait()
+        yield clk.posedge
+
+        data = wbm1_inst.get_read_data()
+        assert data[0] == 0x00001000
+        assert data[1] == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 3: arbitration")
+        current_test.next = 3
+
+        wbm0_inst.init_write(0x00000010, bytearray(range(16)))
+        wbm0_inst.init_write(0x00000020, bytearray(range(16)))
+        wbm1_inst.init_write(0x00001010, bytearray(range(16)))
+        wbm1_inst.init_write(0x00001020, bytearray(range(16)))
+
+        yield wbm1_inst.wait()
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0x00000010, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        data = wb_ram_inst.read_mem(0x00001010, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(0,4) == b'\x11\x22\x33\x44'
+
+        wbm0_inst.init_read(0x00000010, 16)
+        wbm0_inst.init_read(0x00000020, 16)
+        wbm1_inst.init_read(0x00001010, 16)
+        wbm1_inst.init_read(0x00001020, 16)
+
+        yield wbm0_inst.wait()
+        yield wbm1_inst.wait()
+        yield clk.posedge
+
+        data = wbm0_inst.get_read_data()
+        assert data[0] == 0x00000010
+        assert data[1] == bytearray(range(16))
+
+        data = wbm0_inst.get_read_data()
+        assert data[0] == 0x00000020
+        assert data[1] == bytearray(range(16))
+
+        data = wbm1_inst.get_read_data()
+        assert data[0] == 0x00001010
+        assert data[1] == bytearray(range(16))
+
+        data = wbm1_inst.get_read_data()
+        assert data[0] == 0x00001020
+        assert data[1] == bytearray(range(16))
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_arbiter_2.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_arbiter_2.v
new file mode 100644
index 0000000..10c291b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_arbiter_2.v
@@ -0,0 +1,166 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for wb_arbiter_2
+ */
+module test_wb_arbiter_2;
+
+// Parameters
+parameter DATA_WIDTH = 32;
+parameter ADDR_WIDTH = 32;
+parameter SELECT_WIDTH = (DATA_WIDTH/8);
+parameter ARB_TYPE = "PRIORITY";
+parameter LSB_PRIORITY = "HIGH";
+
+// Inputs
+reg clk = 0;
+reg rst = 0;
+reg [7:0] current_test = 0;
+
+reg [ADDR_WIDTH-1:0] wbm0_adr_i = 0;
+reg [DATA_WIDTH-1:0] wbm0_dat_i = 0;
+reg wbm0_we_i = 0;
+reg [SELECT_WIDTH-1:0] wbm0_sel_i = 0;
+reg wbm0_stb_i = 0;
+reg wbm0_cyc_i = 0;
+reg [ADDR_WIDTH-1:0] wbm1_adr_i = 0;
+reg [DATA_WIDTH-1:0] wbm1_dat_i = 0;
+reg wbm1_we_i = 0;
+reg [SELECT_WIDTH-1:0] wbm1_sel_i = 0;
+reg wbm1_stb_i = 0;
+reg wbm1_cyc_i = 0;
+reg [DATA_WIDTH-1:0] wbs_dat_i = 0;
+reg wbs_ack_i = 0;
+reg wbs_err_i = 0;
+reg wbs_rty_i = 0;
+
+// Outputs
+wire [DATA_WIDTH-1:0] wbm0_dat_o;
+wire wbm0_ack_o;
+wire wbm0_err_o;
+wire wbm0_rty_o;
+wire [DATA_WIDTH-1:0] wbm1_dat_o;
+wire wbm1_ack_o;
+wire wbm1_err_o;
+wire wbm1_rty_o;
+wire [ADDR_WIDTH-1:0] wbs_adr_o;
+wire [DATA_WIDTH-1:0] wbs_dat_o;
+wire wbs_we_o;
+wire [SELECT_WIDTH-1:0] wbs_sel_o;
+wire wbs_stb_o;
+wire wbs_cyc_o;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(
+        clk,
+        rst,
+        current_test,
+        wbm0_adr_i,
+        wbm0_dat_i,
+        wbm0_we_i,
+        wbm0_sel_i,
+        wbm0_stb_i,
+        wbm0_cyc_i,
+        wbm1_adr_i,
+        wbm1_dat_i,
+        wbm1_we_i,
+        wbm1_sel_i,
+        wbm1_stb_i,
+        wbm1_cyc_i,
+        wbs_dat_i,
+        wbs_ack_i,
+        wbs_err_i,
+        wbs_rty_i
+    );
+    $to_myhdl(
+        wbm0_dat_o,
+        wbm0_ack_o,
+        wbm0_err_o,
+        wbm0_rty_o,
+        wbm1_dat_o,
+        wbm1_ack_o,
+        wbm1_err_o,
+        wbm1_rty_o,
+        wbs_adr_o,
+        wbs_dat_o,
+        wbs_we_o,
+        wbs_sel_o,
+        wbs_stb_o,
+        wbs_cyc_o
+    );
+
+    // dump file
+    $dumpfile("test_wb_arbiter_2.lxt");
+    $dumpvars(0, test_wb_arbiter_2);
+end
+
+wb_arbiter_2 #(
+    .DATA_WIDTH(DATA_WIDTH),
+    .ADDR_WIDTH(ADDR_WIDTH),
+    .SELECT_WIDTH(SELECT_WIDTH),
+    .ARB_TYPE(ARB_TYPE),
+    .LSB_PRIORITY(LSB_PRIORITY)
+)
+UUT (
+    .clk(clk),
+    .rst(rst),
+    .wbm0_adr_i(wbm0_adr_i),
+    .wbm0_dat_i(wbm0_dat_i),
+    .wbm0_dat_o(wbm0_dat_o),
+    .wbm0_we_i(wbm0_we_i),
+    .wbm0_sel_i(wbm0_sel_i),
+    .wbm0_stb_i(wbm0_stb_i),
+    .wbm0_ack_o(wbm0_ack_o),
+    .wbm0_err_o(wbm0_err_o),
+    .wbm0_rty_o(wbm0_rty_o),
+    .wbm0_cyc_i(wbm0_cyc_i),
+    .wbm1_adr_i(wbm1_adr_i),
+    .wbm1_dat_i(wbm1_dat_i),
+    .wbm1_dat_o(wbm1_dat_o),
+    .wbm1_we_i(wbm1_we_i),
+    .wbm1_sel_i(wbm1_sel_i),
+    .wbm1_stb_i(wbm1_stb_i),
+    .wbm1_ack_o(wbm1_ack_o),
+    .wbm1_err_o(wbm1_err_o),
+    .wbm1_rty_o(wbm1_rty_o),
+    .wbm1_cyc_i(wbm1_cyc_i),
+    .wbs_adr_o(wbs_adr_o),
+    .wbs_dat_i(wbs_dat_i),
+    .wbs_dat_o(wbs_dat_o),
+    .wbs_we_o(wbs_we_o),
+    .wbs_sel_o(wbs_sel_o),
+    .wbs_stb_o(wbs_stb_o),
+    .wbs_ack_i(wbs_ack_i),
+    .wbs_err_i(wbs_err_i),
+    .wbs_rty_i(wbs_rty_i),
+    .wbs_cyc_o(wbs_cyc_o)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_async_reg.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_async_reg.py
new file mode 100755
index 0000000..0148b84
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_async_reg.py
@@ -0,0 +1,251 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+import wb
+
+module = 'wb_async_reg'
+testbench = 'test_%s' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("%s.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    DATA_WIDTH = 32
+    ADDR_WIDTH = 32
+    SELECT_WIDTH = 4
+
+    # Inputs
+    wbm_clk = Signal(bool(0))
+    wbm_rst = Signal(bool(0))
+    wbs_clk = Signal(bool(0))
+    wbs_rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    wbm_adr_i = Signal(intbv(0)[ADDR_WIDTH:])
+    wbm_dat_i = Signal(intbv(0)[DATA_WIDTH:])
+    wbm_we_i = Signal(bool(0))
+    wbm_sel_i = Signal(intbv(0)[SELECT_WIDTH:])
+    wbm_stb_i = Signal(bool(0))
+    wbm_cyc_i = Signal(bool(0))
+    wbs_dat_i = Signal(intbv(0)[DATA_WIDTH:])
+    wbs_ack_i = Signal(bool(0))
+    wbs_err_i = Signal(bool(0))
+    wbs_rty_i = Signal(bool(0))
+
+    # Outputs
+    wbm_dat_o = Signal(intbv(0)[DATA_WIDTH:])
+    wbm_ack_o = Signal(bool(0))
+    wbm_err_o = Signal(bool(0))
+    wbm_rty_o = Signal(bool(0))
+    wbs_adr_o = Signal(intbv(0)[ADDR_WIDTH:])
+    wbs_dat_o = Signal(intbv(0)[DATA_WIDTH:])
+    wbs_we_o = Signal(bool(0))
+    wbs_sel_o = Signal(intbv(0)[SELECT_WIDTH:])
+    wbs_stb_o = Signal(bool(0))
+    wbs_cyc_o = Signal(bool(0))
+
+    # WB master
+    wbm_inst = wb.WBMaster()
+
+    wbm_logic = wbm_inst.create_logic(
+        wbm_clk,
+        adr_o=wbm_adr_i,
+        dat_i=wbm_dat_o,
+        dat_o=wbm_dat_i,
+        we_o=wbm_we_i,
+        sel_o=wbm_sel_i,
+        stb_o=wbm_stb_i,
+        ack_i=wbm_ack_o,
+        cyc_o=wbm_cyc_i,
+        name='master'
+    )
+
+    # WB RAM model
+    wb_ram_inst = wb.WBRam(2**16)
+
+    wb_ram_port0 = wb_ram_inst.create_port(
+        wbs_clk,
+        adr_i=wbs_adr_o,
+        dat_i=wbs_dat_o,
+        dat_o=wbs_dat_i,
+        we_i=wbs_we_o,
+        sel_i=wbs_sel_o,
+        stb_i=wbs_stb_o,
+        ack_o=wbs_ack_i,
+        cyc_i=wbs_cyc_o,
+        latency=1,
+        asynchronous=False,
+        name='slave'
+    )
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        wbm_clk=wbm_clk,
+        wbm_rst=wbm_rst,
+        wbs_clk=wbs_clk,
+        wbs_rst=wbs_rst,
+        current_test=current_test,
+        wbm_adr_i=wbm_adr_i,
+        wbm_dat_i=wbm_dat_i,
+        wbm_dat_o=wbm_dat_o,
+        wbm_we_i=wbm_we_i,
+        wbm_sel_i=wbm_sel_i,
+        wbm_stb_i=wbm_stb_i,
+        wbm_ack_o=wbm_ack_o,
+        wbm_err_o=wbm_err_o,
+        wbm_rty_o=wbm_rty_o,
+        wbm_cyc_i=wbm_cyc_i,
+        wbs_adr_o=wbs_adr_o,
+        wbs_dat_i=wbs_dat_i,
+        wbs_dat_o=wbs_dat_o,
+        wbs_we_o=wbs_we_o,
+        wbs_sel_o=wbs_sel_o,
+        wbs_stb_o=wbs_stb_o,
+        wbs_ack_i=wbs_ack_i,
+        wbs_err_i=wbs_err_i,
+        wbs_rty_i=wbs_rty_i,
+        wbs_cyc_o=wbs_cyc_o
+    )
+
+    @always(delay(4))
+    def wbm_clkgen():
+        wbm_clk.next = not wbm_clk
+
+    @always(delay(5))
+    def wbs_clkgen():
+        wbs_clk.next = not wbs_clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield wbm_clk.posedge
+        wbm_rst.next = 1
+        wbs_rst.next = 1
+        yield wbm_clk.posedge
+        yield wbm_clk.posedge
+        yield wbm_clk.posedge
+        wbm_rst.next = 0
+        wbs_rst.next = 0
+        yield wbm_clk.posedge
+        yield delay(100)
+        yield wbm_clk.posedge
+
+        yield wbm_clk.posedge
+        print("test 1: write")
+        current_test.next = 1
+
+        wbm_inst.init_write(4, b'\x11\x22\x33\x44')
+
+        yield wbm_inst.wait()
+        yield wbm_clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(4,4) == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield wbm_clk.posedge
+        print("test 2: read")
+        current_test.next = 2
+
+        wbm_inst.init_read(4, 4)
+
+        yield wbm_inst.wait()
+        yield wbm_clk.posedge
+
+        data = wbm_inst.get_read_data()
+        assert data[0] == 4
+        assert data[1] == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield wbm_clk.posedge
+        print("test 3: various writes")
+        current_test.next = 3
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wb_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*32)
+                wbm_inst.init_write(256*(16*offset+length)+offset, b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length])
+
+                yield wbm_inst.wait()
+                yield wbm_clk.posedge
+
+                data = wb_ram_inst.read_mem(256*(16*offset+length), 32)
+                for i in range(0, len(data), 16):
+                    print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset-1, 1) == b'\xAA'
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset+length, 1) == b'\xAA'
+
+        yield delay(100)
+
+        yield wbm_clk.posedge
+        print("test 4: various reads")
+        current_test.next = 4
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wbm_inst.init_read(256*(16*offset+length)+offset, length)
+
+                yield wbm_inst.wait()
+                yield wbm_clk.posedge
+
+                data = wbm_inst.get_read_data()
+                assert data[0] == 256*(16*offset+length)+offset
+                assert data[1] == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_async_reg.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_async_reg.v
new file mode 100644
index 0000000..461ef24
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_async_reg.v
@@ -0,0 +1,138 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for wb_async_reg
+ */
+module test_wb_async_reg;
+
+// Parameters
+parameter DATA_WIDTH = 32;
+parameter ADDR_WIDTH = 32;
+parameter SELECT_WIDTH = 4;
+
+// Inputs
+reg wbm_clk = 0;
+reg wbm_rst = 0;
+reg wbs_clk = 0;
+reg wbs_rst = 0;
+reg [7:0] current_test = 0;
+
+reg [ADDR_WIDTH-1:0] wbm_adr_i = 0;
+reg [DATA_WIDTH-1:0] wbm_dat_i = 0;
+reg wbm_we_i = 0;
+reg [SELECT_WIDTH-1:0] wbm_sel_i = 0;
+reg wbm_stb_i = 0;
+reg wbm_cyc_i = 0;
+reg [DATA_WIDTH-1:0] wbs_dat_i = 0;
+reg wbs_ack_i = 0;
+reg wbs_err_i = 0;
+reg wbs_rty_i = 0;
+
+// Outputs
+wire [DATA_WIDTH-1:0] wbm_dat_o;
+wire wbm_ack_o;
+wire wbm_err_o;
+wire wbm_rty_o;
+wire [ADDR_WIDTH-1:0] wbs_adr_o;
+wire [DATA_WIDTH-1:0] wbs_dat_o;
+wire wbs_we_o;
+wire [SELECT_WIDTH-1:0] wbs_sel_o;
+wire wbs_stb_o;
+wire wbs_cyc_o;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(
+        wbm_clk,
+        wbm_rst,
+        wbs_clk,
+        wbs_rst,
+        current_test,
+        wbm_adr_i,
+        wbm_dat_i,
+        wbm_we_i,
+        wbm_sel_i,
+        wbm_stb_i,
+        wbm_cyc_i,
+        wbs_dat_i,
+        wbs_ack_i,
+        wbs_err_i,
+        wbs_rty_i
+    );
+    $to_myhdl(
+        wbm_dat_o,
+        wbm_ack_o,
+        wbm_err_o,
+        wbm_rty_o,
+        wbs_adr_o,
+        wbs_dat_o,
+        wbs_we_o,
+        wbs_sel_o,
+        wbs_stb_o,
+        wbs_cyc_o
+    );
+
+    // dump file
+    $dumpfile("test_wb_async_reg.lxt");
+    $dumpvars(0, test_wb_async_reg);
+end
+
+wb_async_reg #(
+    .DATA_WIDTH(DATA_WIDTH),
+    .ADDR_WIDTH(ADDR_WIDTH),
+    .SELECT_WIDTH(SELECT_WIDTH)
+)
+UUT (
+    .wbm_clk(wbm_clk),
+    .wbm_rst(wbm_rst),
+    .wbm_adr_i(wbm_adr_i),
+    .wbm_dat_i(wbm_dat_i),
+    .wbm_dat_o(wbm_dat_o),
+    .wbm_we_i(wbm_we_i),
+    .wbm_sel_i(wbm_sel_i),
+    .wbm_stb_i(wbm_stb_i),
+    .wbm_ack_o(wbm_ack_o),
+    .wbm_err_o(wbm_err_o),
+    .wbm_rty_o(wbm_rty_o),
+    .wbm_cyc_i(wbm_cyc_i),
+    .wbs_clk(wbs_clk),
+    .wbs_rst(wbs_rst),
+    .wbs_adr_o(wbs_adr_o),
+    .wbs_dat_i(wbs_dat_i),
+    .wbs_dat_o(wbs_dat_o),
+    .wbs_we_o(wbs_we_o),
+    .wbs_sel_o(wbs_sel_o),
+    .wbs_stb_o(wbs_stb_o),
+    .wbs_ack_i(wbs_ack_i),
+    .wbs_err_i(wbs_err_i),
+    .wbs_rty_i(wbs_rty_i),
+    .wbs_cyc_o(wbs_cyc_o)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_dp_ram.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_dp_ram.py
new file mode 100755
index 0000000..8e24768
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_dp_ram.py
@@ -0,0 +1,285 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+import wb
+
+module = 'wb_dp_ram'
+testbench = 'test_%s' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("%s.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    DATA_WIDTH = 32
+    ADDR_WIDTH = 32
+    SELECT_WIDTH = 4
+
+    # Inputs
+    a_clk = Signal(bool(0))
+    a_rst = Signal(bool(0))
+    b_clk = Signal(bool(0))
+    b_rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    a_adr_i = Signal(intbv(0)[ADDR_WIDTH:])
+    a_dat_i = Signal(intbv(0)[DATA_WIDTH:])
+    a_we_i = Signal(bool(0))
+    a_sel_i = Signal(intbv(0)[SELECT_WIDTH:])
+    a_stb_i = Signal(bool(0))
+    a_cyc_i = Signal(bool(0))
+    b_adr_i = Signal(intbv(0)[ADDR_WIDTH:])
+    b_dat_i = Signal(intbv(0)[DATA_WIDTH:])
+    b_we_i = Signal(bool(0))
+    b_sel_i = Signal(intbv(0)[SELECT_WIDTH:])
+    b_stb_i = Signal(bool(0))
+    b_cyc_i = Signal(bool(0))
+
+    # Outputs
+    a_dat_o = Signal(intbv(0)[DATA_WIDTH:])
+    a_ack_o = Signal(bool(0))
+    b_dat_o = Signal(intbv(0)[DATA_WIDTH:])
+    b_ack_o = Signal(bool(0))
+
+    # WB master A
+    wbm_inst_a = wb.WBMaster()
+
+    wbm_logic_a = wbm_inst_a.create_logic(
+        a_clk,
+        adr_o=a_adr_i,
+        dat_i=a_dat_o,
+        dat_o=a_dat_i,
+        we_o=a_we_i,
+        sel_o=a_sel_i,
+        stb_o=a_stb_i,
+        ack_i=a_ack_o,
+        cyc_o=a_cyc_i,
+        name='master_a'
+    )
+
+    # WB master B
+    wbm_inst_b = wb.WBMaster()
+
+    wbm_logic_b = wbm_inst_b.create_logic(
+        b_clk,
+        adr_o=b_adr_i,
+        dat_i=b_dat_o,
+        dat_o=b_dat_i,
+        we_o=b_we_i,
+        sel_o=b_sel_i,
+        stb_o=b_stb_i,
+        ack_i=b_ack_o,
+        cyc_o=b_cyc_i,
+        name='master_'
+    )
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        a_clk=a_clk,
+        a_rst=a_rst,
+        b_clk=b_clk,
+        b_rst=b_rst,
+        current_test=current_test,
+        a_adr_i=a_adr_i,
+        a_dat_i=a_dat_i,
+        a_dat_o=a_dat_o,
+        a_we_i=a_we_i,
+        a_sel_i=a_sel_i,
+        a_stb_i=a_stb_i,
+        a_ack_o=a_ack_o,
+        a_cyc_i=a_cyc_i,
+        b_adr_i=b_adr_i,
+        b_dat_i=b_dat_i,
+        b_dat_o=b_dat_o,
+        b_we_i=b_we_i,
+        b_sel_i=b_sel_i,
+        b_stb_i=b_stb_i,
+        b_ack_o=b_ack_o,
+        b_cyc_i=b_cyc_i
+    )
+
+    @always(delay(4))
+    def a_clkgen():
+        a_clk.next = not a_clk
+
+    @always(delay(5))
+    def b_clkgen():
+        b_clk.next = not b_clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield a_clk.posedge
+        a_rst.next = 1
+        b_rst.next = 1
+        yield a_clk.posedge
+        yield a_clk.posedge
+        yield a_clk.posedge
+        a_rst.next = 0
+        b_rst.next = 0
+        yield a_clk.posedge
+        yield delay(100)
+        yield a_clk.posedge
+
+        yield a_clk.posedge
+        print("test 1: read and write (port A)")
+        current_test.next = 1
+
+        wbm_inst_a.init_write(4, b'\x11\x22\x33\x44')
+
+        yield wbm_inst_a.wait()
+        yield a_clk.posedge
+
+        wbm_inst_a.init_read(4, 4)
+
+        yield wbm_inst_a.wait()
+        yield a_clk.posedge
+
+        data = wbm_inst_a.get_read_data()
+        assert data[0] == 4
+        assert data[1] == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield a_clk.posedge
+        print("test 2: read and write (port B)")
+        current_test.next = 2
+
+        wbm_inst_b.init_write(4, b'\x11\x22\x33\x44')
+
+        yield wbm_inst_b.wait()
+        yield b_clk.posedge
+
+        wbm_inst_b.init_read(4, 4)
+
+        yield wbm_inst_b.wait()
+        yield b_clk.posedge
+
+        data = wbm_inst_b.get_read_data()
+        assert data[0] == 4
+        assert data[1] == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield a_clk.posedge
+        print("test 3: various reads and writes (port A)")
+        current_test.next = 3
+
+        for length in range(1,8):
+            for offset in range(4):
+                wbm_inst_a.init_write(256*(16*offset+length)+offset, b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length])
+
+                yield wbm_inst_a.wait()
+                yield a_clk.posedge
+
+        for length in range(1,8):
+            for offset in range(4):
+                wbm_inst_a.init_read(256*(16*offset+length)+offset, length)
+
+                yield wbm_inst_a.wait()
+                yield a_clk.posedge
+
+                data = wbm_inst_a.get_read_data()
+                assert data[0] == 256*(16*offset+length)+offset
+                assert data[1] == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+
+        yield delay(100)
+
+        yield a_clk.posedge
+        print("test 4: various reads and writes (port B)")
+        current_test.next = 4
+
+        for length in range(1,8):
+            for offset in range(4):
+                wbm_inst_b.init_write(256*(16*offset+length)+offset, b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length])
+
+                yield wbm_inst_b.wait()
+                yield b_clk.posedge
+
+        for length in range(1,8):
+            for offset in range(4):
+                wbm_inst_b.init_read(256*(16*offset+length)+offset, length)
+
+                yield wbm_inst_b.wait()
+                yield b_clk.posedge
+
+                data = wbm_inst_b.get_read_data()
+                assert data[0] == 256*(16*offset+length)+offset
+                assert data[1] == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+
+        yield delay(100)
+
+        yield a_clk.posedge
+        print("test 5: simultaneous read and write")
+        current_test.next = 5
+
+        wbm_inst_a.init_write(8, b'\xAA\xAA\xAA\xAA')
+        wbm_inst_b.init_write(12, b'\xBB\xBB\xBB\xBB')
+
+        yield wbm_inst_a.wait()
+        yield wbm_inst_b.wait()
+        yield a_clk.posedge
+
+        wbm_inst_a.init_read(12, 4)
+        wbm_inst_b.init_read(8, 4)
+
+        yield wbm_inst_a.wait()
+        yield wbm_inst_b.wait()
+        yield a_clk.posedge
+
+        data = wbm_inst_a.get_read_data()
+        assert data[0] == 12
+        assert data[1] == b'\xBB\xBB\xBB\xBB'
+        data = wbm_inst_b.get_read_data()
+        assert data[0] == 8
+        assert data[1] == b'\xAA\xAA\xAA\xAA'
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_dp_ram.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_dp_ram.v
new file mode 100644
index 0000000..d6b12b5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_dp_ram.v
@@ -0,0 +1,124 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for wb_dp_ram
+ */
+module test_wb_dp_ram;
+
+// Parameters
+parameter DATA_WIDTH = 32;
+parameter ADDR_WIDTH = 16;
+parameter SELECT_WIDTH = 4;
+
+// Inputs
+reg a_clk = 0;
+reg a_rst = 0;
+reg b_clk = 0;
+reg b_rst = 0;
+reg [7:0] current_test = 0;
+
+reg [ADDR_WIDTH-1:0] a_adr_i = 0;
+reg [DATA_WIDTH-1:0] a_dat_i = 0;
+reg a_we_i = 0;
+reg [SELECT_WIDTH-1:0] a_sel_i = 0;
+reg a_stb_i = 0;
+reg a_cyc_i = 0;
+reg [ADDR_WIDTH-1:0] b_adr_i = 0;
+reg [DATA_WIDTH-1:0] b_dat_i = 0;
+reg b_we_i = 0;
+reg [SELECT_WIDTH-1:0] b_sel_i = 0;
+reg b_stb_i = 0;
+reg b_cyc_i = 0;
+
+// Outputs
+wire [DATA_WIDTH-1:0] a_dat_o;
+wire a_ack_o;
+wire [DATA_WIDTH-1:0] b_dat_o;
+wire b_ack_o;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(
+        a_clk,
+        a_rst,
+        b_clk,
+        b_rst,
+        current_test,
+        a_adr_i,
+        a_dat_i,
+        a_we_i,
+        a_sel_i,
+        a_stb_i,
+        a_cyc_i,
+        b_adr_i,
+        b_dat_i,
+        b_we_i,
+        b_sel_i,
+        b_stb_i,
+        b_cyc_i
+    );
+    $to_myhdl(
+        a_dat_o,
+        a_ack_o,
+        b_dat_o,
+        b_ack_o
+    );
+
+    // dump file
+    $dumpfile("test_wb_dp_ram.lxt");
+    $dumpvars(0, test_wb_dp_ram);
+end
+
+wb_dp_ram #(
+    .DATA_WIDTH(DATA_WIDTH),
+    .ADDR_WIDTH(ADDR_WIDTH),
+    .SELECT_WIDTH(SELECT_WIDTH)
+)
+UUT (
+    .a_clk(a_clk),
+    .a_adr_i(a_adr_i),
+    .a_dat_i(a_dat_i),
+    .a_dat_o(a_dat_o),
+    .a_we_i(a_we_i),
+    .a_sel_i(a_sel_i),
+    .a_stb_i(a_stb_i),
+    .a_ack_o(a_ack_o),
+    .a_cyc_i(a_cyc_i),
+    .b_clk(b_clk),
+    .b_adr_i(b_adr_i),
+    .b_dat_i(b_dat_i),
+    .b_dat_o(b_dat_o),
+    .b_we_i(b_we_i),
+    .b_sel_i(b_sel_i),
+    .b_stb_i(b_stb_i),
+    .b_ack_o(b_ack_o),
+    .b_cyc_i(b_cyc_i)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_mux_2.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_mux_2.py
new file mode 100755
index 0000000..8891790
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_mux_2.py
@@ -0,0 +1,284 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+import wb
+
+module = 'wb_mux_2'
+testbench = 'test_%s' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("%s.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    DATA_WIDTH = 32
+    ADDR_WIDTH = 32
+    SELECT_WIDTH = 4
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    wbm_adr_i = Signal(intbv(0)[ADDR_WIDTH:])
+    wbm_dat_i = Signal(intbv(0)[DATA_WIDTH:])
+    wbm_we_i = Signal(bool(0))
+    wbm_sel_i = Signal(intbv(0)[SELECT_WIDTH:])
+    wbm_stb_i = Signal(bool(0))
+    wbm_cyc_i = Signal(bool(0))
+    wbs0_dat_i = Signal(intbv(0)[DATA_WIDTH:])
+    wbs0_ack_i = Signal(bool(0))
+    wbs0_err_i = Signal(bool(0))
+    wbs0_rty_i = Signal(bool(0))
+    wbs0_addr = Signal(intbv(0)[ADDR_WIDTH:])
+    wbs0_addr_msk = Signal(intbv(0)[ADDR_WIDTH:])
+    wbs1_dat_i = Signal(intbv(0)[DATA_WIDTH:])
+    wbs1_ack_i = Signal(bool(0))
+    wbs1_err_i = Signal(bool(0))
+    wbs1_rty_i = Signal(bool(0))
+    wbs1_addr = Signal(intbv(0)[ADDR_WIDTH:])
+    wbs1_addr_msk = Signal(intbv(0)[ADDR_WIDTH:])
+
+    # Outputs
+    wbm_dat_o = Signal(intbv(0)[DATA_WIDTH:])
+    wbm_ack_o = Signal(bool(0))
+    wbm_err_o = Signal(bool(0))
+    wbm_rty_o = Signal(bool(0))
+    wbs0_adr_o = Signal(intbv(0)[ADDR_WIDTH:])
+    wbs0_dat_o = Signal(intbv(0)[DATA_WIDTH:])
+    wbs0_we_o = Signal(bool(0))
+    wbs0_sel_o = Signal(intbv(0)[SELECT_WIDTH:])
+    wbs0_stb_o = Signal(bool(0))
+    wbs0_cyc_o = Signal(bool(0))
+    wbs1_adr_o = Signal(intbv(0)[ADDR_WIDTH:])
+    wbs1_dat_o = Signal(intbv(0)[DATA_WIDTH:])
+    wbs1_we_o = Signal(bool(0))
+    wbs1_sel_o = Signal(intbv(0)[SELECT_WIDTH:])
+    wbs1_stb_o = Signal(bool(0))
+    wbs1_cyc_o = Signal(bool(0))
+
+    # WB master
+    wbm_inst = wb.WBMaster()
+
+    wbm_logic = wbm_inst.create_logic(
+        clk,
+        adr_o=wbm_adr_i,
+        dat_i=wbm_dat_o,
+        dat_o=wbm_dat_i,
+        we_o=wbm_we_i,
+        sel_o=wbm_sel_i,
+        stb_o=wbm_stb_i,
+        ack_i=wbm_ack_o,
+        cyc_o=wbm_cyc_i,
+        name='master'
+    )
+
+    # WB RAM model
+    wb_ram0_inst = wb.WBRam(2**16)
+
+    wb_ram0_port0 = wb_ram0_inst.create_port(
+        clk,
+        adr_i=wbs0_adr_o,
+        dat_i=wbs0_dat_o,
+        dat_o=wbs0_dat_i,
+        we_i=wbs0_we_o,
+        sel_i=wbs0_sel_o,
+        stb_i=wbs0_stb_o,
+        ack_o=wbs0_ack_i,
+        cyc_i=wbs0_cyc_o,
+        latency=1,
+        asynchronous=False,
+        name='slave0'
+    )
+
+    # WB RAM model
+    wb_ram1_inst = wb.WBRam(2**16)
+
+    wb_ram1_port0 = wb_ram1_inst.create_port(
+        clk,
+        adr_i=wbs1_adr_o,
+        dat_i=wbs1_dat_o,
+        dat_o=wbs1_dat_i,
+        we_i=wbs1_we_o,
+        sel_i=wbs1_sel_o,
+        stb_i=wbs1_stb_o,
+        ack_o=wbs1_ack_i,
+        cyc_i=wbs1_cyc_o,
+        latency=1,
+        asynchronous=False,
+        name='slave1'
+    )
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        clk=clk,
+        rst=rst,
+        current_test=current_test,
+        wbm_adr_i=wbm_adr_i,
+        wbm_dat_i=wbm_dat_i,
+        wbm_dat_o=wbm_dat_o,
+        wbm_we_i=wbm_we_i,
+        wbm_sel_i=wbm_sel_i,
+        wbm_stb_i=wbm_stb_i,
+        wbm_ack_o=wbm_ack_o,
+        wbm_err_o=wbm_err_o,
+        wbm_rty_o=wbm_rty_o,
+        wbm_cyc_i=wbm_cyc_i,
+        wbs0_adr_o=wbs0_adr_o,
+        wbs0_dat_i=wbs0_dat_i,
+        wbs0_dat_o=wbs0_dat_o,
+        wbs0_we_o=wbs0_we_o,
+        wbs0_sel_o=wbs0_sel_o,
+        wbs0_stb_o=wbs0_stb_o,
+        wbs0_ack_i=wbs0_ack_i,
+        wbs0_err_i=wbs0_err_i,
+        wbs0_rty_i=wbs0_rty_i,
+        wbs0_cyc_o=wbs0_cyc_o,
+        wbs0_addr=wbs0_addr,
+        wbs0_addr_msk=wbs0_addr_msk,
+        wbs1_adr_o=wbs1_adr_o,
+        wbs1_dat_i=wbs1_dat_i,
+        wbs1_dat_o=wbs1_dat_o,
+        wbs1_we_o=wbs1_we_o,
+        wbs1_sel_o=wbs1_sel_o,
+        wbs1_stb_o=wbs1_stb_o,
+        wbs1_ack_i=wbs1_ack_i,
+        wbs1_err_i=wbs1_err_i,
+        wbs1_rty_i=wbs1_rty_i,
+        wbs1_cyc_o=wbs1_cyc_o,
+        wbs1_addr=wbs1_addr,
+        wbs1_addr_msk=wbs1_addr_msk
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        wbs0_addr.next = 0x00000000
+        wbs0_addr_msk.next = 0xFFFF0000
+
+        wbs1_addr.next = 0x00010000
+        wbs1_addr_msk.next = 0xFFFF0000
+
+        yield clk.posedge
+        print("test 1: write to slave 0")
+        current_test.next = 1
+
+        wbm_inst.init_write(0x00000004, b'\x11\x22\x33\x44')
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        data = wb_ram0_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram0_inst.read_mem(4,4) == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 2: read from slave 0")
+        current_test.next = 2
+
+        wbm_inst.init_read(0x00000004, 4)
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        data = wbm_inst.get_read_data()
+        assert data[0] == 0x00000004
+        assert data[1] == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 3: write to slave 1")
+        current_test.next = 3
+
+        wbm_inst.init_write(0x00010004, b'\x11\x22\x33\x44')
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        data = wb_ram1_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram1_inst.read_mem(4,4) == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 4: read from slave 1")
+        current_test.next = 4
+
+        wbm_inst.init_read(0x00010004, 4)
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        data = wbm_inst.get_read_data()
+        assert data[0] == 0x00010004
+        assert data[1] == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_mux_2.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_mux_2.v
new file mode 100644
index 0000000..81df242
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_mux_2.v
@@ -0,0 +1,170 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for wb_mux_2
+ */
+module test_wb_mux_2;
+
+// Parameters
+parameter DATA_WIDTH = 32;
+parameter ADDR_WIDTH = 32;
+parameter SELECT_WIDTH = 4;
+
+// Inputs
+reg clk = 0;
+reg rst = 0;
+reg [7:0] current_test = 0;
+
+reg [ADDR_WIDTH-1:0] wbm_adr_i = 0;
+reg [DATA_WIDTH-1:0] wbm_dat_i = 0;
+reg wbm_we_i = 0;
+reg [SELECT_WIDTH-1:0] wbm_sel_i = 0;
+reg wbm_stb_i = 0;
+reg wbm_cyc_i = 0;
+reg [DATA_WIDTH-1:0] wbs0_dat_i = 0;
+reg wbs0_ack_i = 0;
+reg wbs0_err_i = 0;
+reg wbs0_rty_i = 0;
+reg [ADDR_WIDTH-1:0] wbs0_addr = 0;
+reg [ADDR_WIDTH-1:0] wbs0_addr_msk = 0;
+reg [DATA_WIDTH-1:0] wbs1_dat_i = 0;
+reg wbs1_ack_i = 0;
+reg wbs1_err_i = 0;
+reg wbs1_rty_i = 0;
+reg [ADDR_WIDTH-1:0] wbs1_addr = 0;
+reg [ADDR_WIDTH-1:0] wbs1_addr_msk = 0;
+
+// Outputs
+wire [DATA_WIDTH-1:0] wbm_dat_o;
+wire wbm_ack_o;
+wire wbm_err_o;
+wire wbm_rty_o;
+wire [ADDR_WIDTH-1:0] wbs0_adr_o;
+wire [DATA_WIDTH-1:0] wbs0_dat_o;
+wire wbs0_we_o;
+wire [SELECT_WIDTH-1:0] wbs0_sel_o;
+wire wbs0_stb_o;
+wire wbs0_cyc_o;
+wire [ADDR_WIDTH-1:0] wbs1_adr_o;
+wire [DATA_WIDTH-1:0] wbs1_dat_o;
+wire wbs1_we_o;
+wire [SELECT_WIDTH-1:0] wbs1_sel_o;
+wire wbs1_stb_o;
+wire wbs1_cyc_o;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(clk,
+                rst,
+                current_test,
+                wbm_adr_i,
+                wbm_dat_i,
+                wbm_we_i,
+                wbm_sel_i,
+                wbm_stb_i,
+                wbm_cyc_i,
+                wbs0_dat_i,
+                wbs0_ack_i,
+                wbs0_err_i,
+                wbs0_rty_i,
+                wbs0_addr,
+                wbs0_addr_msk,
+                wbs1_dat_i,
+                wbs1_ack_i,
+                wbs1_err_i,
+                wbs1_rty_i,
+                wbs1_addr,
+                wbs1_addr_msk);
+    $to_myhdl(wbm_dat_o,
+              wbm_ack_o,
+              wbm_err_o,
+              wbm_rty_o,
+              wbs0_adr_o,
+              wbs0_dat_o,
+              wbs0_we_o,
+              wbs0_sel_o,
+              wbs0_stb_o,
+              wbs0_cyc_o,
+              wbs1_adr_o,
+              wbs1_dat_o,
+              wbs1_we_o,
+              wbs1_sel_o,
+              wbs1_stb_o,
+              wbs1_cyc_o);
+
+    // dump file
+    $dumpfile("test_wb_mux_2.lxt");
+    $dumpvars(0, test_wb_mux_2);
+end
+
+wb_mux_2 #(
+    .DATA_WIDTH(DATA_WIDTH),
+    .ADDR_WIDTH(ADDR_WIDTH),
+    .SELECT_WIDTH(SELECT_WIDTH)
+)
+UUT (
+    .clk(clk),
+    .rst(rst),
+    .wbm_adr_i(wbm_adr_i),
+    .wbm_dat_i(wbm_dat_i),
+    .wbm_dat_o(wbm_dat_o),
+    .wbm_we_i(wbm_we_i),
+    .wbm_sel_i(wbm_sel_i),
+    .wbm_stb_i(wbm_stb_i),
+    .wbm_ack_o(wbm_ack_o),
+    .wbm_err_o(wbm_err_o),
+    .wbm_rty_o(wbm_rty_o),
+    .wbm_cyc_i(wbm_cyc_i),
+    .wbs0_adr_o(wbs0_adr_o),
+    .wbs0_dat_i(wbs0_dat_i),
+    .wbs0_dat_o(wbs0_dat_o),
+    .wbs0_we_o(wbs0_we_o),
+    .wbs0_sel_o(wbs0_sel_o),
+    .wbs0_stb_o(wbs0_stb_o),
+    .wbs0_ack_i(wbs0_ack_i),
+    .wbs0_err_i(wbs0_err_i),
+    .wbs0_rty_i(wbs0_rty_i),
+    .wbs0_cyc_o(wbs0_cyc_o),
+    .wbs0_addr(wbs0_addr),
+    .wbs0_addr_msk(wbs0_addr_msk),
+    .wbs1_adr_o(wbs1_adr_o),
+    .wbs1_dat_i(wbs1_dat_i),
+    .wbs1_dat_o(wbs1_dat_o),
+    .wbs1_we_o(wbs1_we_o),
+    .wbs1_sel_o(wbs1_sel_o),
+    .wbs1_stb_o(wbs1_stb_o),
+    .wbs1_ack_i(wbs1_ack_i),
+    .wbs1_err_i(wbs1_err_i),
+    .wbs1_rty_i(wbs1_rty_i),
+    .wbs1_cyc_o(wbs1_cyc_o),
+    .wbs1_addr(wbs1_addr),
+    .wbs1_addr_msk(wbs1_addr_msk)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_ram.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_ram.py
new file mode 100755
index 0000000..7b43232
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_ram.py
@@ -0,0 +1,170 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+import wb
+
+module = 'wb_ram'
+testbench = 'test_%s' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("%s.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    DATA_WIDTH = 32
+    ADDR_WIDTH = 16
+    SELECT_WIDTH = 4
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    adr_i = Signal(intbv(0)[ADDR_WIDTH:])
+    dat_i = Signal(intbv(0)[DATA_WIDTH:])
+    we_i = Signal(bool(0))
+    sel_i = Signal(intbv(0)[SELECT_WIDTH:])
+    stb_i = Signal(bool(0))
+    cyc_i = Signal(bool(0))
+
+    # Outputs
+    dat_o = Signal(intbv(0)[DATA_WIDTH:])
+    ack_o = Signal(bool(0))
+
+    # WB master
+    wbm_inst = wb.WBMaster()
+
+    wbm_logic = wbm_inst.create_logic(
+        clk,
+        adr_o=adr_i,
+        dat_i=dat_o,
+        dat_o=dat_i,
+        we_o=we_i,
+        sel_o=sel_i,
+        stb_o=stb_i,
+        ack_i=ack_o,
+        cyc_o=cyc_i,
+        name='master'
+    )
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        clk=clk,
+        rst=rst,
+        current_test=current_test,
+        adr_i=adr_i,
+        dat_i=dat_i,
+        dat_o=dat_o,
+        we_i=we_i,
+        sel_i=sel_i,
+        stb_i=stb_i,
+        ack_o=ack_o,
+        cyc_i=cyc_i
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        yield clk.posedge
+        print("test 1: read and write")
+        current_test.next = 1
+
+        wbm_inst.init_write(4, b'\x11\x22\x33\x44')
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        wbm_inst.init_read(4, 4)
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        data = wbm_inst.get_read_data()
+        assert data[0] == 4
+        assert data[1] == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 2: various reads and writes")
+        current_test.next = 2
+
+        for length in range(1,8):
+            for offset in range(4):
+                wbm_inst.init_write(256*(16*offset+length)+offset, b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length])
+
+                yield wbm_inst.wait()
+                yield clk.posedge
+
+        for length in range(1,8):
+            for offset in range(4):
+                wbm_inst.init_read(256*(16*offset+length)+offset, length)
+
+                yield wbm_inst.wait()
+                yield clk.posedge
+
+                data = wbm_inst.get_read_data()
+                assert data[0] == 256*(16*offset+length)+offset
+                assert data[1] == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_ram.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_ram.v
new file mode 100644
index 0000000..707d04c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_ram.v
@@ -0,0 +1,95 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for wb_ram
+ */
+module test_wb_ram;
+
+// Parameters
+parameter DATA_WIDTH = 32;
+parameter ADDR_WIDTH = 16;
+parameter SELECT_WIDTH = 4;
+
+// Inputs
+reg clk = 0;
+reg rst = 0;
+reg [7:0] current_test = 0;
+
+reg [ADDR_WIDTH-1:0] adr_i = 0;
+reg [DATA_WIDTH-1:0] dat_i = 0;
+reg we_i = 0;
+reg [SELECT_WIDTH-1:0] sel_i = 0;
+reg stb_i = 0;
+reg cyc_i = 0;
+
+// Outputs
+wire [DATA_WIDTH-1:0] dat_o;
+wire ack_o;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(
+        clk,
+        rst,
+        current_test,
+        adr_i,
+        dat_i,
+        we_i,
+        sel_i,
+        stb_i,
+        cyc_i
+    );
+    $to_myhdl(
+        dat_o,
+        ack_o
+    );
+
+    // dump file
+    $dumpfile("test_wb_ram.lxt");
+    $dumpvars(0, test_wb_ram);
+end
+
+wb_ram #(
+    .DATA_WIDTH(DATA_WIDTH),
+    .ADDR_WIDTH(ADDR_WIDTH),
+    .SELECT_WIDTH(SELECT_WIDTH)
+)
+UUT (
+    .clk(clk),
+    .adr_i(adr_i),
+    .dat_i(dat_i),
+    .dat_o(dat_o),
+    .we_i(we_i),
+    .sel_i(sel_i),
+    .stb_i(stb_i),
+    .ack_o(ack_o),
+    .cyc_i(cyc_i)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_ram_model.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_ram_model.py
new file mode 100755
index 0000000..5daeb7a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_ram_model.py
@@ -0,0 +1,259 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+import wb
+
+def bench():
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    port0_adr_i = Signal(intbv(0)[32:])
+    port0_dat_i = Signal(intbv(0)[32:])
+    port0_we_i = Signal(bool(0))
+    port0_sel_i = Signal(intbv(0)[4:])
+    port0_stb_i = Signal(bool(0))
+    port0_cyc_i = Signal(bool(0))
+
+    # Outputs
+    port0_dat_o = Signal(intbv(0)[32:])
+    port0_ack_o = Signal(bool(0))
+
+    # WB RAM model
+    wb_ram_inst = wb.WBRam(2**16)
+
+    wb_ram_port0 = wb_ram_inst.create_port(
+        clk,
+        adr_i=port0_adr_i,
+        dat_i=port0_dat_i,
+        dat_o=port0_dat_o,
+        we_i=port0_we_i,
+        sel_i=port0_sel_i,
+        stb_i=port0_stb_i,
+        ack_o=port0_ack_o,
+        cyc_i=port0_cyc_i,
+        latency=1,
+        asynchronous=False,
+        name='port0'
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        yield clk.posedge
+        print("test 1: baseline")
+        current_test.next = 1
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 2: direct write")
+        current_test.next = 2
+
+        wb_ram_inst.write_mem(0, b'test')
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(0,4) == b'test'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 2: write via port0")
+        current_test.next = 2
+
+        yield clk.posedge
+        port0_adr_i.next = 4
+        port0_dat_i.next = 0x44332211
+        port0_sel_i.next = 0xF
+        port0_we_i.next = 1
+
+        port0_cyc_i.next = 1
+        port0_stb_i.next = 1
+
+        yield port0_ack_o.posedge
+        yield clk.posedge
+        port0_we_i.next = 0
+        port0_cyc_i.next = 0
+        port0_stb_i.next = 0
+
+        yield clk.posedge
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(4,4) == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 3: read via port0")
+        current_test.next = 3
+
+        yield clk.posedge
+        port0_adr_i.next = 4
+        port0_we_i.next = 0
+
+        port0_cyc_i.next = 1
+        port0_stb_i.next = 1
+
+        yield port0_ack_o.posedge
+        yield clk.posedge
+        port0_we_i.next = 0
+        port0_cyc_i.next = 0
+        port0_stb_i.next = 0
+
+        assert port0_dat_o == 0x44332211
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 4: various writes")
+        current_test.next = 4
+
+        for length in range(1,8):
+            for offset in range(4):
+                yield clk.posedge
+                sel_start = ((2**(4)-1) << offset % 4) & (2**(4)-1)
+                sel_end = ((2**(4)-1) >> (4 - (((offset + int(length/1) - 1) % 4) + 1)))
+                cycles = int((length + 4-1 + (offset % 4)) / 4)
+                i = 1
+
+                port0_cyc_i.next = 1
+
+                port0_stb_i.next = 1
+                port0_we_i.next = 1
+                port0_adr_i.next = 256*(16*offset+length)
+                val = 0
+                for j in range(4):
+                    if j >= offset % 4 and (cycles > 1 or j < (((offset + int(length/1) - 1) % 4) + 1)):
+                        val |= (0x11 * i) << j*8
+                        i += 1
+                port0_dat_i.next = val
+                if cycles == 1:
+                    port0_sel_i.next = sel_start & sel_end
+                else:
+                    port0_sel_i.next = sel_start
+
+                yield clk.posedge
+                while not port0_ack_o:
+                    yield clk.posedge
+
+                port0_we_i.next = 0
+                port0_stb_i.next = 0
+
+                for k in range(1,cycles-1):
+                    yield clk.posedge
+                    port0_stb_i.next = 1
+                    port0_we_i.next = 1
+                    port0_adr_i.next = 256*(16*offset+length)+4*k
+                    val = 0
+                    for j in range(4):
+                        val |= (0x11 * i) << j*8
+                        i += 1
+                    port0_dat_i.next = val
+                    port0_sel_i.next = 2**(4)-1
+
+                    yield clk.posedge
+                    while not port0_ack_o:
+                        yield clk.posedge
+
+                    port0_we_i.next = 0
+                    port0_stb_i.next = 0
+
+                if cycles > 1:
+                    yield clk.posedge
+                    port0_stb_i.next = 1
+                    port0_we_i.next = 1
+                    port0_adr_i.next = 256*(16*offset+length)+4*(cycles-1)
+                    val = 0
+                    for j in range(4):
+                        if j < (((offset + int(length/1) - 1) % 4) + 1):
+                            val |= (0x11 * i) << j*8
+                            i += 1
+                    port0_dat_i.next = val
+                    port0_sel_i.next = sel_end
+
+                    yield clk.posedge
+                    while not port0_ack_o:
+                        yield clk.posedge
+
+                    port0_we_i.next = 0
+                    port0_stb_i.next = 0
+
+                port0_we_i.next = 0
+                port0_stb_i.next = 0
+
+                port0_cyc_i.next = 0
+
+                yield clk.posedge
+                yield clk.posedge
+
+                data = wb_ram_inst.read_mem(256*(16*offset+length), 32)
+                for i in range(0, len(data), 16):
+                    print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset,length) == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    os.chdir(os.path.dirname(os.path.abspath(__file__)))
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
+
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_reg.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_reg.py
new file mode 100755
index 0000000..0a682ec
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_reg.py
@@ -0,0 +1,239 @@
+#!/usr/bin/env python
+"""
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import os
+
+import wb
+
+module = 'wb_reg'
+testbench = 'test_%s' % module
+
+srcs = []
+
+srcs.append("../rtl/%s.v" % module)
+srcs.append("%s.v" % testbench)
+
+src = ' '.join(srcs)
+
+build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
+
+def bench():
+
+    # Parameters
+    DATA_WIDTH = 32
+    ADDR_WIDTH = 32
+    SELECT_WIDTH = 4
+
+    # Inputs
+    clk = Signal(bool(0))
+    rst = Signal(bool(0))
+    current_test = Signal(intbv(0)[8:])
+
+    wbm_adr_i = Signal(intbv(0)[ADDR_WIDTH:])
+    wbm_dat_i = Signal(intbv(0)[DATA_WIDTH:])
+    wbm_we_i = Signal(bool(0))
+    wbm_sel_i = Signal(intbv(0)[SELECT_WIDTH:])
+    wbm_stb_i = Signal(bool(0))
+    wbm_cyc_i = Signal(bool(0))
+    wbs_dat_i = Signal(intbv(0)[DATA_WIDTH:])
+    wbs_ack_i = Signal(bool(0))
+    wbs_err_i = Signal(bool(0))
+    wbs_rty_i = Signal(bool(0))
+
+    # Outputs
+    wbm_dat_o = Signal(intbv(0)[DATA_WIDTH:])
+    wbm_ack_o = Signal(bool(0))
+    wbm_err_o = Signal(bool(0))
+    wbm_rty_o = Signal(bool(0))
+    wbs_adr_o = Signal(intbv(0)[ADDR_WIDTH:])
+    wbs_dat_o = Signal(intbv(0)[DATA_WIDTH:])
+    wbs_we_o = Signal(bool(0))
+    wbs_sel_o = Signal(intbv(0)[SELECT_WIDTH:])
+    wbs_stb_o = Signal(bool(0))
+    wbs_cyc_o = Signal(bool(0))
+
+    # WB master
+    wbm_inst = wb.WBMaster()
+
+    wbm_logic = wbm_inst.create_logic(
+        clk,
+        adr_o=wbm_adr_i,
+        dat_i=wbm_dat_o,
+        dat_o=wbm_dat_i,
+        we_o=wbm_we_i,
+        sel_o=wbm_sel_i,
+        stb_o=wbm_stb_i,
+        ack_i=wbm_ack_o,
+        cyc_o=wbm_cyc_i,
+        name='master'
+    )
+
+    # WB RAM model
+    wb_ram_inst = wb.WBRam(2**16)
+
+    wb_ram_port0 = wb_ram_inst.create_port(
+        clk,
+        adr_i=wbs_adr_o,
+        dat_i=wbs_dat_o,
+        dat_o=wbs_dat_i,
+        we_i=wbs_we_o,
+        sel_i=wbs_sel_o,
+        stb_i=wbs_stb_o,
+        ack_o=wbs_ack_i,
+        cyc_i=wbs_cyc_o,
+        latency=1,
+        asynchronous=False,
+        name='slave'
+    )
+
+    # DUT
+    if os.system(build_cmd):
+        raise Exception("Error running build command")
+
+    dut = Cosimulation(
+        "vvp -m myhdl %s.vvp -lxt2" % testbench,
+        clk=clk,
+        rst=rst,
+        current_test=current_test,
+        wbm_adr_i=wbm_adr_i,
+        wbm_dat_i=wbm_dat_i,
+        wbm_dat_o=wbm_dat_o,
+        wbm_we_i=wbm_we_i,
+        wbm_sel_i=wbm_sel_i,
+        wbm_stb_i=wbm_stb_i,
+        wbm_ack_o=wbm_ack_o,
+        wbm_err_o=wbm_err_o,
+        wbm_rty_o=wbm_rty_o,
+        wbm_cyc_i=wbm_cyc_i,
+        wbs_adr_o=wbs_adr_o,
+        wbs_dat_i=wbs_dat_i,
+        wbs_dat_o=wbs_dat_o,
+        wbs_we_o=wbs_we_o,
+        wbs_sel_o=wbs_sel_o,
+        wbs_stb_o=wbs_stb_o,
+        wbs_ack_i=wbs_ack_i,
+        wbs_err_i=wbs_err_i,
+        wbs_rty_i=wbs_rty_i,
+        wbs_cyc_o=wbs_cyc_o
+    )
+
+    @always(delay(4))
+    def clkgen():
+        clk.next = not clk
+
+    @instance
+    def check():
+        yield delay(100)
+        yield clk.posedge
+        rst.next = 1
+        yield clk.posedge
+        rst.next = 0
+        yield clk.posedge
+        yield delay(100)
+        yield clk.posedge
+
+        yield clk.posedge
+        print("test 1: write")
+        current_test.next = 1
+
+        wbm_inst.init_write(4, b'\x11\x22\x33\x44')
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        data = wb_ram_inst.read_mem(0, 32)
+        for i in range(0, len(data), 16):
+            print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+        assert wb_ram_inst.read_mem(4,4) == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 2: read")
+        current_test.next = 2
+
+        wbm_inst.init_read(4, 4)
+
+        yield wbm_inst.wait()
+        yield clk.posedge
+
+        data = wbm_inst.get_read_data()
+        assert data[0] == 4
+        assert data[1] == b'\x11\x22\x33\x44'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 3: various writes")
+        current_test.next = 3
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wb_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*32)
+                wbm_inst.init_write(256*(16*offset+length)+offset, b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length])
+
+                yield wbm_inst.wait()
+                yield clk.posedge
+
+                data = wb_ram_inst.read_mem(256*(16*offset+length), 32)
+                for i in range(0, len(data), 16):
+                    print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
+
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset-1, 1) == b'\xAA'
+                assert wb_ram_inst.read_mem(256*(16*offset+length)+offset+length, 1) == b'\xAA'
+
+        yield delay(100)
+
+        yield clk.posedge
+        print("test 4: various reads")
+        current_test.next = 4
+
+        for length in range(1,8):
+            for offset in range(4,8):
+                wbm_inst.init_read(256*(16*offset+length)+offset, length)
+
+                yield wbm_inst.wait()
+                yield clk.posedge
+
+                data = wbm_inst.get_read_data()
+                assert data[0] == 256*(16*offset+length)+offset
+                assert data[1] == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
+
+        yield delay(100)
+
+        raise StopSimulation
+
+    return instances()
+
+def test_bench():
+    sim = Simulation(bench())
+    sim.run()
+
+if __name__ == '__main__':
+    print("Running test...")
+    test_bench()
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_reg.v b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_reg.v
new file mode 100644
index 0000000..3a20813
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/test_wb_reg.v
@@ -0,0 +1,132 @@
+/*
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// Language: Verilog 2001
+
+`timescale 1ns / 1ps
+
+/*
+ * Testbench for wb_reg
+ */
+module test_wb_reg;
+
+// Parameters
+parameter DATA_WIDTH = 32;
+parameter ADDR_WIDTH = 32;
+parameter SELECT_WIDTH = 4;
+
+// Inputs
+reg clk = 0;
+reg rst = 0;
+reg [7:0] current_test = 0;
+
+reg [ADDR_WIDTH-1:0] wbm_adr_i = 0;
+reg [DATA_WIDTH-1:0] wbm_dat_i = 0;
+reg wbm_we_i = 0;
+reg [SELECT_WIDTH-1:0] wbm_sel_i = 0;
+reg wbm_stb_i = 0;
+reg wbm_cyc_i = 0;
+reg [DATA_WIDTH-1:0] wbs_dat_i = 0;
+reg wbs_ack_i = 0;
+reg wbs_err_i = 0;
+reg wbs_rty_i = 0;
+
+// Outputs
+wire [DATA_WIDTH-1:0] wbm_dat_o;
+wire wbm_ack_o;
+wire wbm_err_o;
+wire wbm_rty_o;
+wire [ADDR_WIDTH-1:0] wbs_adr_o;
+wire [DATA_WIDTH-1:0] wbs_dat_o;
+wire wbs_we_o;
+wire [SELECT_WIDTH-1:0] wbs_sel_o;
+wire wbs_stb_o;
+wire wbs_cyc_o;
+
+initial begin
+    // myhdl integration
+    $from_myhdl(
+        clk,
+        rst,
+        current_test,
+        wbm_adr_i,
+        wbm_dat_i,
+        wbm_we_i,
+        wbm_sel_i,
+        wbm_stb_i,
+        wbm_cyc_i,
+        wbs_dat_i,
+        wbs_ack_i,
+        wbs_err_i,
+        wbs_rty_i
+    );
+    $to_myhdl(
+        wbm_dat_o,
+        wbm_ack_o,
+        wbm_err_o,
+        wbm_rty_o,
+        wbs_adr_o,
+        wbs_dat_o,
+        wbs_we_o,
+        wbs_sel_o,
+        wbs_stb_o,
+        wbs_cyc_o
+    );
+
+    // dump file
+    $dumpfile("test_wb_reg.lxt");
+    $dumpvars(0, test_wb_reg);
+end
+
+wb_reg #(
+    .DATA_WIDTH(DATA_WIDTH),
+    .ADDR_WIDTH(ADDR_WIDTH),
+    .SELECT_WIDTH(SELECT_WIDTH)
+)
+UUT (
+    .clk(clk),
+    .rst(rst),
+    .wbm_adr_i(wbm_adr_i),
+    .wbm_dat_i(wbm_dat_i),
+    .wbm_dat_o(wbm_dat_o),
+    .wbm_we_i(wbm_we_i),
+    .wbm_sel_i(wbm_sel_i),
+    .wbm_stb_i(wbm_stb_i),
+    .wbm_ack_o(wbm_ack_o),
+    .wbm_err_o(wbm_err_o),
+    .wbm_rty_o(wbm_rty_o),
+    .wbm_cyc_i(wbm_cyc_i),
+    .wbs_adr_o(wbs_adr_o),
+    .wbs_dat_i(wbs_dat_i),
+    .wbs_dat_o(wbs_dat_o),
+    .wbs_we_o(wbs_we_o),
+    .wbs_sel_o(wbs_sel_o),
+    .wbs_stb_o(wbs_stb_o),
+    .wbs_ack_i(wbs_ack_i),
+    .wbs_err_i(wbs_err_i),
+    .wbs_rty_i(wbs_rty_i),
+    .wbs_cyc_o(wbs_cyc_o)
+);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/verilog-wishbone/tb/wb.py b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/wb.py
new file mode 100644
index 0000000..b618ef8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/verilog-wishbone/tb/wb.py
@@ -0,0 +1,441 @@
+"""
+
+Copyright (c) 2015-2016 Alex Forencich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+"""
+
+from myhdl import *
+import mmap
+
+class WBMaster(object):
+    def __init__(self):
+        self.command_queue = []
+        self.read_data_queue = []
+        self.has_logic = False
+        self.clk = None
+        self.cyc_o = None
+
+    def init_read(self, address, length):
+        self.command_queue.append(('r', address, length))
+
+    def init_read_words(self, address, length, ws=2):
+        assert ws in (1, 2, 4, 8)
+        self.init_read(int(address*ws), int(length*ws))
+
+    def init_read_dwords(self, address, length):
+        self.init_read_words(address, length, 4)
+
+    def init_read_qwords(self, address, length):
+        self.init_read_words(address, length, 8)
+
+    def init_write(self, address, data):
+        self.command_queue.append(('w', address, data))
+
+    def init_write_words(self, address, data, ws=2):
+        assert ws in (1, 2, 4, 8)
+        data2 = []
+        for w in data:
+            d = []
+            for j in range(ws):
+                d.append(w&0xff)
+                w >>= 8
+            data2.extend(bytearray(d))
+        self.init_write(int(address*ws), data2)
+
+    def init_write_dwords(self, address, data):
+        self.init_write_words(address, data, 4)
+
+    def init_write_qwords(self, address, data):
+        self.init_write_words(address, data, 8)
+
+    def idle(self):
+        return len(self.command_queue) == 0 and not self.cyc_o.next
+
+    def wait(self):
+        while not self.idle():
+            yield self.clk.posedge
+
+    def read_data_ready(self):
+        return not self.read_data_queue
+
+    def get_read_data(self):
+        return self.read_data_queue.pop(0)
+
+    def get_read_data_words(self, ws=2):
+        assert ws in (1, 2, 4, 8)
+        v = self.get_read_data()
+        if v is None:
+            return None
+        address, data = v
+        d = []
+        for i in range(int(len(data)/ws)):
+            w = 0
+            for j in range(ws-1,-1,-1):
+                w <<= 8
+                w += data[i*ws+j]
+            d.append(w)
+        return (int(address/ws), d)
+
+    def get_read_data_dwords(self):
+        return self.get_read_data_words(4)
+
+    def get_read_data_qwords(self):
+        return self.get_read_data_words(8)
+
+    def create_logic(self,
+                clk,
+                adr_o=Signal(intbv(0)[8:]),
+                dat_i=None,
+                dat_o=None,
+                we_o=Signal(bool(0)),
+                sel_o=Signal(intbv(1)[1:]),
+                stb_o=Signal(bool(0)),
+                ack_i=Signal(bool(0)),
+                cyc_o=Signal(bool(0)),
+                name=None
+            ):
+
+        if self.has_logic:
+            raise Exception("Logic already instantiated!")
+
+        if dat_i is not None:
+            assert len(dat_i) % 8 == 0
+            w = len(dat_i)
+        if dat_o is not None:
+            assert len(dat_o) % 8 == 0
+            w = len(dat_o)
+        if dat_i is not None and dat_o is not None:
+            assert len(dat_i) == len(dat_o)
+
+        bw = int(w/8)   # width of bus in bytes
+        ww = len(sel_o) # width of bus in words
+        ws = int(bw/ww) # word size in bytes
+
+        assert ww in (1, 2, 4, 8)
+        assert ws in (1, 2, 4, 8)
+
+        self.has_logic = True
+        self.clk = clk
+        self.cyc_o = cyc_o
+
+        @instance
+        def logic():
+            while True:
+                yield clk.posedge
+
+                # check for commands
+                if len(self.command_queue) > 0:
+                    cmd = self.command_queue.pop(0)
+
+                    # address
+                    addr = cmd[1]
+                    # address in words
+                    adw = int(addr/ws)
+                    # select for first access
+                    sel_start = ((2**(ww)-1) << int(adw % ww)) & (2**(ww)-1)
+
+                    if cmd[0] == 'w':
+                        data = cmd[2]
+                        # select for last access
+                        sel_end = (2**(ww)-1) >> int(ww - (((int((addr+len(data)-1)/ws)) % ww) + 1))
+                        # number of cycles
+                        cycles = int((len(data) + bw-1 + (addr % bw)) / bw)
+                        i = 0
+
+                        if name is not None:
+                            print("[%s] Write data a:0x%08x d:%s" % (name, addr, " ".join(("{:02x}".format(c) for c in bytearray(data)))))
+
+                        cyc_o.next = 1
+
+                        # first cycle
+                        stb_o.next = 1
+                        we_o.next = 1
+                        adr_o.next = int(adw/ww)*ww
+                        val = 0
+                        for j in range(bw):
+                            if j >= addr % bw and (cycles > 1 or j < (((addr + len(data) - 1) % bw) + 1)):
+                                val |= bytearray(data)[i] << j*8
+                                i += 1
+                        dat_o.next = val
+
+                        if cycles == 1:
+                            sel_o.next = sel_start & sel_end
+                        else:
+                            sel_o.next = sel_start
+
+                        yield clk.posedge
+                        while not int(ack_i):
+                            yield clk.posedge
+
+                        stb_o.next = 0
+                        we_o.next = 0
+
+                        for k in range(1, cycles-1):
+                            # middle cycles
+                            yield clk.posedge
+                            stb_o.next = 1
+                            we_o.next = 1
+                            adr_o.next = int(adw/ww)*ww + k * ww
+                            val = 0
+                            for j in range(bw):
+                                val |= bytearray(data)[i] << j*8
+                                i += 1
+                            dat_o.next = val
+                            sel_o.next = 2**(ww)-1
+
+                            yield clk.posedge
+                            while not int(ack_i):
+                                yield clk.posedge
+
+                            stb_o.next = 0
+                            we_o.next = 0
+
+                        if cycles > 1:
+                            # last cycle
+                            yield clk.posedge
+                            stb_o.next = 1
+                            we_o.next = 1
+                            adr_o.next = int(adw/ww)*ww + (cycles-1) * ww
+                            val = 0
+                            for j in range(bw):
+                                if j < (((addr + len(data) - 1) % bw) + 1):
+                                    val |= bytearray(data)[i] << j*8
+                                    i += 1
+                            dat_o.next = val
+                            sel_o.next = sel_end
+
+                            yield clk.posedge
+                            while not int(ack_i):
+                                yield clk.posedge
+
+                            stb_o.next = 0
+                            we_o.next = 0
+
+                        we_o.next = 0
+                        stb_o.next = 0
+
+                        cyc_o.next = 0
+
+                    elif cmd[0] == 'r':
+                        length = cmd[2]
+                        data = b''
+                        # select for last access
+                        sel_end = (2**(ww)-1) >> int(ww - (((int((addr+length-1)/ws)) % ww) + 1))
+                        # number of cycles
+                        cycles = int((length + bw-1 + (addr % bw)) / bw)
+
+                        cyc_o.next = 1
+
+                        # first cycle
+                        stb_o.next = 1
+                        adr_o.next = int(adw/ww)*ww
+                        if cycles == 1:
+                            sel_o.next = sel_start & sel_end
+                        else:
+                            sel_o.next = sel_start
+
+                        yield clk.posedge
+                        while not int(ack_i):
+                            yield clk.posedge
+
+                        stb_o.next = 0
+
+                        val = int(dat_i)
+
+                        for j in range(bw):
+                            if j >= addr % bw and (cycles > 1 or j < (((addr + length - 1) % bw) + 1)):
+                                data += bytes(bytearray([(val >> j*8) & 255]))
+
+                        for k in range(1, cycles-1):
+                            # middle cycles
+                            yield clk.posedge
+                            stb_o.next = 1
+                            adr_o.next = int(adw/ww)*ww + k * ww
+                            sel_o.next = 2**(ww)-1
+
+                            yield clk.posedge
+                            while not int(ack_i):
+                                yield clk.posedge
+
+                            stb_o.next = 0
+
+                            val = int(dat_i)
+
+                            for j in range(bw):
+                                data += bytes(bytearray([(val >> j*8) & 255]))
+
+                        if cycles > 1:
+                            # last cycle
+                            yield clk.posedge
+                            stb_o.next = 1
+                            adr_o.next = int(adw/ww)*ww + (cycles-1) * ww
+                            sel_o.next = sel_end
+
+                            yield clk.posedge
+                            while not int(ack_i):
+                                yield clk.posedge
+
+                            stb_o.next = 0
+
+                            val = int(dat_i)
+
+                            for j in range(bw):
+                                if j < (((addr + length - 1) % bw) + 1):
+                                    data += bytes(bytearray([(val >> j*8) & 255]))
+
+                        stb_o.next = 0
+                        cyc_o.next = 0
+
+                        if name is not None:
+                            print("[%s] Read data a:0x%08x d:%s" % (name, addr, " ".join(("{:02x}".format(c) for c in bytearray(data)))))
+
+                        self.read_data_queue.append((addr, data))
+
+        return instances()
+
+
+class WBRam(object):
+    def __init__(self, size = 1024):
+        self.size = size
+        self.mem = mmap.mmap(-1, size)
+
+    def read_mem(self, address, length):
+        self.mem.seek(address)
+        return self.mem.read(length)
+
+    def write_mem(self, address, data):
+        self.mem.seek(address)
+        self.mem.write(data)
+
+    def read_words(self, address, length, ws=2):
+        assert ws in (1, 2, 4, 8)
+        self.mem.seek(int(address*ws))
+        d = []
+        for i in range(length):
+            w = 0
+            data = bytearray(self.mem.read(ws))
+            for j in range(ws-1,-1,-1):
+                w <<= 8
+                w += data[j]
+            d.append(w)
+        return d
+
+    def read_dwords(self, address, length):
+        return self.read_words(address, length, 4)
+
+    def read_qwords(self, address, length):
+        return self.read_words(address, length, 8)
+
+    def write_words(self, address, data, ws=2):
+        assert ws in (1, 2, 4, 8)
+        self.mem.seek(int(address*ws))
+        for w in data:
+            d = []
+            for j in range(ws):
+                d.append(w&0xff)
+                w >>= 8
+            self.mem.write(bytearray(d))
+
+    def write_dwords(self, address, length):
+        return self.write_words(address, length, 4)
+
+    def write_qwords(self, address, length):
+        return self.write_words(address, length, 8)
+
+    def create_port(self,
+                clk,
+                adr_i=Signal(intbv(0)[8:]),
+                dat_i=None,
+                dat_o=None,
+                we_i=Signal(bool(0)),
+                sel_i=Signal(intbv(1)[1:]),
+                stb_i=Signal(bool(0)),
+                ack_o=Signal(bool(0)),
+                cyc_i=Signal(bool(0)),
+                latency=1,
+                asynchronous=False,
+                name=None
+            ):
+
+        if dat_i is not None:
+            assert len(dat_i) % 8 == 0
+            w = len(dat_i)
+        if dat_o is not None:
+            assert len(dat_o) % 8 == 0
+            w = len(dat_o)
+        if dat_i is not None and dat_o is not None:
+            assert len(dat_i) == len(dat_o)
+
+        bw = int(w/8)   # width of bus in bytes
+        ww = len(sel_i) # width of bus in words
+        ws = int(bw/ww) # word size in bytes
+
+        assert ww in (1, 2, 4, 8)
+        assert ws in (1, 2, 4, 8)
+
+        @instance
+        def logic():
+            while True:
+                if asynchronous:
+                    yield adr_i, cyc_i, stb_i
+                else:
+                    yield clk.posedge
+
+                ack_o.next = False
+
+                # address in increments of bus word width
+                addr = int(int(adr_i)/ww)*ww
+
+                if cyc_i & stb_i & ~ack_o:
+                    if asynchronous:
+                        yield delay(latency)
+                    else:
+                        for i in range(latency):
+                            yield clk.posedge
+                    ack_o.next = True
+                    self.mem.seek(addr*ws % self.size)
+                    if we_i:
+                        # write
+                        data = []
+                        val = int(dat_i)
+                        for i in range(bw):
+                            data += [val & 0xff]
+                            val >>= 8
+                        data = bytearray(data)
+                        for i in range(ww):
+                            if sel_i & (1 << i):
+                                self.mem.write(data[i*ws:(i+1)*ws])
+                            else:
+                                self.mem.seek(ws, 1)
+                        if name is not None:
+                            print("[%s] Write word a:0x%08x sel:0x%02x d:%s" % (name, addr, sel_i, " ".join(("{:02x}".format(c) for c in bytearray(data)))))
+                    else:
+                        data = bytearray(self.mem.read(bw))
+                        val = 0
+                        for i in range(bw-1,-1,-1):
+                            val <<= 8
+                            val += data[i]
+                        dat_o.next = val
+                        if name is not None:
+                            print("[%s] Read word a:0x%08x d:%s" % (name, addr, " ".join(("{:02x}".format(c) for c in bytearray(data)))))
+
+        return instances()
+
diff --git a/verilog/rtl/softshell/third_party/wb2axip/.gitignore b/verilog/rtl/softshell/third_party/wb2axip/.gitignore
new file mode 100644
index 0000000..7df043a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/.gitignore
@@ -0,0 +1,26 @@
+legal.txt
+a.out
+.svn
+xilinx
+obj_dir
+obj-pc
+obj-zip
+*.o
+*.a
+*.vcd
+.swp
+.*.swp
+.*.swo
+svn-commit*
+*_tb
+*_tb.dbl
+*dbg.txt
+*dump.txt
+*debug.txt
+tags
+cpudefs.h
+design.h
+octave-workspace
+core
+20*.tjz
+*.autosave
diff --git a/verilog/rtl/softshell/third_party/wb2axip/Makefile b/verilog/rtl/softshell/third_party/wb2axip/Makefile
new file mode 100644
index 0000000..3969dca
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/Makefile
@@ -0,0 +1,70 @@
+################################################################################
+##
+## Filename:	Makefile
+##
+## Project:	Pipelined Wishbone to AXI converter
+##
+## Purpose:	A master project makefile.  It tries to build all targets
+##		within the project, mostly by directing subdirectory makes.
+##
+## Targets:	
+##
+## Creator:	Dan Gisselquist, Ph.D.
+##		Gisselquist Technology, LLC
+##
+################################################################################
+##
+## Copyright (C) 2015-2020, Gisselquist Technology, LLC
+##
+## This file is part of the WB2AXIP project.
+##
+## The WB2AXIP project contains free software and gateware, licensed under the
+## Apache License, Version 2.0 (the "License").  You may not use this project,
+## or this file, except in compliance with the License.  You may obtain a copy
+## of the License at
+##
+##	http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+## WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+## License for the specific language governing permissions and limitations
+## under the License.
+##
+################################################################################
+##
+##
+.PHONY: all
+all:	archive rtl formal
+# all:	verilated sw bench bit
+#
+# Could also depend upon load, if desired, but not necessary
+BENCH := `find bench -name Makefile` `find bench -name "*.cpp"` `find bench -name "*.h"`
+RTL   := `find rtl -name "*.v"` `find rtl -name Makefile`
+NOTES := `find . -name "*.txt"` `find . -name "*.html"`
+YYMMDD:=`date +%Y%m%d`
+
+.PHONY: archive
+archive:
+	tar --transform s,^,$(YYMMDD)-wb2axi/, -chjf $(YYMMDD)-wb2axi.tjz $(BENCH) $(RTL) $(NOTES)
+
+.PHONY: verilated
+verilated:
+	cd rtl ; $(MAKE) --no-print-directory
+
+.PHONY: rtl
+rtl: verilated
+
+.PHONY: bench
+bench: rtl
+	cd bench/cpp ; $(MAKE) --no-print-directory
+
+.PHONY: formal
+formal:
+	$(MAKE) --no-print-directory -C bench/formal
+
+.PHONY: doc
+doc:
+	cd doc ; $(MAKE) --no-print-directory
+
+
diff --git a/verilog/rtl/softshell/third_party/wb2axip/README.md b/verilog/rtl/softshell/third_party/wb2axip/README.md
new file mode 100644
index 0000000..d35b1f1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/README.md
@@ -0,0 +1,488 @@
+# WB2AXIP: Bus interconnects, bridges, and other components
+
+The bus components and bridges within this repository are unique in that they
+are all designed for 100% throughput with no throughput overhead.  They are also
+unique in that the vast majority of the cores within have all been formally
+verified.
+
+Where the protocol allows it, such as with [AXI4](https://zipcpu.com/blog/2019/05/29/demoaxi.html),
+[AXI-lite](https://zipcpu.com/formal/2018/12/28/axilite.html), and [Wishbone B4
+pipelined](https://zipcpu.com/zipcpu/2017/11/07/wb-formal.html), multiple transactions
+may be in flight at a time so that protocol handling doesn't stall the bus.
+
+This is [uncommon among AXI4 implementations](https://zipcpu.com/formal/2019/05/13/axifull.html) and almost unheard of in the example AXI-lite implementations I have examined.
+
+Most AXI4 implementations will process a single burst transaction packet at
+a time and require some overhead to make this happen.  Xilinx's AXI-lite
+implementations, both interconnect and [slave implementations](https://zipcpu.com/formal/2018/12/28/axilite.html), only handle one
+request at a time.  Other buses, such as Wishbone Classic, AHB, or APB, will
+only ever process one transaction word at a time.
+
+If you are coming from AXI4, AXI-lite, or any one of these other bus
+implementations to the AXI4 or even AXI-lite components supported here, then
+you should expect to see a throughput increase by using one (or more) of the
+cores listed here--given of course that you have a bus master capable of
+issuing multiple requests at a time.
+
+This performance improvement may be as significant as a [16x speedup when
+toggling an I/O](https://zipcpu.com/zipcpu/2019/02/09/cpu-blinky.html), a 4x
+speedup when comparing [this slave](rtl/demofull.v) against [Xilinx's block
+RAM memory controller (when processing single beat transactions)](https://zipcpu.com/blog/2020/03/23/wbm2axisp.html), or as
+insignificant as 2% improvement from using the AXI4 MM to Slave converters
+(according to Xilinx's data sheets---I haven't yet run the test myself).  This
+increased performance extends to the [crossbar implementations](https://zipcpu.com/blog/2019/07/17/crossbar.html) contained within
+this repository as well, and so you may notice the improvement only increases
+when using [these crossbars](https://zipcpu.com/blog/2019/07/17/crossbar.html).
+
+# A Pipelined Wishbone B4 to AXI4 bridge
+
+Built out of necessity, this repository was originally built around [a Wishbone
+(WB) to AXI4 bridge](https://zipcpu.com/blog/2020/03/23/wbm2axisp.html),
+which is designed to provide a conversion from a (simpler) [pipelined wishbone
+bus](http://zipcpu.com/zipcpu/2017/11/07/wb-formal.html) to an AXI4 bus for the
+purposes of driving memory transactions through Xilinx's SDRAM controllers.
+[The WB->AXI bridge](rtl/wbm2axisp.v) is designed to connect a [wishbone
+bus](http://zipcpu.com/zipcpu/2017/11/07/wb-formal.html) to an AXI bus which
+may be wider--such as from a 32-bit WB bus to a 128-bit AXI bus.  Hence, if
+the Memory Interface Generator DDR3 controller is running at a 4:1 clock rate,
+memory clocks to AXI system clocks, then this [bus translator](rtl/wbm2axisp.v)
+should be able to accomplish one transaction per clock at a sustained
+(pipelined) rate (neglecting any stalls due to refresh cycles).
+
+Since the initial build of [the core](rtl/wbm2axisp.v), I've added the
+[WB to AXI lite](rtl/wbm2axilite.v) bridge.  This is also a pipelined bridge,
+and like the original one it has also been formally verified.
+
+# AXI to Wishbone conversion
+
+While not the original purpose of the project, it now has both [AXI-lite to
+WB](rtl/axlite2wbsp.v) and [AXI to WB](rtl/axim2wbsp.v) bridges.  Each of these
+bridges comes in two parts, a read and write half.  These halves can be used
+either independently, generating separate inputs to a
+[WB crossbar](rtl/wbxbar.v), or combined through a [WB
+arbiter](rtl/wbarbiter.v).
+
+[The AXI-lite to WB bridge](rtl/axlite2wbsp.v) has been both formally
+verified and FPGA proven.  This includes both the [write
+half](rtl/axilwr2wbsp.v) as well as the [read half](rtl/axilrd2wbsp.v).
+Given the reluctance of the major vendors to support high speed AXI-lite
+interfaces, you aren't likely to find this kind of performance elsewhere.
+
+[The AXI to WB bridge](rtl/axim2wbsp.v) [write](rtl/aximwr2wbsp.v) and
+[read](aximrd2wbsp.v) components have only been formally verified through
+about a dozen steps or so.  This proof is deep enough to
+verify most of the bus interactions, but not nearly deep enough to verify
+any issues associated with internal FIFO overflows.
+
+# Wishbone pipeline to WB Classic
+
+There's also a [Wishbone (pipelined, master) to Wishbone
+(classic, slave)](rtl/wbp2classic.v) bridge, as well as the reverse
+[Wishbone (classic, master) to Wishbone (pipelined, slave)](rtl/wbc2pipeline.v)
+bridge.  Both of these have passed their formal tests.  They are accompanied
+by a set of formal properties for Wishbone classic, both for
+[slaves](bench/formal/fwbc_slave.v) as well as
+[masters](bench/formal/fwbc_master.v).
+
+# AXI3 bridging
+
+I'm now in the process of adding AXI3 bridges to this repository.  These
+will be necessary for working with the Zynq chips, and others, that are still
+using AXI3.  While the work is ongoing, I do have an [AXI3 to
+AXI4](rtl/axi32axi.v) bridge available that's undergoing testing.  The bridge
+supports two algorithms for `W*` reordering, and should be suitable for most
+applications.
+
+# Formal Verification
+
+Currently, the project contains formal specifications for
+[Avalon](bench/formal/fav_slave.v), [Wishbone
+(classic)](bench/formal/fwbc_slave.v), [Wishbone
+(pipelined)](bench/formal/fwb_slave.v),
+[APB](bench/formal/fapb_slave.v), and
+[AXI-lite](bench/formal/faxil_slave.v) buses.  There's also a (partial) formal
+property specification for an [AXI (full) bus](bench/formal/faxi_slave.v), but
+the one in the master branch is incomplete.  The complete set of AXI
+properties are maintained elsewhere.  These properties, and the cores they've
+been used to verify, have all been tested and verified using SymbiYosys.
+
+# Xilinx Cores
+
+The formal properties were first tested on a pair of Xilinx AXI demonstration
+cores.  These cores failed formal verification.  You can read about them
+on [my blog, at zipcpu.com](https://zipcpu.com), [here for
+AXI-lite](http://zipcpu.com/formal/2018/12/28/axilite.html) and
+[here for AXI](http://zipcpu.com/formal/2019/05/13/axifull.html).
+You can find the Xilinx cores referenced in those articles
+[here](bench/formal/xlnxdemo.v) and [here](bench/formal/xlnxfull_2018_3.v) for
+reference, for those who wish to repeat or examine my proofs.
+
+# Firewalls
+
+A [firewall](https://zipcpu.com/formal/2020/05/16/firewall.html)
+is a guarantor: given an interface, of which only one side is trusted, the
+[firewall](https://zipcpu.com/formal/2020/05/16/firewall.html)
+guarantees the other side can trust the interface.  More than that, a
+[firewall](https://zipcpu.com/formal/2020/05/16/firewall.html) can be used
+to trigger an in-circuit logic analyzer: if ever the interface rules are
+violated, the [firewall](https://zipcpu.com/formal/2020/05/16/firewall.html)
+will set an ouput fault indicator, which can then be used to trigger the logic
+analyzer.  On top of that, the
+[firewalls](https://zipcpu.com/formal/2020/05/16/firewall.html) below are also
+built with an optional reset, allowing the design to safely return to
+functionality after triggering.  In many cases, this requires resetting the
+downstream (untrusted) component.
+
+- [AXILSAFETY](rtl/axilsafety.v) is a bus fault isolator AXI-lite translator,
+  sometimes called a firewall, designed to support a connection to a trusted
+  AXI-lite master, and an untrusted AXI-lite slave.  Should the slave attempt
+  to return an illegal response, or perhaps a response beyond the user
+  parameterized timeouts, then the untrusted slave will be "disconnected" from
+  the bus, and a bus error will be returned for both the errant transaction
+  and any following.
+
+  [AXILSAFETY](rtl/axisafety.v) also has a mode where, once a fault has been
+  detected, the slave is reset and then allowed to return to the bus
+  infrastructure again until its next fault.
+
+  *This core has been formally verified.*
+
+- [AXISAFETY](rtl/axisafety.v) is a bus fault isolator/firewall very similar
+  to the [AXILSAFETY](rtl/axilsafety.v) bus fault isolator above with many of
+  the same options.  The difference is that the [AXISAFETY](rtl/axisafety.v)
+  core works with the full AXI4 specification, whereas the
+  [AXILSAFETY](rtl/axilsafety.v) core works only with AXI4-lite.
+
+  As with the [AXILSAFETY](rtl/axilsafety.v) example, the [AXISAFETY](rtl/axisafety.v)
+  firewall also has a mode where, once a fault has been detected, the slave is
+  reset and allowed to return to the bus infrastructure until its next fault.
+  Unliike the [AXILSAFETY](rtl/axilsafety.v) example, this one will only ever
+  process a single AXI4 burst at a time.
+
+  *This core has been formally verified.*
+
+- [AXISSAFETY](rtl/axissafety.v) is a firewall for the AXI stream protocol.
+  It guarantees the stream protocol, and optionally that the incoming stream
+  will never be stalled for too long a period or that all packets downstream
+  have the same length.
+
+  *This core has been formally verified.*
+
+- [WBSAFETY](rtl/wbsafety.v) is a bus fault isolator/firewall, very similar
+  to the [AXILSAFETY](rtl/axilsafety.v) firewall above, only for the Wishbone
+  bus.  Unlike many vendor firewall implementations, this one is able to reset
+  the downstream core following any error without impacting it's ability to
+  respond to the bus in a protocol compliant fashion.
+
+  *This core has been formally verified.*
+
+# Cross-bars and AXI demonstrators
+
+This repository has since become a repository for all kinds of bus-based
+odds and ends in addition to the bus translators mentioned above.  Some of
+these odds and ends include [crossbar
+switches](https://zipcpu.com/blog/2019/07/17/crossbar.html) and AXI
+demonstrator cores.  As mentioned above, these cores are unique in their 100%
+throughput capabilities.
+
+- [WBXBAR](rtl/wbxbar.v) is a fully function N master to M slave Wishbone
+  [crossbar](https://zipcpu.com/blog/2019/07/17/crossbar.html).  Unlike my
+  Unlike my [earlier WB interconnects](https://zipcpu.com/blog/2017/06/22/simple-wb-interconnect.html), this one guarantees that the
+  ACK responses won't get crossed, and that misbehaving slave accesses will
+  be timed out.  The core also has options for checking for starvation
+  (where a master's request is not granted in a particular period of time),
+  double-buffering all outputs (i.e. with [skid
+  buffers](https://zipcpu.com/blog/2019/05/22/skidbuffer.html), and forcing idle
+  channel values to zero in order to reduce power.
+
+  *This core has been formally verified and used in several designs.*
+
+- [AXILXBAR](rtl/axilxbar.v) is a fully functional, formally verified, `N`
+  master to `M` slave AXI-lite [crossbar interconnect](https://zipcpu.com/blog/2019/07/17/crossbar.html).  As such, it permits
+  `min(N,M)` active channel connections between masters and slaves all at once.
+  This core also has options for low power, whereby unused outputs are forced
+  to zero, and lingering.  Since the AXI protocol doesn't specify exactly
+  when to close a channel, there's an `OPT_LINGER` allowing you to specify
+  how many cycles the channel should be idle for in order for the channel
+  to be closed.  If the channel is not closed, a clock can be spared when
+  reusing it.  Otherwise, two clocks will be required to access a given channel.
+
+  *This core has been formally verified.*
+
+  While I haven't tested Xilinx's interconnect to know, if the quality of
+  [their demonstration AXI-lite slave
+  core](http://zipcpu.com/formal/2018/12/28/axilite.html) is any
+  indication, then this cross-bar should easily outperform anything they have.
+  The key unusual feature?  The ability to maintain one transaction per clock
+  over an extended period of time across any channel pair.  (Their crossbar
+  artificially limits AXI-lite interfaces to one transaction at a time.)
+
+- [AXIL2AXIS](rtl/axil2axis.v) [converts from AXI-lite to AXI stream and back
+  again](https://zipcpu.com/dsp/2020/04/20/axil2axis.html).  It's primary
+  purpose is for testing AXI stream components at low speed, to make certain
+  that they work before increasing the speed of the stream to the system clock
+  rate.  As such, writes to the core will generate writes to the AXI stream on
+  the master side, and reads from the core will accept AXI stream reads on the
+  slave side.
+
+  While this isn't really intended to be a high performance core, it can still
+  handle 100% throughput like most of my IP here.  Therefore, anything less
+  than 100% throughput through this core will be a test of and reflection
+  of how the rest of your system works.
+
+  *This core has been formally verified.*
+
+- [AXIEMPTY](rtl/axiempty.v) is a cross bar helper.  It's the simplest, most
+  basic slave I could come up with that obeyed all the rules of AXI while
+  returning a bus error for every request.  It's designed to be used by the
+  interconnect generator for those cases where there are no slaves on a given
+  AXI bus.
+
+  *This core has been formally verified.*
+
+- [AXILEMPTY](rtl/axilempty.v) is a cross bar helper along the same lines as
+  the [AXIEMPTY](rtl/axiempty.v) core above.  It has an nearly identical
+  purpose, save only that [AXILEMPTY](rtl/axilempty.v) is built to be the
+  empty slave on an AXI-lite bus, not an AXI one.
+
+  *This core has been formally verified.*
+
+- [AXILSINGLE](rtl/axilsingle.v) is designed to be a companion to
+  [AutoFPGA](https://github.com/ZipCPU/autofpga)'s AXI-lite support.  It's
+  purpose is to [simplify connectivity logic when supporting multiple AXI-lite
+  registers](https://zipcpu.com/zipcpu/2019/08/30/subbus.html).  This core
+  takes a generic AXI-lite interface, and simplifies the interface so that
+  multiple single-register cores can be connected to it at no loss in
+  throughput.  The single-register cores can either be full AXI-lite cores in
+  their own respect, subject to simplification rules ([listed
+  within](rtl/axilsingle.v)), or even further simplified from that.
+  They must never stall the bus, and must always return responses within one
+  clock cycle.  The [AXILSINGLE](rtl/axilsingle.v) handles all backpressure
+  issues.  If done right, the backpressure logic from any downstream slave
+  core will be removed by the synthesis tool, allowing all backpressure logic
+  to be condensed into a few shared wires.
+
+  *This core has been formally verified.*
+
+- [AXILDOUBLE](rtl/axildouble.v) is the second AXI-lite companion to
+  [AutoFPGA](https://github.com/ZipCPU/autofpga)'s AXI-lite support.  It's
+  purpose is to [simplify connectivity logic when supporting multiple AXI-lite
+  slaves](https://zipcpu.com/zipcpu/2019/08/30/subbus.html) while imposing
+  no throughput penalty.  This core takes a generic AXI-lite interface, and
+  simplifies the interface so that multiple peripherals can be connected to
+  it.  These peripheral cores can either be full AXI-lite cores in their own
+  respect, subject to simplification rules discussed within, or even simplified 
+  from that.  They must never stall the bus, and must always return responses
+  within one clock cycle.  The [AXILDOUBLE](rtl/axildouble.v) core handles all
+  backpressure issues, address selection, and invalid address returns.
+
+  *This core has been formally verified.*
+
+- [AXIXBAR](rtl/axixbar.v) is a fun project to develop a full `NxM`
+  configurable [crossbar](https://zipcpu.com/blog/2019/07/17/crossbar.html)
+  using the full AXI protocol.
+
+  Unique to [this (full) AXI crossbar](rtl/axixbar.v) is the ability to have
+  multiple ongoing transactions on each of the master-to-slave channels.  Were
+  Xilinx's crossbar to do this, it would've broken their [demonstration
+  AXI-full slave core](http://zipcpu.com/formal/2019/05/13/axifull.html).
+
+- [DEMOAXI](rtl/demoaxi.v) is a demonstration AXI-lite slave core with more
+  power and capability than Xilinx's demonstration AXI-lite slave core.
+  Particular differences include 1) this one passes a formal verification check
+  ([Xilinx's core has bugs](http://zipcpu.com/formal/2018/12/28/axilite.html)),
+  and 2) this one can handle a maximum throughput of one transaction per clock.
+  (Theirs did at best one transaction every other clock period.)  You can read
+  more about this [demonstration AXI-lite slave core](rtl/demoaxi.v) on
+  [ZipCPU.com](http://zipcpu.com) in [this article](http://zipcpu.com/blog/2019/01/12/demoaxilite.html).
+
+  *This core has been formally verified.*
+
+- [AXISSWITCH](rtl/axisswitch.v) is a quick switch for AXI streams.  Given
+  `N` stream inputs, select from among them to produce a stream output.
+   Guarantees that the switch takes place at packet boundaries.  Provides an
+   AXI-lite interface for controlling which AXI stream gets forwarded
+   downstream.
+
+  *This core has been formally verified.*
+
+- [EASYAXIL](rtl/easyaxil.v) is a [second demonstration AXI-lite slave core,
+  only this time re-engineered to look and feel
+  simpler](https://zipcpu.com/blog/2020/03/08/easyaxil.html) than the
+  [DEMOAXI](rtl/demoaxi.v) core above.  It's also designed to use internal
+  registers, vice a memory, so that it can be more easily extended.  The
+  core can either use [skidbuffers](https://zipcpu.com/blog/2019/05/22/skidbuffer.html), in which case its performance matches the
+  [DEMOAXI](rtl/demoaxi.v) core above, or not, in which case it has only half
+  the throughput.  The real key difference is that the [skid
+  buffers](https://zipcpu.com/blog/2019/05/22/skidbuffer.html) have been
+  separated into an external module.
+
+  *This core has been formally verified.  While not used in any designs per se
+  it has formed the basis for many AXI-lite designs.*
+
+- [DEMOFULL](rtl/demofull.v) is a [fully capable AXI4 demonstration slave
+  core](https://zipcpu.com/blog/2019/05/29/demoaxi.html)
+  rather than just the AXI-lite protocol.  Well, okay, it doesn't do anything
+  with the PROT, QOS, CACHE, and LOCK flags, so perhaps it isn't truly the
+  *full* AXI protocol.  Still, it's sufficient for most needs.
+
+  Unlike [Xilinx's demonstration AXI4 slave
+  core](http://zipcpu.com/formal/2019/05/13/axifull.html),
+  [this one](rtl/demofull.v) can handle 100% loading on both read and write
+  channels simultaneously.  That is, it can handle one read and one write beat
+  per channel per clock with no stalls between bursts if the environment will
+  allow it.
+
+  *This core has been formally verified and used in several designs.*
+
+- [AXI2AXILITE](rtl/axi2axilite.v) converts incoming AXI4 (full) requests
+  for an AXI-lite slave.  This conversion is fully pipelined, and capable of
+  sending back to back AXI-lite requests on both channels.
+
+  *This core has been formally verified and used in several designs.*
+
+- [AXIS2MM](rtl/axis2mm.v) converts an incoming stream signal into outgoinng
+  AXI (full) requests.  Supports bursting and aborted transactions.  Also
+  supports writes to a constant address, and continuous writes to concurrent
+  addresses.  This core depends upon all stream addresses being aligned.
+
+  *This core has been formally verified and checked in simulation.*
+
+- [AXIMM2S](rtl/aximm2s.v) reads from a given address, and writes it to
+  a FIFO buffer and then to an eventual AXI stream.  Read requests are not
+  issued unless room already exists in the FIFO, yet for a sufficiently fast
+  stream the read requests may maintain 100% bus utilization--but only if
+  the rest of the bus does as well.  Supports continuous, fixed address or
+  incrementing, and aborted transactions.
+
+  Both this core and the one above it depend upon all stream words being
+  aligned to the stream.
+
+  *This core has been both formally verified and checked in simulation.*
+
+- [AXIDMA](rtl/axidma.v) is a hardware assisted memory copy.  Given a source
+  address, read address, and length, this core reads from the source address
+  into a FIFO, and then writes the data from the FIFO to memory.  As an
+  optimization, memory address requests are not made unless the core is able
+  to transfer at a 100% throughput rate.
+
+  *This core has been formally verified and used in several designs.*
+
+- [AXISGDMA](rtl/axisgdma.v) is a brand new scatter-gather/vector-io based
+  DMA controller.  Give it a pointer to a table of DMA descriptors, and it
+  will issue commands to the DMA until the table is complete.
+
+  This core has not yet been verified in any manner, and is likely to still
+  contain many bugs within it until that time.  Use it at your own risk.
+
+- [AXIVCAMERA](rtl/axivcamera.v) is a AXI-based frame-buffer writer.  Given
+  an AXI-stream video source, a frame start address, the number of lines in the
+  image and the number of bytes per line, this core will copy one (or more)
+  frames of video to memory.
+
+  *This core has been formally verified, and used successfully in a simulation
+  based demonstration.*
+
+- [AXIVDISPLAY](rtl/axivdisplay.v) is a AXI-based frame-buffer source.  Given
+  a frame start address in memory, the number of lines in an image and the
+  number of bytes per line, this core will perpetually read a video image
+  from memory and produce it on an outgoing stream interface.
+
+  This particular version can only handle bus aligned transfers.
+
+  *This core has been formally verified.*
+
+  You can find a demonstration of this core being used in my [VGA
+  simulator](https://github.com/ZipCPU/vgasim)--supporting both VGA and HDMI
+  outputs.
+
+- AXISINGLE is a (to be written) bus simplifier core along the lines of the
+  [AXILSINGLE](rtl/axilsingle.v), [AXILDOUBLE](rtl/axildouble.v) and
+  [AXIDOUBLE](rtl/axidouble.v) cores, in that it can [handle all of the bus
+  logic for multiple AXI slaves while simplifying the bus
+  interactions for each](https://zipcpu.com/zipcpu/2019/08/30/subbus.html)
+  but at no throughput penalty.  Once built, this will also be an
+  [AutoFPGA](https://github.com/ZipCPU/autofpga) companion core.  Slave's of
+  type "SINGLE" (one register, one clock to generate a response) can be ganged
+  together using it.  This core will then essentially turn an AXI core into
+  an AXI-lite core, with the same interface as [AXILSINGLE](rtl/axilsingle.v) 
+  above.  When implemented, it will look very similar to the [AXIDOUBLE](rtl/axidouble.v)
+  core mentioned below.
+
+- [AXIDOUBLE](rtl/axidouble.v) is the second AXI4 (full) companion to
+  [AutoFPGA](https://github.com/ZipCPU/autofpga)'s AXI4 (full) support.  It's
+  purpose is to [simplify connectivity logic when supporting multiple AXI4
+  (full) slaves](https://zipcpu.com/zipcpu/2019/08/30/subbus.html).
+  This core takes a generic AXI4 (full) interface, and simplifies
+  the interface so that peripherals can be connected to it with a minimal amount
+  of logic.  These peripherals cores can either be full AXI4 (full) cores in
+  their own respect, subject to simplification rules discussed within,
+  simplified AXI-lite slave as one might use with
+  [AXILDOUBLE](rtl/axildouble.v), or even simpler than that.  Key to this
+  simplification is the assumption that the simplified slaves must never stall
+  the bus, and that they must always return responses within one clock cycle.
+  The [AXIDOUBLE](rtl/axidouble.v) core handles all backpressure issues, ID
+  logic, burst logic, address selection, invalid address return and exclusive
+  access logic.
+
+  *This core has been formally verified.*
+
+- [WBXCLK](rtl/wbxclk.v) can be used to cross clock domains on a pipelined
+  Wishbone bus.  It's conceptually an asynchronous request FIFO coupled with
+  an asynchronous acknowledgment FIFO to cross clock domains.  A counter in
+  the original clock domain guarantees that the number of outstanding
+  transactions remains smaller than the FIFO size.  The design is complicated
+  by the masters ability to arbitrarily lower CYC at any time mid-cycle and
+  reliably be able to cancel any outgoing transactions in the downstream
+  channel direction.
+
+  *This core has been formally verified.*
+
+- [AXIVFIFO](rtl/axivfifo.v) implements a virtual FIFO.  A virtual FIFO is
+  basically a memory backed FIFO.  Hence, after data gets written to this
+  core it is then burst across an AXI bus to the whatever memory device is
+  connected to the bus.  This allows you to build FIFOs of arbitrarily large
+  length for ... whatever task.
+
+  *This core has been formally verified.*
+
+- [AXIXCLK](rtl/axixclk.v) can be used to cross clock domains in an AXI
+  context.  As implemented, it is little more than a set of asynchronous FIFOs
+  applied to each of the AXI channels.  The asynchronous FIFOs have been
+  formally verified,
+
+- [AXISRANDOM](rtl/axisrandom.v) is a quick AXI stream source generating random
+  numbers via a linear feedback shift register.
+
+# APB
+
+There are now two APB cores in this repository:
+
+- [APBSLAVE](rtl/apbslave.v) is a demonstration APB slave.
+
+  *This core has been formally verified.*
+
+- [AXIL2APB](rtl/axil2apb.v) -- a high throughput AXI-lite to APB bridge.
+  Unlike other bridges, this one bridges to a single APB slave only.  It can
+  also maintain PSEL high across multiple bursts, achieving a maximum
+  throughput rate of 50%.
+
+  *This core has been formally verified.*
+
+
+# Licensing
+
+This repository is licensed under the [Apache 2
+license](https://www.apache.org/licenses/LICENSE-2.0.html).
+
+# Thanks
+
+I'd like to thank @wallento for his initial work on a
+[Wishbone to AXI converter](https://github.com/wallento/wb2axi), and his
+encouragement to improve upon it.  While this isn't a fork of his work, the
+initial [pipelined wishbone to AXI bridge](rtl/wbm2axisp.v) which formed
+the core seed for this project took its initial motivation from his work.
+
+Many of the rest of these projects have been motivated by the desire to learn
+and develop my formal verification skills.  For that, I would thank the staff
+of Symbiotic EDA for their tools and their encouragement.
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/README.md b/verilog/rtl/softshell/third_party/wb2axip/bench/README.md
new file mode 100644
index 0000000..1daf462
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/README.md
@@ -0,0 +1,15 @@
+This repository contains three types of bench testing information.
+
+1. [Formal scripts and properties](formal) for the use in formal proofs using
+   SymbiYosys.  To be complete, each formal script will produce a full proof
+   (with induction), together with a series of cover traces demonstrating
+   all of what the design should/could do, and at high speed.  You can find
+   many of these cover results posted in the [../doc](../doc/gfx) directory.
+
+2. [CPP scripts](cpp) for use with Verilator.  These aren't very well developed,
+   and were not used to verify anything here.
+
+3. [MCY information](mcy).  [MCY](https://github.com/YosysHQ/mcy) is a new
+   program built by SymbioticEDA for the purpose of testing whether or not
+   a test bench is sufficient for determining if a design truly works.  My
+   [mcy directory](mcy) contains my attempts and efforts at using this program.
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/cpp/Makefile b/verilog/rtl/softshell/third_party/wb2axip/bench/cpp/Makefile
new file mode 100644
index 0000000..2ca7c2b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/cpp/Makefile
@@ -0,0 +1,69 @@
+################################################################################
+##
+## Filename: 	Makefile
+##
+## Project:	Pipelined Wishbone to AXI converter
+##
+## Purpose:	
+##
+## Creator:	Dan Gisselquist, Ph.D.
+##		Gisselquist Technology, LLC
+##
+################################################################################
+##
+## Copyright (C) 2015-2020, Gisselquist Technology, LLC
+##
+## This file is part of the WB2AXIP project.
+##
+## The WB2AXIP project contains free software and gateware, licensed under the
+## Apache License, Version 2.0 (the "License").  You may not use this project,
+## or this file, except in compliance with the License.  You may obtain a copy
+## of the License at
+##
+##	http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+## WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+## License for the specific language governing permissions and limitations
+## under the License.
+##
+################################################################################
+##
+##
+CXX	:= g++
+FLAGS	:= -Wall -Og -g
+OBJDIR  := obj-pc
+RTLD	:= ../verilog
+VERILATOR_ROOT ?= $(shell bash -c 'verilator -V|grep VERILATOR_ROOT| head -1 | sed -e " s/^.*=\s*//"')
+INCS	:= -I$(RTLD)/obj_dir/ -I$(VROOT)/include
+SOURCES := # testset.cpp
+VOBJDR	:= $(RTLD)/obj_dir
+VLIB	:= $(VROOT)/include/verilated.cpp
+SIMSRCS := aximemsim.cpp # testset.cpp
+SIMOBJ := $(subst .cpp,.o,$(SIMSRCS))
+SIMOBJS:= $(addprefix $(OBJDIR)/,$(SIMOBJ))
+all:	$(OBJDIR)/ testset
+
+$(OBJDIR)/:
+	@bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi"
+
+$(OBJDIR)/aximemsim.o: aximemsim.cpp aximemsim.h
+
+$(OBJDIR)/%.o: %.cpp
+	$(CXX) $(FLAGS) $(INCS) -c $< -o $@
+
+# testset: $(OBJDIR)/testset.o $(OBJDIR)/aximemsim.o $(VOBJDR)/Vtestset__ALL.a
+#	$(CXX) $(FLAGS) $(INCS) $^ $(VLIB) -o $@
+.PHONY: testset
+testset:
+	@echo
+	@echo "I seem to have lost the testset.cpp file that this test suite"
+	@echo "was based off of.  Hence, the suite is incomplete."
+	@echo
+
+.PHONY: clean
+clean:
+	rm -rf $(OBJDIR)/
+	# rm -f  ./testset
+
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/cpp/aximemsim.cpp b/verilog/rtl/softshell/third_party/wb2axip/bench/cpp/aximemsim.cpp
new file mode 100644
index 0000000..2a66e18
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/cpp/aximemsim.cpp
@@ -0,0 +1,200 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	aximemsim.cpp
+//
+// Project:	Pipelined Wishbone to AXI converter
+//
+// Purpose:	
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2016-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+#include <stdio.h>
+
+#include "aximemsim.h"
+
+class	ADRFIFO {
+	typedef	{
+		int id; unsigned addr;
+	} ADRFIFOELEMENT;
+	int	m_head, m_tail, m_len;
+	int	*m_mem;
+public:
+	ADRFIFO(int ln) {
+		m_mem = new ADRFIFOELEMENT[ln];
+		m_head = m_tail = 0;
+		m_len = ln;
+	}
+
+	void	push(int id, unsigned addr) {
+		int nhead = m_head + 1;
+		if (nhead >= m_len)
+			nhead = 0;
+		assert(nhead != m_tail);
+		m_mem[m_head].id   = id;
+		m_mem[m_head].addr = addr;
+		m_head = nhead;
+	}
+
+	bool	full(void) {
+		int nhead = m_head + 1;
+		if (nhead >= m_len)
+			nhead = 0;
+		return (nhead == m_tail);
+	}
+
+	bool	valid(void) {
+		return (m_head != m_tail);
+	}
+
+	int	id(void)	{ return m_mem[m_tail].id; }
+	int	addr(void)	{ return m_mem[m_tail].addr; }
+	int	pop(void)	{
+		if (m_tail == m_head)
+			return;
+		m_tail++;
+		if (m_tail >= m_len)
+			m_tail = 0;
+	}
+};
+
+class	DATFIFO {
+	typedef	{
+		unsigned data[4];
+		int	strb;
+	} DATAFIFOELEMENT;
+	int	m_head, m_tail, m_len;
+	int	*m_mem;
+public:
+	DATAFIFO(int ln) {
+		m_mem = new DATAFIFOELEMENT[ln];
+		m_head = m_tail = 0;
+		m_len = ln;
+	}
+
+	void	push(int strb, unsigned dat0, unsigned dat1,
+			unsigned dat, unsigned dat3) {
+		int nhead = m_head + 1;
+		if (nhead >= m_len)
+			nhead = 0;
+		assert(nhead != m_tail);
+		m_mem[m_head].strb   = id;
+		m_mem[m_head].data[0] = dat0;
+		m_mem[m_head].data[1] = dat1;
+		m_mem[m_head].data[2] = dat2;
+		m_mem[m_head].data[3] = dat3;
+		m_head = nhead;
+	}
+
+	bool	full(void) {
+		int nhead = m_head + 1;
+		if (nhead >= m_len)
+			nhead = 0;
+		return (nhead == m_tail);
+	}
+
+	bool	valid(void) {
+		return (m_head != m_tail);
+	}
+
+	int	strb(void)	{ return m_mem[m_tail].strb; }
+	unsigned *data(void)	{ return &m_mem[m_tail].data[0]; }
+	int	pop(void)	{
+		if (m_tail == m_head)
+			return;
+		m_tail++;
+		if (m_tail >= m_len)
+			m_tail = 0;
+	}
+};
+
+AXIMEMSIM::AXIMEMSIM(unsigned abits) {
+	// abits is the number of bits in a memory address, referencing 8-bit
+	// bytes, therefore we can size our memory properly.
+	assert(abits>2);
+	m_len = (1<<(abits-2));
+	m_mask= m_len-1;
+	m_mem = new unsigned[(1<<(abits-2))];
+
+	memset(m_mem, 0, sizeof(unsigned)<<(abits-2));
+}
+
+void AXIMEMSIM::apply(AXIBUS &bus) {
+	// First, let's validate our inputs ..., and queue up our outputs
+	bus.ar.ready = (!m_readfifo.full());
+	bus.aw.ready = (!m_writefifo.full());
+	bus.w.ready  = (!m_wdata.full());
+	if (bus.r.ready)
+		bus.r.valid = false;
+	if (bus.b.ready)
+		bus.b.valid = false;
+
+	if ((bus.ar.ready)&&(!m_readfifo.full())) {
+		assert(bus.ar.len  == 0);
+		assert(bus.ar.size  == 5);
+		assert(bus.ar.burst == 1);
+		assert(bus.ar.lock  == 0);
+		assert(bus.ar.cache == 2);
+		assert(bus.ar.prot  == 2);
+		assert(bus.ar.qos   == 0);
+
+		m_readfifo.push(bus.ar.id, bus.ar.addr);
+	}
+
+	if ((bus.aw.ready)&&(!m_writefifo.full())) {
+		assert(bus.aw.len   == 0);
+		assert(bus.aw.size  == 5);
+		assert(bus.aw.burst == 1);
+		assert(bus.aw.lock  == 0);
+		assert(bus.aw.cache == 2);
+		assert(bus.aw.prot  == 2);
+		assert(bus.aw.qos   == 0);
+
+		m_awfifo.push(bus.aw.id, bus.aw.addr);
+	}
+
+	if ((bus.w.ready)&&(!m_writedata.full())) {
+		m_writefifo.push(bus.aw.strb, bus.aw.data[0], bus.aw.data[1],
+			bus.aw.data[2], bus.aw.data[3]);
+
+	if (m_respfifo[m_now].valid) {
+		if (m_respfifo[m_now].read) {
+			if ((!bus.r.valid)||(bus.r.ready)) {
+				bus.r.data[0] = m_respfifo[m_now].data[0];
+				bus.r.data[1] = m_respfifo[m_now].data[1];
+				bus.r.data[2] = m_respfifo[m_now].data[2];
+				bus.r.data[3] = m_respfifo[m_now].data[3];
+				bus.r.valid = true;
+				m_now++;
+			}
+		} else if ((!bus.b.valid)||(bus.b.ready)) {
+			bus.b.resp = m_respfifo[m_now].resp;
+			bus.b.id = m_respfifo[m_now].id;
+			bus.b.valid = true;
+			m_now++;
+		}
+	}
+}
+
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/cpp/aximemsim.h b/verilog/rtl/softshell/third_party/wb2axip/bench/cpp/aximemsim.h
new file mode 100644
index 0000000..7915f37
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/cpp/aximemsim.h
@@ -0,0 +1,84 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	aximemsim.h
+//
+// Project:	Pipelined Wishbone to AXI converter
+//
+// Purpose:	To attempt to emulate how the MIG responds to AXI requests.
+//		Of course, this is written with no knowledge of how MIG actually
+//	responds, just a touch of knowledge regarding how a DDR3 memory works,
+//	so ... your mileage might vary.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2016-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+#ifndef	AXIMEMSIM_H
+#define	AXIMEMSIM_H
+
+typedef	struct {
+	unsigned	addr;
+	int		id, len, size, burst, lock, cache, prot, qos;
+	bool		ready, valid;
+} AXI_AWBUS;
+
+typedef	struct {
+	unsigned	addr;
+	int		id, len, size, burst, lock, cache, prot, qos;
+	bool		ready, valid;
+} AXI_ARBUS;
+
+typedef	struct {
+	int		strb;
+	unsigned	data[4];	// 128 bits
+	int		ready, valid, last;
+} AXI_WBUS;
+
+typedef	struct {
+	int		id, resp;
+	int		ready, valid;
+} AXI_WRESP;
+
+typedef	struct {
+	int		id, resp;
+	unsigned	data[4];	// 128 bits
+	int		ready, valid, last;
+} AXI_RDATA;
+
+typedef	struct	{
+	AXI_AWBUS	aw;
+	AXI_ARBUS	ar;
+	AXI_WBUS	w;
+	AXI_WRESP	b;
+	AXI_RDATA	r;
+} AXIBUS;
+
+class	AXIMEMSIM {
+	unsigned	*m_mem;
+public:
+	AXIMEMSIM(unsigned abits);
+	void	apply(AXIBUS &bus);
+};
+
+#endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/.gitignore b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/.gitignore
new file mode 100644
index 0000000..3f9e760
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/.gitignore
@@ -0,0 +1,50 @@
+*.smt2
+*.yslog
+*.check
+*.ys.v
+addrdecode_*/
+afifo_*/
+apbslave_*/
+axi2axilite_*/
+axi_addr_miter_*/
+axidma_*/
+axil2axis_*/
+axil2apb_*/
+axildouble_*/
+axilite2axi_*/
+axilwr2wbsp_*/
+axilrd2wbsp_*/
+axilsafety_*/
+axilsingle_*/
+axildouble_*/
+axilxbar_*/
+axidouble_*/
+aximrd2wbsp_*/
+aximwr2wbsp_*/
+aximm2s_*/
+axiperf_*/
+axis2mm_*/
+axisafety_*/
+axisgfsm_*/
+axisrandom_*/
+axissafety_*/
+axisswitch_*/
+axixbar_*/
+axixclk_*/
+axlite2wbsp_*/
+demoaxi_*/
+demofull_*/
+easyaxil_*/
+sfifo_*/
+skidbuffer_*/
+wbarbiter_*/
+wbm2axilite_*/
+wbm2axisp_*/
+wbp2classic_*/
+wbc2pipeline_*/
+wbsafety_*/
+xlnxdemo_*/
+xlnxfull_*/
+xlnxstream_*/
+wbxbar_*/
+wbxclk_*/
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/Makefile b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/Makefile
new file mode 100644
index 0000000..fd93c8a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/Makefile
@@ -0,0 +1,701 @@
+################################################################################
+##
+## Filename:	Makefile
+##
+## Project:	Pipelined Wishbone to AXI converter
+##
+## Purpose:	To direct the formal verification of the bus bridge
+##		sources.
+##
+## Targets:	The default target, all, tests all of the components defined
+##		within this module.
+##
+## Creator:	Dan Gisselquist, Ph.D.
+##		Gisselquist Technology, LLC
+##
+################################################################################
+##
+## Copyright (C) 2017-2020, Gisselquist Technology, LLC
+##
+## This file is part of the WB2AXIP project.
+##
+## The WB2AXIP project contains free software and gateware, licensed under the
+## Apache License, Version 2.0 (the "License").  You may not use this project,
+## or this file, except in compliance with the License.  You may obtain a copy
+## of the License at
+##
+##	http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+## WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+## License for the specific language governing permissions and limitations
+## under the License.
+##
+################################################################################
+##
+##
+HELPERS   := sfifo afifo addrdecode wbarbiter skidbuffer
+CROSSBARS := axilxbar wbxbar # axixbar
+CROSSCLOCK:= wbxclk
+BRIDGES   := wbm2axilite axlite2wbsp wbp2classic wbc2pipeline axilsingle axildouble axil2apb # wbm2axisp axi2axilite axilite2axi
+AXISTREAM := xlnxstream_2018_3 axisswitch.v axisrandom.v
+AXISLAVES := demoaxi easyaxil axil2axis axiperf # demofull xlnxfull
+AXIMASTERS :=
+FIREWALLS := wbsafety axilsafety axissafety # axisafety
+TESTS := $(HELPERS) $(AXISLAVES) $(AXISTREAM) $(FIREWALLS) $(BRIDGES) $(CROSSCLOCK) $(CROSSBARS) $(AXIMASTERS) apbslave
+.PHONY: $(TESTS)
+all: $(TESTS)
+RTL        := ../../rtl
+SMTBMC     := yosys-smtbmc
+
+#
+# Helpers
+WBARB      := wbarbiter
+DECODER    := addrdecode
+SFIFO      := sfifo
+AFIFO      := afifo
+SKIDBUFFER := skidbuffer
+XBAR := $(RTL)/$(DECODER).v $(RTL)/$(SKIDBUFFER).v
+#
+# Slaves
+AXIL2AXIS  := axil2axis
+AXIPERF    := axiperf
+APBSLAVE   := apbslave
+DEMOAXI    := demoaxi
+EASYAXIL   := easyaxil
+XILINXDEMO := xlnxdemo
+#
+# AXI Stream cores
+XLNXSTREAM := xlnxstream_2018_3
+AXISRANDOM := axisrandom
+AXISSWITCH := axisswitch
+AXISSWITCH := axisswitch
+#
+# Bridges
+AXIL2APB   := axil2apb
+WB2AXI     := wbm2axisp
+WB2LITE    := wbm2axilite
+RDLITE     := axilrd2wbsp
+WRLITE     := axilwr2wbsp
+AXLITE     := axlite2wbsp
+AXILSINGLE := axilsingle
+AXILDOUBLE := axildouble
+WBP2CLASSIC:= wbp2classic
+WBC2PIPELIN:= wbc2pipeline
+#
+# Cross clock
+WBXCLK     := wbxclk
+#
+# Crossbars
+AXILXBAR   := axilxbar
+WBXBAR     := wbxbar
+WBXBAR4x8  := wbxbar4x8
+WBXBAR1x8  := wbxbar1x8
+WBXBAR4x1  := wbxbar4x1
+# AXIXBAR    := axixbar
+#
+# Firewalls
+WBSAFETY   := wbsafety
+AXILSAFETY := axilsafety
+AXISSAFETY := axissafety
+#
+# Bus property sets
+AXIL       := faxil_master.v faxil_slave.v
+WB         := fwb_master.v   fwb_slave.v
+WBC        := fwbc_master.v  fwbc_slave.v
+AXIS       := faxis_master.v faxis_slave.v
+APB        := fapb_master.v   fapb_slave.v
+
+.PHONY: $(WBARB) $(WB2AXI) $(RDLITE) $(WRLITE) $(AXLITE) $(WB2LITE) $(DEMOAXI)
+.PHONY: $(EASYAXIL) $(AXIPERF)
+
+$(WBARB): $(WBARB)_prf/PASS $(WBARB)_cvr/PASS
+$(WBARB)_prf/PASS: $(RTL)/$(WBARB).v $(WBARB).sby $(WB)
+	sby -f $(WBARB).sby prf
+$(WBARB)_cvr/PASS: $(RTL)/$(WBARB).v $(WBARB).sby $(WB)
+	sby -f $(WBARB).sby cvr
+
+#
+# This WB to AXI proof is contained elsewhere
+#
+# .PHONY: $(WB2AXI)
+# $(WB2AXI): $(WB2AXI)/PASS
+# $(WB2AXI)/PASS: $(RTL)/$(WB2AXI).v $(WB2AXI).sby $(WB)
+#	sby -f $(WB2AXI).sby
+
+$(RDLITE): $(RDLITE)_prf/PASS $(RDLITE)_cvr/PASS
+$(RDLITE)_prf/PASS: $(RDLITE).sby $(RTL)/$(RDLITE).v $(WB) $(AXIL)
+	sby -f $(RDLITE).sby prf
+$(RDLITE)_cvr/PASS: $(RDLITE).sby $(RTL)/$(RDLITE).v $(WB) $(AXIL)
+	sby -f $(RDLITE).sby cvr
+
+$(WRLITE): $(WRLITE)_prf/PASS $(WRLITE)_cvr/PASS
+$(WRLITE)_prf/PASS: $(WRLITE).sby $(RTL)/$(WRLITE).v $(WB) $(AXIL)
+	sby -f $(WRLITE).sby prf
+$(WRLITE)_cvr/PASS: $(WRLITE).sby $(RTL)/$(WRLITE).v $(WB) $(AXIL)
+	sby -f $(WRLITE).sby cvr
+
+.PHONY: $(AXLITE)
+$(AXLITE): $(AXLITE)_prf/PASS $(AXLITE)_cvr/PASS
+AXLITE_DEPS := $(RTL)/$(RDLITE).v $(RTL)/$(WRLITE).v $(AXIL) $(WB)	\
+	$(RTL)/$(WBARB).v $(AXLITE).sby $(RTL)/$(AXLITE).v		\
+	$(RDLITE)_prf/PASS $(RDLITE)_cvr/PASS				\
+	$(WRLITE)_prf/PASS $(WRLITE)_cvr/PASS
+
+$(AXLITE)_prf/PASS: $(AXLITE_DEPS)
+	sby -f $(AXLITE).sby prf
+
+$(AXLITE)_cvr/PASS: $(AXLITE_DEPS)
+	sby -f $(AXLITE).sby cvr
+
+.PHONY: $(WB2LITE)
+$(WB2LITE): $(WB2LITE)_cvr/PASS $(WB2LITE)_prf/PASS
+$(WB2LITE)_prf/PASS: $(RTL)/$(WB2LITE).v $(WB) $(AXIL)
+$(WB2LITE)_prf/PASS: $(WB2LITE).sby
+	sby -f $(WB2LITE).sby prf
+
+$(WB2LITE)_cvr/PASS: $(RTL)/$(WB2LITE).v $(WB) $(AXIL)
+$(WB2LITE)_cvr/PASS: $(WB2LITE).sby
+	sby -f $(WB2LITE).sby cvr
+
+.PHONY: $(DEMOAXI)
+$(DEMOAXI): $(DEMOAXI)_prf/PASS $(DEMOAXI)_cvr/PASS
+$(DEMOAXI)_prf/PASS: $(RTL)/$(DEMOAXI).v $(DEMOAXI).sby $(AXIL)
+	sby -f $(DEMOAXI).sby prf
+$(DEMOAXI)_cvr/PASS: $(RTL)/$(DEMOAXI).v $(DEMOAXI).sby $(AXIL)
+	sby -f $(DEMOAXI).sby cvr
+
+.PHONY: $(EASYAXIL)
+$(EASYAXIL): $(EASYAXIL)_prfreg/PASS $(EASYAXIL)_prfreglp/PASS $(EASYAXIL)_cvrreg/PASS
+$(EASYAXIL): $(EASYAXIL)_prfskd/PASS $(EASYAXIL)_prfskdlp/PASS $(EASYAXIL)_cvrskd/PASS
+$(EASYAXIL)_prfreg/PASS: $(RTL)/$(EASYAXIL).v $(EASYAXIL).sby $(AXIL)
+	sby -f $(EASYAXIL).sby prfreg
+$(EASYAXIL)_prfreglp/PASS: $(RTL)/$(EASYAXIL).v $(EASYAXIL).sby $(AXIL)
+	sby -f $(EASYAXIL).sby prfreglp
+$(EASYAXIL)_cvrreg/PASS: $(RTL)/$(EASYAXIL).v $(EASYAXIL).sby $(AXIL)
+	sby -f $(EASYAXIL).sby cvrreg
+$(EASYAXIL)_prfskd/PASS: $(RTL)/$(EASYAXIL).v $(RTL)/$(SKIDBUFFER).v $(EASYAXIL).sby $(AXIL)
+	sby -f $(EASYAXIL).sby prfskd
+$(EASYAXIL)_prfskdlp/PASS: $(RTL)/$(EASYAXIL).v $(RTL)/$(SKIDBUFFER).v $(EASYAXIL).sby $(AXIL)
+	sby -f $(EASYAXIL).sby prfskdlp
+$(EASYAXIL)_cvrskd/PASS: $(RTL)/$(EASYAXIL).v $(RTL)/$(SKIDBUFFER).v $(EASYAXIL).sby $(AXIL)
+	sby -f $(EASYAXIL).sby cvrskd
+
+.PHONY: $(AXIPERF)
+$(AXIPERF): $(AXIPERF)_prf/PASS $(AXIPERF)_cvr/PASS
+$(AXIPERF)_prf/PASS: $(RTL)/$(AXIPERF).v $(RTL)/$(SKIDBUFFER).v $(AXIPERF).sby $(AXIL)
+	sby -f $(AXIPERF).sby prf
+$(AXIPERF)_cvr/PASS: $(RTL)/$(AXIPERF).v $(RTL)/$(SKIDBUFFER).v $(AXIPERF).sby $(AXIL)
+	sby -f $(AXIPERF).sby cvr
+
+.PHONY: $(XILINXDEMO)
+$(XILINXDEMO): $(XILINXDEMO)_prf/FAIL $(XILINXDEMO)_cvr/PASS
+$(XILINXDEMO)_prf/FAIL: $(XILINXDEMO).v $(XILINXDEMO).sby $(AXIL)
+	@echo "Expect the Xilinx demo proof to fail."
+	@echo "Xilinx's code didn't work in the first place."
+	sby -f $(XILINXDEMO).sby prf
+$(XILINXDEMO)_cvr/PASS: $(XILINXDEMO).v $(XILINXDEMO).sby $(AXIL)
+	sby -f $(XILINXDEMO).sby cvr
+
+
+.PHONY: $(XLNXSTREAM)
+$(XLNXSTREAM): $(XLNXSTREAM)_prf/FAIL $(XLNXSTREAM)_cvr/PASS
+$(XLNXSTREAM)_prf/FAIL: $(XLNXSTREAM).v $(XLNXSTREAM).sby $(AXIS)
+	@echo "Expect the Xilinx stream master demo proof to fail."
+	@echo "Xilinx's code didn't work in the first place."
+	sby -f $(XLNXSTREAM).sby prf
+$(XLNXSTREAM)_cvr/PASS: $(XLNXSTREAM).v $(XLNXSTREAM).sby $(AXIS)
+	sby -f $(XLNXSTREAM).sby cvr
+
+#
+# Cross clock
+.PHONY: $(WBXCLK)
+$(WBXCLK): $(WBXCLK)_prf/PASS $(WBXCLK)_cvr/PASS
+$(WBXCLK)_prf/PASS: $(RTL)/$(WBXCLK).v $(RTL)/afifo.v $(WBXCLK).sby $(WB)
+	sby -f $(WBXCLK).sby prf
+$(WBXCLK)_cvr/PASS: $(RTL)/$(WBXCLK).v $(RTL)/afifo.v $(WBXCLK).sby $(WB)
+	sby -f $(WBXCLK).sby cvr
+
+.PHONY: $(AXILXBAR) $(AXILXBAR)prf $(AXILXBAR)cvr $(AXILXBAR)_prf
+$(AXILXBAR): $(AXILXBAR)prf $(AXILXBAR)cvr
+$(AXILXBAR)_prf: $(AXILXBAR)prf
+$(AXILXBAR)prf: $(AXILXBAR)_prf1x8_lp/PASS
+$(AXILXBAR)prf: $(AXILXBAR)_prf4x1_lp/PASS
+$(AXILXBAR)prf: $(AXILXBAR)_prf1x8/PASS
+$(AXILXBAR)prf: $(AXILXBAR)_prf4x1/PASS
+$(AXILXBAR)prf: $(AXILXBAR)_prf4x8/PASS
+$(AXILXBAR)prf: $(AXILXBAR)_prf4x8_lp/PASS
+$(AXILXBAR)_prf4x8/PASS: $(AXILXBAR).sby $(RTL)/$(AXILXBAR).v $(AXIL) $(XBAR)
+	sby -f $(AXILXBAR).sby prf4x8
+$(AXILXBAR)_prf1x8/PASS: $(AXILXBAR).sby $(RTL)/$(AXILXBAR).v $(AXIL) $(XBAR)
+	sby -f $(AXILXBAR).sby prf1x8
+$(AXILXBAR)_prf4x1/PASS: $(AXILXBAR).sby $(RTL)/$(AXILXBAR).v $(AXIL) $(XBAR)
+	sby -f $(AXILXBAR).sby prf4x1
+$(AXILXBAR)_prf4x8_lp/PASS: $(AXILXBAR).sby $(RTL)/$(AXILXBAR).v $(AXIL) $(XBAR)
+	sby -f $(AXILXBAR).sby prf4x8_lp
+$(AXILXBAR)_prf1x8_lp/PASS: $(AXILXBAR).sby $(RTL)/$(AXILXBAR).v $(AXIL) $(XBAR)
+	sby -f $(AXILXBAR).sby prf1x8_lp
+$(AXILXBAR)_prf4x1_lp/PASS: $(AXILXBAR).sby $(RTL)/$(AXILXBAR).v $(AXIL) $(XBAR)
+	sby -f $(AXILXBAR).sby prf4x1_lp
+$(AXILXBAR)cvr: $(AXILXBAR)_cvr4x8_lp/PASS
+$(AXILXBAR)cvr: $(AXILXBAR)_cvr4x8/PASS
+$(AXILXBAR)cvr: $(AXILXBAR)_cvr1x3_lp/PASS
+$(AXILXBAR)cvr: $(AXILXBAR)_cvr1x3/PASS
+$(AXILXBAR)cvr: $(AXILXBAR)_cvr4x1_lp/PASS
+$(AXILXBAR)cvr: $(AXILXBAR)_cvr4x1/PASS
+$(AXILXBAR)_cvr4x8/PASS: $(AXILXBAR).sby $(RTL)/$(AXILXBAR).v $(AXIL) $(XBAR)
+	sby -f $(AXILXBAR).sby cvr4x8
+$(AXILXBAR)_cvr1x3/PASS: $(AXILXBAR).sby $(RTL)/$(AXILXBAR).v $(AXIL) $(XBAR)
+	sby -f $(AXILXBAR).sby cvr1x3
+$(AXILXBAR)_cvr4x1/PASS: $(AXILXBAR).sby $(RTL)/$(AXILXBAR).v $(AXIL) $(XBAR)
+	sby -f $(AXILXBAR).sby cvr4x1
+$(AXILXBAR)_cvr4x8_lp/PASS: $(AXILXBAR).sby $(RTL)/$(AXILXBAR).v $(AXIL) $(XBAR)
+	sby -f $(AXILXBAR).sby cvr4x8_lp
+$(AXILXBAR)_cvr1x3_lp/PASS: $(AXILXBAR).sby $(RTL)/$(AXILXBAR).v $(AXIL) $(XBAR)
+	sby -f $(AXILXBAR).sby cvr1x3_lp
+$(AXILXBAR)_cvr4x1_lp/PASS: $(AXILXBAR).sby $(RTL)/$(AXILXBAR).v $(AXIL) $(XBAR)
+	sby -f $(AXILXBAR).sby cvr4x1_lp
+
+
+.PHONY: $(WBXBAR) $(WBXBAR4x8) $(WBXBAR1x8) $(WBXBAR4x1)
+.PHONY: $(WBXBAR)_prf $(WBXBAR)_cvr
+.PHONY: $(WBXBAR4x8)_prf $(WBXBAR4x8)_cvr
+.PHONY: $(WBXBAR1x8)_prf $(WBXBAR1x8)_cvr
+.PHONY: $(WBXBAR4x1)_prf $(WBXBAR4x1)_cvr
+$(WBXBAR): $(WBXBAR4x1)_prf
+$(WBXBAR): $(WBXBAR1x8)_prf
+$(WBXBAR): $(WBXBAR4x8)_prf
+$(WBXBAR): $(WBXBAR4x1)_cvr
+$(WBXBAR): $(WBXBAR1x8)_cvr
+$(WBXBAR): $(WBXBAR4x8)_cvr
+$(WBXBAR)_prf: $(WBXBAR4x1)_prf $(WBXBAR1x8)_prf $(WBXBAR4x8)_prf
+$(WBXBAR)_cvr: $(WBXBAR4x1)_cvr $(WBXBAR1x8)_cvr $(WBXBAR4x8)_cvr
+
+$(WBXBAR4x8): $(WBXBAR4x8)_prf $(WBXBAR4x8)_cvr
+$(WBXBAR1x8): $(WBXBAR1x8)_prf $(WBXBAR1x8)_cvr
+$(WBXBAR4x1): $(WBXBAR4x1)_prf $(WBXBAR4x1)_cvr
+
+$(WBXBAR4x8)_prf: wbxbar_prf4x8_buflp/PASS
+$(WBXBAR4x8)_prf: wbxbar_prf4x8_buf/PASS
+$(WBXBAR4x8)_prf: wbxbar_prf4x8_lp/PASS
+$(WBXBAR4x8)_prf: wbxbar_prf4x8_cheap/PASS
+$(WBXBAR4x8)_prf: wbxbar_prf4x8_buflpko/PASS
+$(WBXBAR4x8)_prf: wbxbar_prf4x8_bufko/PASS
+$(WBXBAR4x8)_prf: wbxbar_prf4x8_lpko/PASS
+$(WBXBAR4x8)_prf: wbxbar_prf4x8_cheapko/PASS
+$(WBXBAR4x8)_prf: wbxbar_prf4x8_buflpkos/PASS
+$(WBXBAR4x8)_prf: wbxbar_prf4x8_bufkos/PASS
+$(WBXBAR4x8)_prf: wbxbar_prf4x8_lpkos/PASS
+$(WBXBAR4x8)_prf: wbxbar_prf4x8_cheapkos/PASS
+
+wbxbar_prf4x8_buflp/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x8_buflp
+wbxbar_prf4x8_buf/PASS:      $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x8_buf
+wbxbar_prf4x8_lp/PASS:       $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x8_lp
+wbxbar_prf4x8_cheap/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x8_cheap
+#
+wbxbar_prf4x8_buflpko/PASS:  $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x8_buflpko
+wbxbar_prf4x8_bufko/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x8_bufko
+wbxbar_prf4x8_lpko/PASS:     $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x8_lpko
+wbxbar_prf4x8_cheapko/PASS:  $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x8_cheapko
+wbxbar_prf4x8_buflpkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x8_buflpkos
+wbxbar_prf4x8_bufkos/PASS:   $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x8_bufkos
+wbxbar_prf4x8_lpkos/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x8_lpkos
+wbxbar_prf4x8_cheapkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x8_cheapkos
+#
+#
+$(WBXBAR4x8)_cvr: wbxbar_cvr4x8_buflp/PASS
+$(WBXBAR4x8)_cvr: wbxbar_cvr4x8_buf/PASS
+$(WBXBAR4x8)_cvr: wbxbar_cvr4x8_lp/PASS
+$(WBXBAR4x8)_cvr: wbxbar_cvr4x8_cheap/PASS
+#
+wbxbar_cvr4x8_buflp/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby cvr4x8_buflp
+wbxbar_cvr4x8_buf/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby cvr4x8_buf
+wbxbar_cvr4x8_lp/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby cvr4x8_lp
+wbxbar_cvr4x8_cheap/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby cvr4x8_cheap
+#
+#
+$(WBXBAR1x8)_prf: wbxbar_prf1x8_buflp/PASS
+$(WBXBAR1x8)_prf: wbxbar_prf1x8_buf/PASS
+$(WBXBAR1x8)_prf: wbxbar_prf1x8_lp/PASS
+$(WBXBAR1x8)_prf: wbxbar_prf1x8_cheap/PASS
+#
+
+wbxbar_prf1x8_buflp/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf1x8_buflp
+wbxbar_prf1x8_buf/PASS:      $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf1x8_buf
+wbxbar_prf1x8_lp/PASS:       $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf1x8_lp
+wbxbar_prf1x8_cheap/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf1x8_cheap
+#
+#
+$(WBXBAR1x8)_cvr: wbxbar_cvr1x3_buflp/PASS
+$(WBXBAR1x8)_cvr: wbxbar_cvr1x3_buf/PASS
+$(WBXBAR1x8)_cvr: wbxbar_cvr1x3_lp/PASS
+$(WBXBAR1x8)_cvr: wbxbar_cvr1x3_cheap/PASS
+#
+#
+wbxbar_cvr1x3_buflp/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby cvr1x3_buflp
+wbxbar_cvr1x3_buf/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby cvr1x3_buf
+wbxbar_cvr1x3_lp/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby cvr1x3_lp
+wbxbar_cvr1x3_cheap/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby cvr1x3_cheap
+#
+#
+$(WBXBAR1x8)_prf: wbxbar_prf1x8_buflpko/PASS
+$(WBXBAR1x8)_prf: wbxbar_prf1x8_bufko/PASS
+$(WBXBAR1x8)_prf: wbxbar_prf1x8_lpko/PASS
+$(WBXBAR1x8)_prf: wbxbar_prf1x8_cheapko/PASS
+$(WBXBAR1x8)_prf: wbxbar_prf1x8_buflpkos/PASS
+$(WBXBAR1x8)_prf: wbxbar_prf1x8_bufkos/PASS
+$(WBXBAR1x8)_prf: wbxbar_prf1x8_lpkos/PASS
+$(WBXBAR1x8)_prf: wbxbar_prf1x8_cheapkos/PASS
+#
+
+#
+wbxbar_prf1x8_buflpko/PASS:  $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf1x8_buflpko
+wbxbar_prf1x8_bufko/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf1x8_bufko
+wbxbar_prf1x8_lpko/PASS:     $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf1x8_lpko
+wbxbar_prf1x8_cheapko/PASS:  $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf1x8_cheapko
+wbxbar_prf1x8_buflpkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf1x8_buflpkos
+wbxbar_prf1x8_bufkos/PASS:   $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf1x8_bufkos
+wbxbar_prf1x8_lpkos/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf1x8_lpkos
+wbxbar_prf1x8_cheapkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf1x8_cheapkos
+#
+#
+$(WBXBAR4x1)_prf: wbxbar_prf4x1_buflp/PASS
+$(WBXBAR4x1)_prf: wbxbar_prf4x1_buf/PASS
+$(WBXBAR4x1)_prf: wbxbar_prf4x1_lp/PASS
+$(WBXBAR4x1)_prf: wbxbar_prf4x1_cheap/PASS
+#
+wbxbar_prf4x1_buflp/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x1_buflp
+wbxbar_prf4x1_buf/PASS:      $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x1_buf
+wbxbar_prf4x1_lp/PASS:       $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x1_lp
+wbxbar_prf4x1_cheap/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x1_cheap
+#
+$(WBXBAR4x1)_prf: wbxbar_prf4x1_buflpko/PASS
+$(WBXBAR4x1)_prf: wbxbar_prf4x1_bufko/PASS
+$(WBXBAR4x1)_prf: wbxbar_prf4x1_lpko/PASS
+$(WBXBAR4x1)_prf: wbxbar_prf4x1_cheapko/PASS
+$(WBXBAR4x1)_prf: wbxbar_prf4x1_buflpkos/PASS
+$(WBXBAR4x1)_prf: wbxbar_prf4x1_bufkos/PASS
+$(WBXBAR4x1)_prf: wbxbar_prf4x1_lpkos/PASS
+$(WBXBAR4x1)_prf: wbxbar_prf4x1_cheapkos/PASS
+#
+wbxbar_prf4x1_buflpko/PASS:  $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x1_buflpko
+wbxbar_prf4x1_bufko/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x1_bufko
+wbxbar_prf4x1_lpko/PASS:     $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x1_lpko
+wbxbar_prf4x1_cheapko/PASS:  $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x1_cheapko
+wbxbar_prf4x1_buflpkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x1_buflpkos
+wbxbar_prf4x1_bufkos/PASS:   $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x1_bufkos
+wbxbar_prf4x1_lpkos/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x1_lpkos
+wbxbar_prf4x1_cheapkos/PASS: $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby prf4x1_cheapkos
+#
+$(WBXBAR4x1)_cvr: wbxbar_cvr4x1_buflp/PASS
+$(WBXBAR4x1)_cvr: wbxbar_cvr4x1_buf/PASS
+$(WBXBAR4x1)_cvr: wbxbar_cvr4x1_lp/PASS
+$(WBXBAR4x1)_cvr: wbxbar_cvr4x1_cheap/PASS
+#
+wbxbar_cvr4x1_buflp/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby cvr4x1_buflp
+wbxbar_cvr4x1_buf/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby cvr4x1_buf
+wbxbar_cvr4x1_lp/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby cvr4x1_lp
+wbxbar_cvr4x1_cheap/PASS:    $(WBXBAR).sby $(RTL)/$(WBXBAR).v $(WB) $(XBAR)
+	sby -f $(WBXBAR).sby cvr4x1_cheap
+#
+#
+
+.PHONY: $(WBP2CLASSIC)
+$(WBP2CLASSIC): $(WBP2CLASSIC)_prf/PASS $(WBP2CLASSIC)_cvr/PASS
+$(WBP2CLASSIC)_prf/PASS: $(RTL)/$(WBP2CLASSIC).v $(WB) $(WBC)
+	sby -f $(WBP2CLASSIC).sby prf
+$(WBP2CLASSIC)_cvr/PASS: $(RTL)/$(WBP2CLASSIC).v $(WB) $(WBC)
+	sby -f $(WBP2CLASSIC).sby cvr
+
+.PHONY: $(WBC2PIPELIN)
+$(WBC2PIPELIN): $(WBC2PIPELIN)_prf/PASS $(WBC2PIPELIN)_cvr/PASS
+$(WBC2PIPELIN)_prf/PASS: $(RTL)/$(WBC2PIPELIN).v $(WB) $(WBC)
+	sby -f $(WBC2PIPELIN).sby prf
+$(WBC2PIPELIN)_cvr/PASS: $(RTL)/$(WBC2PIPELIN).v $(WB) $(WBC)
+	sby -f $(WBC2PIPELIN).sby cvr
+
+.PHONY: $(AXILSINGLE)
+$(AXILSINGLE): $(AXILSINGLE)_prf/PASS $(AXILSINGLE)_cvr/PASS
+$(AXILSINGLE)_prf/PASS: $(RTL)/$(AXILSINGLE).v $(RTL)/$(SFIFO).v $(AXILSINGLE).sby $(AXIL)
+	sby -f $(AXILSINGLE).sby prf
+$(AXILSINGLE)_cvr/PASS: $(RTL)/$(AXILSINGLE).v $(RTL)/$(SFIFO).v $(AXILSINGLE).sby $(AXIL)
+	sby -f $(AXILSINGLE).sby cvr
+
+.PHONY: $(AXILDOUBLE)
+$(AXILDOUBLE): $(AXILDOUBLE)_prf/PASS $(AXILDOUBLE)_cvr/PASS
+$(AXILDOUBLE)_prf/PASS: $(RTL)/$(AXILDOUBLE).v $(RTL)/$(SFIFO).v $(AXILDOUBLE).sby $(AXIL)
+	sby -f $(AXILDOUBLE).sby prf
+$(AXILDOUBLE)_cvr/PASS: $(RTL)/$(AXILDOUBLE).v $(RTL)/$(SFIFO).v $(AXILDOUBLE).sby $(AXIL)
+	sby -f $(AXILDOUBLE).sby cvr
+
+.PHONY: $(SFIFO)
+$(SFIFO): $(SFIFO)_prf/PASS    $(SFIFO)_prf_a/PASS  $(SFIFO)_cvr/PASS
+$(SFIFO): $(SFIFO)_prf_r/PASS  $(SFIFO)_prf_w/PASS  $(SFIFO)_prf_wr/PASS
+$(SFIFO): $(SFIFO)_prf_ar/PASS $(SFIFO)_prf_aw/PASS $(SFIFO)_prf_awr/PASS
+$(SFIFO)_prf/PASS: $(RTL)/$(SFIFO).v $(SFIFO).sby
+	sby -f $(SFIFO).sby prf
+$(SFIFO)_prf_r/PASS: $(RTL)/$(SFIFO).v $(SFIFO).sby
+	sby -f $(SFIFO).sby prf_r
+$(SFIFO)_prf_w/PASS: $(RTL)/$(SFIFO).v $(SFIFO).sby
+	sby -f $(SFIFO).sby prf_w
+$(SFIFO)_prf_wr/PASS: $(RTL)/$(SFIFO).v $(SFIFO).sby
+	sby -f $(SFIFO).sby prf_wr
+$(SFIFO)_prf_a/PASS: $(RTL)/$(SFIFO).v $(SFIFO).sby
+	sby -f $(SFIFO).sby prf_a
+$(SFIFO)_prf_ar/PASS: $(RTL)/$(SFIFO).v $(SFIFO).sby
+	sby -f $(SFIFO).sby prf_ar
+$(SFIFO)_prf_aw/PASS: $(RTL)/$(SFIFO).v $(SFIFO).sby
+	sby -f $(SFIFO).sby prf_aw
+$(SFIFO)_prf_awr/PASS: $(RTL)/$(SFIFO).v $(SFIFO).sby
+	sby -f $(SFIFO).sby prf_awr
+$(SFIFO)_cvr/PASS: $(RTL)/$(SFIFO).v $(SFIFO).sby
+	sby -f $(SFIFO).sby cvr
+
+.PHONY: $(AFIFO)
+$(AFIFO): $(AFIFO)_prf/PASS    $(AFIFO)_cvr/PASS
+$(AFIFO)_prf/PASS: $(RTL)/$(AFIFO).v $(AFIFO).sby
+	sby -f $(AFIFO).sby prf
+$(AFIFO)_cvr/PASS: $(RTL)/$(AFIFO).v $(AFIFO).sby
+	sby -f $(AFIFO).sby cvr
+
+.PHONY: $(DECODER)
+$(DECODER): $(DECODER)_prfrlp/PASS $(DECODER)_cvrrlp/PASS
+$(DECODER): $(DECODER)_prfr/PASS   $(DECODER)_cvrr/PASS
+$(DECODER): $(DECODER)_prfc/PASS   $(DECODER)_cvrc/PASS
+$(DECODER)_prfrlp/PASS: $(DECODER).sby $(RTL)/$(DECODER).v
+	sby -f $(DECODER).sby prfrlp
+$(DECODER)_prfr/PASS:   $(DECODER).sby $(RTL)/$(DECODER).v
+	sby -f $(DECODER).sby prfr
+$(DECODER)_prfc/PASS:   $(DECODER).sby $(RTL)/$(DECODER).v
+	sby -f $(DECODER).sby prfc
+$(DECODER)_cvrrlp/PASS: $(DECODER).sby $(RTL)/$(DECODER).v
+	sby -f $(DECODER).sby cvrrlp
+$(DECODER)_cvrr/PASS:   $(DECODER).sby $(RTL)/$(DECODER).v
+	sby -f $(DECODER).sby cvrr
+$(DECODER)_cvrc/PASS:   $(DECODER).sby $(RTL)/$(DECODER).v
+	sby -f $(DECODER).sby cvrc
+
+.PHONY: $(SKIDBUFFER)
+$(SKIDBUFFER): $(SKIDBUFFER)_prfc/PASS $(SKIDBUFFER)_prfo/PASS
+$(SKIDBUFFER): $(SKIDBUFFER)_lpc/PASS  $(SKIDBUFFER)_lpo/PASS
+$(SKIDBUFFER): $(SKIDBUFFER)_cvr/PASS
+$(SKIDBUFFER)_prfc/PASS: $(SKIDBUFFER).sby $(RTL)/$(SKIDBUFFER).v
+	sby -f $(SKIDBUFFER).sby prfc
+$(SKIDBUFFER)_prfo/PASS: $(SKIDBUFFER).sby $(RTL)/$(SKIDBUFFER).v
+	sby -f $(SKIDBUFFER).sby prfo
+$(SKIDBUFFER)_lpc/PASS:  $(SKIDBUFFER).sby $(RTL)/$(SKIDBUFFER).v
+	sby -f $(SKIDBUFFER).sby lpc
+$(SKIDBUFFER)_lpo/PASS:  $(SKIDBUFFER).sby $(RTL)/$(SKIDBUFFER).v
+	sby -f $(SKIDBUFFER).sby lpo
+$(SKIDBUFFER)_cvr/PASS:  $(SKIDBUFFER).sby $(RTL)/$(SKIDBUFFER).v
+	sby -f $(SKIDBUFFER).sby cvr
+
+.PHONY: $(WBSAFETY)
+$(WBSAFETY): $(WBSAFETY)_prf/PASS   $(WBSAFETY)_prfr/PASS
+$(WBSAFETY): $(WBSAFETY)_fault/PASS $(WBSAFETY)_faultr/PASS
+$(WBSAFETY): $(WBSAFETY)_cvr/PASS   $(SKIDBUFFER)
+WBSAFETYDEP := $(WBSAFETY).sby $(RTL)/$(WBSAFETY).v $(RTL)/$(SKIDBUFFER).v $(WB)
+$(WBSAFETY)_prf/PASS: $(WBSAFETYDEP)
+	sby -f $(WBSAFETY).sby prf
+$(WBSAFETY)_prfr/PASS: $(WBSAFETYDEP)
+	sby -f $(WBSAFETY).sby prfr
+$(WBSAFETY)_fault/PASS: $(WBSAFETYDEP)
+	sby -f $(WBSAFETY).sby fault
+$(WBSAFETY)_faultr/PASS: $(WBSAFETYDEP)
+	sby -f $(WBSAFETY).sby faultr
+$(WBSAFETY)_cvr/PASS: $(WBSAFETYDEP)
+	sby -f $(WBSAFETY).sby cvr
+
+.PHONY: $(AXILSAFETY)
+$(AXILSAFETY): $(AXILSAFETY)_prf/PASS    $(AXILSAFETY)_prfr/PASS
+$(AXILSAFETY): $(AXILSAFETY)_fault/PASS  $(AXILSAFETY)_faultr/PASS
+$(AXILSAFETY): $(AXILSAFETY)_prlong/PASS $(AXILSAFETY)_longr/PASS
+$(AXILSAFETY): $(AXILSAFETY)_cvr/PASS   $(SKIDBUFFER)
+AXILSAFETYDEP := $(AXILSAFETY).sby $(RTL)/$(AXILSAFETY).v $(RTL)/$(SKIDBUFFER).v $(WB)
+$(AXILSAFETY)_prf/PASS: $(AXILSAFETYDEP)
+	sby -f $(AXILSAFETY).sby prf
+$(AXILSAFETY)_prfr/PASS: $(AXILSAFETYDEP)
+	sby -f $(AXILSAFETY).sby prfr
+$(AXILSAFETY)_fault/PASS: $(AXILSAFETYDEP)
+	sby -f $(AXILSAFETY).sby fault
+$(AXILSAFETY)_faultr/PASS: $(AXILSAFETYDEP)
+	sby -f $(AXILSAFETY).sby faultr
+$(AXILSAFETY)_longr/PASS: $(AXILSAFETYDEP)
+	sby -f $(AXILSAFETY).sby longr
+$(AXILSAFETY)_prlong/PASS: $(AXILSAFETYDEP)
+	sby -f $(AXILSAFETY).sby prlong
+$(AXILSAFETY)_cvr/PASS: $(AXILSAFETYDEP)
+	sby -f $(AXILSAFETY).sby cvr
+
+.PHONY: $(AXIL2AXIS)
+$(AXIL2AXIS): $(AXIL2AXIS)_prf/PASS       $(AXIL2AXIS)_prflps/PASS
+$(AXIL2AXIS): $(AXIL2AXIS)_prflpu/PASS    $(AXIL2AXIS)_prfsink/PASS
+$(AXIL2AXIS): $(AXIL2AXIS)_prfsource/PASS $(AXIL2AXIS)_cvr/PASS
+AXIL2AXISDEPS := $(AXIL2AXIS).sby $(RTL)/sfifo.v $(RTL)/skidbuffer.v	\
+		$(RTL)/$(AXIL2AXIS).v $(AXIL)
+$(AXIL2AXIS)_prf/PASS: $(AXIL2AXISDEPS)
+	sby -f $(AXIL2AXIS).sby prf
+$(AXIL2AXIS)_prflpu/PASS: $(AXIL2AXISDEPS)
+	sby -f $(AXIL2AXIS).sby prflpu
+$(AXIL2AXIS)_prflps/PASS: $(AXIL2AXISDEPS)
+	sby -f $(AXIL2AXIS).sby prflps
+$(AXIL2AXIS)_prfsink/PASS: $(AXIL2AXISDEPS)
+	sby -f $(AXIL2AXIS).sby prfsink
+$(AXIL2AXIS)_prfsource/PASS: $(AXIL2AXISDEPS)
+	sby -f $(AXIL2AXIS).sby prfsource
+$(AXIL2AXIS)_cvr/PASS: $(AXIL2AXISDEPS)
+	sby -f $(AXIL2AXIS).sby cvr
+
+.PHONY: $(APBSLAVE)
+$(APBSLAVE): $(APBSLAVE)_prf/PASS       $(APBSLAVE)_cvr/PASS
+APBSLAVEDEPS := $(APBSLAVE).sby $(RTL)/$(APBSLAVE).v $(APB)
+$(APBSLAVE)_prf/PASS: $(APBSLAVEDEPS)
+	sby -f $(APBSLAVE).sby prf
+$(APBSLAVE)_cvr/PASS: $(APBSLAVEDEPS)
+	sby -f $(APBSLAVE).sby cvr
+
+.PHONY: $(AXIL2APB)
+$(AXIL2APB): $(AXIL2APB)_prf/PASS       $(AXIL2APB)_prfskd/PASS
+$(AXIL2APB): $(AXIL2APB)_cvr/PASS
+AXIL2APBDEPS := $(AXIL2APB).sby $(RTL)/$(AXIL2APB).v $(APB)
+$(AXIL2APB)_prf/PASS: $(AXIL2APBDEPS)
+	sby -f $(AXIL2APB).sby prf
+$(AXIL2APB)_prfskd/PASS: $(AXIL2APBDEPS)
+	sby -f $(AXIL2APB).sby prfskd
+$(AXIL2APB)_cvr/PASS: $(AXIL2APBDEPS)
+	sby -f $(AXIL2APB).sby cvr
+
+.PHONY: $(AXISRANDOM)
+$(AXISRANDOM): $(AXISRANDOM)_prf/PASS
+$(AXISRANDOM)_prf/PASS: $(AXISRANDOM).sby $(RTL)/$(AXISRANDOM).v
+	sby -f $(AXISRANDOM).sby prf
+
+.PHONY: $(AXISSWITCH)
+$(AXISSWITCH): $(AXISSWITCH)_prf/PASS
+$(AXISSWITCH)_prf/PASS: $(AXISSWITCH).sby $(RTL)/$(AXISSWITCH).v
+	sby -f $(AXISSWITCH).sby prf
+
+.PHONY: $(AXISSAFETY)
+$(AXISSAFETY): $(AXISSAFETY)_prf/PASS
+$(AXISSAFETY): $(AXISSAFETY)_prfr/PASS
+$(AXISSAFETY): $(AXISSAFETY)_prfrpkt/PASS
+$(AXISSAFETY): $(AXISSAFETY)_prfpkt/PASS
+$(AXISSAFETY): $(AXISSAFETY)_prfs/PASS
+$(AXISSAFETY): $(AXISSAFETY)_prfrs/PASS
+$(AXISSAFETY): $(AXISSAFETY)_prfrpkts/PASS
+$(AXISSAFETY): $(AXISSAFETY)_prfpkts/PASS
+$(AXISSAFETY): $(AXISSAFETY)_fault/PASS
+$(AXISSAFETY): $(AXISSAFETY)_faultr/PASS
+$(AXISSAFETY): $(AXISSAFETY)_faultrpkt/PASS
+$(AXISSAFETY): $(AXISSAFETY)_faultpkt/PASS
+$(AXISSAFETY): $(AXISSAFETY)_faults/PASS
+$(AXISSAFETY): $(AXISSAFETY)_faultrs/PASS
+$(AXISSAFETY): $(AXISSAFETY)_faultrpkts/PASS
+$(AXISSAFETY): $(AXISSAFETY)_faultpkts/PASS
+$(AXISSAFETY): $(AXISSAFETY)_cvr/PASS
+$(AXISSAFETY): $(AXISSAFETY)_cvrnopkt/PASS
+$(AXISSAFETY)_prf/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby prf
+$(AXISSAFETY)_prfr/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby prfr
+$(AXISSAFETY)_prfrpkt/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby prfrpkt
+$(AXISSAFETY)_prfpkt/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby prfpkt
+$(AXISSAFETY)_prfs/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby prfs
+$(AXISSAFETY)_prfrs/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby prfrs
+$(AXISSAFETY)_prfrpkts/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby prfrpkts
+$(AXISSAFETY)_prfpkts/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby prfpkts
+$(AXISSAFETY)_fault/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby fault
+$(AXISSAFETY)_faultr/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby faultr
+$(AXISSAFETY)_faultrpkt/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby faultrpkt
+$(AXISSAFETY)_faultpkt/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby faultpkt
+$(AXISSAFETY)_faults/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby faults
+$(AXISSAFETY)_faultrs/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby faultrs
+$(AXISSAFETY)_faultrpkts/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby faultrpkts
+$(AXISSAFETY)_faultpkts/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby faultpkts
+$(AXISSAFETY)_cvr/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby cvr
+$(AXISSAFETY)_cvrnopkt/PASS: $(AXISSAFETY).sby $(RTL)/$(AXISSAFETY).v
+	sby -f $(AXISSAFETY).sby cvrnopkt
+
+.PHONY: clean
+clean:
+	rm -rf  $(DEMOAXI)_*/
+	rm -rf  $(WBARB)_*/
+	rm -rf  $(WB2LITE)_*/
+	rm -rf  $(RDLITE)_*/     $(WRLITE)_*/
+	rm -rf  $(WBC2PIPELIN)_*/ $(WBP2CLASSIC)_*/
+	rm -rf  $(AXLITE)_*/     $(WBXCLK)_*/
+	rm -rf  $(SFIFO)_*/      $(AFIFO)_*/
+	rm -rf  $(SKIDBUFFER)_*/ $(DECODER)_*/
+	rm -rf  $(WBXBAR)_*/     $(AXILXBAR)_*/
+	rm -rf  $(AXILSINGLE)_*/ $(AXILDOUBLE)_*/
+	rm -rf  $(EASYAXIL)_*/
+	rm -rf  $(WBSAFETY)_*/   $(AXILSAFETY)_*/
+	rm -rf  $(AXIPERF)_*/    $(AXIL2AXIS)_*/
+	rm -rf  $(AXIL2APB)_*/   $(APBSLAVE)_*/
+	rm -rf	$(AXISRANDOM)_*/ $(AXISSWITCH)_*/
+	@# The three broken cores, to include Xilinx's
+	rm -rf  $(XILINXDEMO)_*/
+	rm -rf  $(XLNXSTREAM)_*/
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/README.md b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/README.md
new file mode 100644
index 0000000..ec71760
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/README.md
@@ -0,0 +1,65 @@
+Every IP component in the [rtl](../../rtl) directory should have a respective
+SymbiYosys script here.  (A .sby file.)  Many of the AXI scripts remain
+proprietary and so get published elsewhere, but the AXI-lite and Wishbone
+scripts can be found here.
+
+In addition to the formal verification scripts found in this directory,
+you'll also find a series of bus properties for various interface standards.
+In general, these property sets are found in pairs--one property set for the
+slave, and a second property set for verifying the bus master.  I routinely
+compare these sets against each other using [meld](https://meldmerge.org),
+so you shouldn't find any really substantial differences between them.
+
+## Wishbone (Pipelined)
+
+[Master](fwb_master.v) and [Slave](fwb_slave.v) properties.
+
+My properties insist on two clarifications to the WB specification: 1) any
+bus cycle may be aborted by dropping the CYC line, and 2) the CYC line will
+drop and all bus cycles will be aborted following any bus error.  I've also
+dropped the retry signal from the standard.
+
+## Wishbone (Classic)
+
+[Master](fwbc_master.v) and [Slave](fwbc_slave.v) properties.
+
+## AXI4-Lite
+
+[Master](faxil_master.v) and [Slave](faxil_slave.v) properties.  These may
+be the easiest AXI4-lite property sets to use.
+
+## AXI4
+
+These properties are kept in a separate repository.  You can see some of what
+they contain in the [master](faxi_master.v) and [slave](faxi_slave.v) properties
+contained in this directory.  The full properties, however, will allow you to
+do a proper induction (unbounded) proof.  Those full properties can also handle
+out-of-order packet returns, such as AXI permits, to make certain that a
+core is fully/properly functional.  The difficulty of checking these out of
+order properties using induction is one of the reasons these properties may be
+purchased rather than downloaded for free.
+
+## AXI Stream
+
+[Master](faxis_master.v) and [slave](faxis_slave.v) properties.
+
+I rarely use these properties, however.  I've found that every AXI stream
+slave is unique, especially input or output slaves that operate at a fixed
+rate.  These properties also rely upon default portlist properties for
+the rarely used signals, `TID`, `TKEEP`, `TDEST`, and `TUSER`, something
+Yosys didn't yet support when they were first written.
+
+That said, the properties are currently good enough as is to prove that
+[Xilinx's AXI-Stream master](xlnxstream_2018_3.v) demonstration IP is broken.
+
+## Avalon
+
+It's been a while since I've worked with Avalon, but the [slave
+properties](fav_slave.v) found here saved my bacon in a
+[Cyclone-V design](https://zipcpu.com/blog/2018/02/09/first-cyclonev.html)
+more than once.  These properties only use a subset of the Avalon signals
+as well, and don't support any of the burst signaling capabilities of Avalon.
+
+## APB
+
+[Master](fapb_master.v) and [slave](fapb_slave.v) properties.
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/addrdecode.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/addrdecode.sby
new file mode 100644
index 0000000..ef26cb1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/addrdecode.sby
@@ -0,0 +1,30 @@
+[tasks]
+prfrlp prf opt_registered opt_lowpower
+prfr   prf opt_registered
+prfc   prf
+cvrrlp cvr opt_registered opt_lowpower
+cvrr   cvr opt_registered
+cvrc   cvr
+
+[options]
+prf: mode prove
+prf: depth 4
+cvr: mode cover
+cvr: depth 16
+
+[engines]
+smtbmc
+
+[script]
+read -define ADDRDECODE
+read -formal addrdecode.v
+--pycode-begin--
+cmd = "hierarchy -top addrdecode"
+cmd += " -chparam OPT_LOWPOWER   %d" % (1 if "opt_lowpower"   in tags else 0)
+cmd += " -chparam OPT_REGISTERED %d" % (1 if "opt_registered" in tags else 0)
+output(cmd)
+--pycode-end--
+prep -top addrdecode
+
+[files]
+../../rtl/addrdecode.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/afifo.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/afifo.gtkw
new file mode 100644
index 0000000..0f6677f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/afifo.gtkw
@@ -0,0 +1,82 @@
+[*]
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Wed Dec 11 04:26:37 2019
+[*]
+[dumpfile] "(null)"
+[timestart] 0
+[size] 1920 1054
+[pos] -1 -1
+*-5.190785 160 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 196
+[signals_width] 150
+[sst_expanded] 1
+[sst_vpaned_height] 315
+@28
+[color] 3
+afifo.i_wclk
+[color] 3
+afifo.i_wr_reset_n
+[color] 3
+afifo.i_wr
+@22
+[color] 3
+afifo.i_wr_data[15:0]
+@28
+[color] 3
+afifo.o_wr_full
+@200
+-
+@28
+[color] 2
+afifo.i_rclk
+[color] 2
+afifo.i_rd_reset_n
+[color] 2
+afifo.i_rd
+@22
+[color] 2
+afifo.o_rd_data[15:0]
+@28
+[color] 2
+afifo.o_rd_empty
+@200
+-
+@22
+[color] 3
+afifo.wr_addr[3:0]
+[color] 3
+afifo.wr_rgray[3:0]
+afifo.rd_addr[3:0]
+afifo.rd_wgray[3:0]
+@200
+-
+@28
+afifo.f_state[1:0]
+@22
+afifo.f_addr[3:0]
+@28
+afifo.pre_rclk
+afifo.pre_wclk
+afifo.now_rclk
+@22
+afifo.mem<0>[15:0]
+@200
+-
+@22
+afifo.rd_wgray[3:0]
+afifo.rgray[3:0]
+@200
+-
+@22
+afifo.wgray[3:0]
+afifo.wr_rgray[3:0]
+afifo.f_first[15:0]
+@23
+afifo.f_next[15:0]
+@200
+-
+@28
+afifo.f_first_in_fifo
+afifo.f_next_in_fifo
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/afifo.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/afifo.sby
new file mode 100644
index 0000000..a7cd551
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/afifo.sby
@@ -0,0 +1,20 @@
+[tasks]
+prf
+cvr
+
+[options]
+prf: mode prove
+prf: depth 4
+cvr: mode cover
+cvr: depth 32
+multiclock on
+
+[engines]
+smtbmc boolector
+
+[script]
+read -formal -D AFIFO afifo.v
+prep -top afifo
+
+[files]
+../../rtl/afifo.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/apbslave.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/apbslave.gtkw
new file mode 100644
index 0000000..34c5bca
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/apbslave.gtkw
@@ -0,0 +1,46 @@
+[*]
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Wed Aug 19 14:48:18 2020
+[*]
+[dumpfile] "(null)"
+[timestart] 0
+[size] 1787 600
+[pos] -1 -1
+*-3.628906 30 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 196
+[signals_width] 126
+[sst_expanded] 1
+[sst_vpaned_height] 155
+@28
+apbslave.PRESETn
+apbslave.PCLK
+@200
+-
+@28
+[color] 3
+apbslave.PSEL
+[color] 3
+apbslave.PWRITE
+[color] 3
+apbslave.PENABLE
+@29
+[color] 2
+apbslave.PREADY
+@22
+[color] 3
+apbslave.PADDR[11:0]
+[color] 3
+apbslave.PWDATA[31:0]
+@23
+[color] 2
+apbslave.PRDATA[31:0]
+@29
+[color] 2
+apbslave.PSLVERR
+@200
+-
+@22
+apbslave.f_addr[11:0]
+apbslave.f_data[31:0]
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/apbslave.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/apbslave.sby
new file mode 100644
index 0000000..c9fffa0
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/apbslave.sby
@@ -0,0 +1,21 @@
+[tasks]
+prf
+cvr
+
+[options]
+prf: mode prove
+prf: depth 4
+cvr: mode cover
+cvr: depth 40
+
+[engines]
+smtbmc
+
+[script]
+read -formal apbslave.v
+read -formal fapb_slave.v
+prep -top apbslave
+
+[files]
+../../rtl/apbslave.v
+fapb_slave.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axi3reorder.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axi3reorder.sby
new file mode 100644
index 0000000..a6d73db
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axi3reorder.sby
@@ -0,0 +1,49 @@
+[tasks]
+bmcsreg		bmc opt_sreg
+bmcfifo		bmc
+bmcsreglp	bmc opt_sreg opt_lowpower
+bmcfifolp	bmc          opt_lowpower
+bmcsreglat	bmc opt_sreg              opt_low_latency
+bmcfifolat	bmc                       opt_low_latency
+bmcsreglatlp	bmc opt_sreg opt_lowpower opt_low_latency
+bmcfifolatlp	bmc          opt_lowpower opt_low_latency
+cvrsreg		cvr opt_sreg                                      # 34 steps
+cvrfifo		cvr					  cvrfifo # 21 steps
+cvrsreglp	cvr opt_sreg opt_lowpower                         # 34 steps
+cvrfifolp	cvr          opt_lowpower                 cvrfifo # 21 steps
+cvrsreglat	cvr opt_sreg              opt_low_latency         # 34 steps
+cvrfifolat	cvr                       opt_low_latency cvrfifo
+cvrsreglatlp	cvr opt_sreg opt_lowpower opt_low_latency
+cvrfifolatlp	cvr          opt_lowpower opt_low_latency cvrfifo
+
+[options]
+bmc: mode bmc
+bmc: depth 40
+cvr: mode cover
+cvr: depth 40
+# bmcsreg: 18 steps of BMC takes 19 hrs
+# bmcfifo: 22 steps of BMC takes 16 hrs
+# bmcsreglp: 18 steps of BMC takes 17 hrs
+# bmcfifolp: 23 steps of BMC takes 20 hrs
+
+[engines]
+# smtbmc
+smtbmc boolector
+
+[script]
+cvrfifo: read -define SFIFO
+read -formal sfifo.v
+read -formal axi3reorder.v
+--pycode-begin--
+cmd = "hierarchy -top axi3reorder -chparam DW 8 -chparam OPT_LGWFIFO 2"
+cmd += " -chparam C_AXI_ID_WIDTH 2"
+cmd += " -chparam OPT_METHOD      %d" % (1 if "opt_sreg" in tags else 2)
+cmd += " -chparam OPT_LOWPOWER    %d" % (1 if "opt_lowpower" in tags else 0)
+cmd += " -chparam OPT_LOW_LATENCY %d" % (1 if "opt_low_latency" in tags else 0)
+output(cmd)
+--pycode-end--
+prep -top axi3reorder
+
+[files]
+../../rtl/sfifo.v
+../../rtl/axi3reorder.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axi_addr_miter.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axi_addr_miter.sby
new file mode 100644
index 0000000..bc22da2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axi_addr_miter.sby
@@ -0,0 +1,36 @@
+[tasks]
+prf8
+prf16
+prf32
+prf64
+prf128
+prf256
+prf512
+prf1024
+
+[options]
+mode  bmc
+depth 2
+
+[engines]
+smtbmc
+
+[script]
+read -formal axi_addr.v
+read -formal faxi_addr.v
+read -formal axi_addr_miter.v
+prf8:    hierarchy -top axi_addr_miter -chparam DW    8
+prf16:   hierarchy -top axi_addr_miter -chparam DW   16
+prf32:   hierarchy -top axi_addr_miter -chparam DW   32
+prf64:   hierarchy -top axi_addr_miter -chparam DW   64
+prf128:  hierarchy -top axi_addr_miter -chparam DW  128
+prf256:  hierarchy -top axi_addr_miter -chparam DW  256
+prf512:  hierarchy -top axi_addr_miter -chparam DW  512
+prf1024: hierarchy -top axi_addr_miter -chparam DW 1024
+
+prep -top axi_addr_miter
+
+[files]
+../../rtl/axi_addr.v
+faxi_addr.v
+axi_addr_miter.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axi_addr_miter.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axi_addr_miter.v
new file mode 100644
index 0000000..8c8c24c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axi_addr_miter.v
@@ -0,0 +1,68 @@
+module	axi_addr_miter(i_last_addr, i_size, i_burst, i_len);
+	parameter	AW = 32,
+			DW = 32;
+	input	wire	[AW-1:0]	i_last_addr;
+	input	wire	[2:0]		i_size; // 1b, 2b, 4b, 8b, etc
+	input	wire	[1:0]		i_burst; // fixed, incr, wrap, reserved
+	input	wire	[7:0]		i_len;
+
+	localparam	DSZ = $clog2(DW)-3;
+
+	wire	[7:0]		ref_incr;
+	wire	[AW-1:0]	ref_next_addr;
+
+	faxi_addr #(.AW(AW))
+		ref(i_last_addr, i_size, i_burst, i_len,ref_incr,ref_next_addr);
+
+	wire	[AW-1:0]	uut_next_addr;
+
+	axi_addr #(.AW(AW), .DW(DW))
+		uut(i_last_addr, i_size, i_burst, i_len, uut_next_addr);
+
+	always @(*)
+		assert(DW == (1<<(DSZ+3)));
+
+	always @(*)
+		assume(i_burst != 2'b11);
+
+	always @(*)
+		assume(i_size <= DSZ);
+
+	always @(*)
+	if (i_burst == 2'b10)
+	begin
+		assume((i_len == 1)
+			||(i_len == 3)
+			||(i_len == 7)
+			||(i_len == 15));
+	end
+
+	reg	aligned;
+
+	always @(*)
+	begin
+		aligned = 0;
+		case(DSZ)
+		3'b000: aligned = 1;
+		3'b001: aligned = (i_last_addr[0] == 0);
+		3'b010: aligned = (i_last_addr[1:0] == 0);
+		3'b011: aligned = (i_last_addr[2:0] == 0);
+		3'b100: aligned = (i_last_addr[3:0] == 0);
+		3'b101: aligned = (i_last_addr[4:0] == 0);
+		3'b110: aligned = (i_last_addr[5:0] == 0);
+		3'b111: aligned = (i_last_addr[6:0] == 0);
+		endcase
+	end
+
+	always @(*)
+	if (i_burst == 2'b10)
+		assume(aligned);
+
+	always @(*)
+		assert(uut_next_addr == ref_next_addr);
+
+	always @(*)
+	if (i_burst == 2'b01)
+		assume(i_last_addr[AW-1:12] == ref_next_addr[AW-1:12]);
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axil2apb.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axil2apb.gtkw
new file mode 100644
index 0000000..f25cc74
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axil2apb.gtkw
@@ -0,0 +1,123 @@
+[*]
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Wed Aug 19 18:54:33 2020
+[*]
+[dumpfile] "(null)"
+[timestart] 0
+[size] 1920 1054
+[pos] -1 -1
+*-3.628906 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 196
+[signals_width] 230
+[sst_expanded] 1
+[sst_vpaned_height] 315
+@28
+axil2apb.S_AXI_ARESETN
+axil2apb.S_AXI_ACLK
+@200
+-
+@28
+[color] 2
+axil2apb.M_APB_PSEL
+[color] 2
+axil2apb.M_APB_PENABLE
+@29
+[color] 3
+axil2apb.M_APB_PREADY
+@22
+[color] 2
+axil2apb.M_APB_PADDR[31:0]
+@28
+[color] 2
+axil2apb.M_APB_PWRITE
+@22
+[color] 2
+axil2apb.M_APB_PWDATA[31:0]
+@28
+[color] 2
+axil2apb.M_APB_PPROT[2:0]
+@22
+[color] 2
+axil2apb.M_APB_PWSTRB[3:0]
+@23
+[color] 3
+axil2apb.M_APB_PRDATA[31:0]
+@29
+[color] 3
+axil2apb.M_APB_PSLVERR
+@200
+-
+@800200
+-AXI writes
+@28
+[color] 3
+axil2apb.S_AXI_AWVALID
+[color] 2
+axil2apb.S_AXI_AWREADY
+@22
+[color] 3
+axil2apb.S_AXI_AWADDR[31:0]
+@28
+[color] 3
+axil2apb.S_AXI_AWPROT[2:0]
+@200
+-
+@28
+[color] 3
+axil2apb.S_AXI_WVALID
+[color] 2
+axil2apb.S_AXI_WREADY
+@22
+[color] 3
+axil2apb.S_AXI_WDATA[31:0]
+[color] 3
+axil2apb.S_AXI_WSTRB[3:0]
+@200
+-
+@28
+[color] 2
+axil2apb.S_AXI_BVALID
+[color] 3
+axil2apb.S_AXI_BREADY
+[color] 2
+axil2apb.S_AXI_BRESP[1:0]
+axil2apb.faxi_awr_outstanding[1:0]
+axil2apb.faxi_wr_outstanding[1:0]
+axil2apb.axil_write_ready
+@1000200
+-AXI writes
+@800200
+-AXI reads
+@28
+[color] 3
+axil2apb.S_AXI_ARVALID
+[color] 2
+axil2apb.S_AXI_ARREADY
+@22
+[color] 3
+axil2apb.S_AXI_ARADDR[31:0]
+@28
+[color] 3
+axil2apb.S_AXI_ARPROT[2:0]
+@200
+-
+@28
+axil2apb.S_AXI_RVALID
+[color] 3
+axil2apb.S_AXI_RREADY
+@22
+[color] 2
+axil2apb.S_AXI_RDATA[31:0]
+@28
+[color] 2
+axil2apb.S_AXI_RRESP[1:0]
+axil2apb.faxi_rd_outstanding[1:0]
+axil2apb.axil_read_ready
+axil2apb.arskd_valid
+@1000200
+-AXI reads
+@28
+axil2apb.write_grant
+axil2apb.apb_idle
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axil2apb.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axil2apb.sby
new file mode 100644
index 0000000..05604b4
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axil2apb.sby
@@ -0,0 +1,28 @@
+[tasks]
+prf
+prfskd prf opt_skidbuffer
+cvr opt_skidbuffer
+
+[options]
+prf: mode prove
+prf: depth 20
+cvr: mode cover
+cvr: depth 40
+
+[engines]
+smtbmc
+
+[script]
+read -formal axil2apb.v
+read -formal fapb_master.v
+read -formal faxil_slave.v
+read -formal skidbuffer.v
+opt_skidbuffer:  hierarchy -top axil2apb -chparam OPT_OUTGOING_SKIDBUFFER 1
+~opt_skidbuffer: hierarchy -top axil2apb -chparam OPT_OUTGOING_SKIDBUFFER 0
+prep -top axil2apb
+
+[files]
+../../rtl/axil2apb.v
+../../rtl/skidbuffer.v
+faxil_slave.v
+fapb_master.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axil2axis.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axil2axis.gtkw
new file mode 100644
index 0000000..97a7628
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axil2axis.gtkw
@@ -0,0 +1,109 @@
+[*]
+[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
+[*] Sun Apr 19 18:19:02 2020
+[*]
+[dumpfile] "(null)"
+[timestart] 0
+[size] 1920 1021
+[pos] -1 -1
+*-4.124164 5 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] axil2axis.
+[sst_width] 270
+[signals_width] 190
+[sst_expanded] 1
+[sst_vpaned_height] 290
+@28
+axil2axis.S_AXI_ACLK
+axil2axis.S_AXI_ARESETN
+@c00200
+-AXIL Writes
+@28
+[color] 3
+axil2axis.S_AXI_AWVALID
+[color] 2
+axil2axis.S_AXI_AWREADY
+@22
+[color] 3
+axil2axis.S_AXI_AWADDR[3:0]
+@28
+[color] 3
+axil2axis.S_AXI_AWPROT[2:0]
+@200
+-
+@28
+[color] 3
+axil2axis.S_AXI_WVALID
+[color] 2
+axil2axis.S_AXI_WREADY
+@22
+[color] 3
+axil2axis.S_AXI_WDATA[31:0]
+[color] 3
+axil2axis.S_AXI_WSTRB[3:0]
+@200
+-
+@28
+[color] 2
+axil2axis.S_AXI_BVALID
+[color] 3
+axil2axis.S_AXI_BREADY
+[color] 2
+axil2axis.S_AXI_BRESP[1:0]
+@1401200
+-AXIL Writes
+@c00200
+-Stream Master
+@28
+[color] 2
+axil2axis.M_AXIS_TVALID
+[color] 3
+axil2axis.M_AXIS_TREADY
+[color] 2
+axil2axis.M_AXIS_TLAST
+@22
+axil2axis.wfifo_fill[9:0]
+@1401200
+-Stream Master
+@c00200
+-AXIL Reads
+@28
+[color] 3
+axil2axis.S_AXI_ARVALID
+[color] 2
+axil2axis.S_AXI_ARREADY
+@22
+[color] 3
+axil2axis.S_AXI_ARADDR[3:0]
+@28
+[color] 3
+axil2axis.S_AXI_ARPROT[2:0]
+@200
+-
+@28
+[color] 2
+axil2axis.S_AXI_RVALID
+[color] 3
+axil2axis.S_AXI_RREADY
+@22
+[color] 2
+axil2axis.S_AXI_RDATA[31:0]
+@28
+[color] 2
+axil2axis.S_AXI_RRESP[1:0]
+@1401200
+-AXIL Reads
+@c00200
+-Stream Slave
+@28
+[color] 3
+axil2axis.S_AXIS_TVALID
+[color] 2
+axil2axis.S_AXIS_TREADY
+[color] 3
+axil2axis.S_AXIS_TLAST
+@22
+axil2axis.rfifo_fill[9:0]
+@1401200
+-Stream Slave
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axil2axis.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axil2axis.sby
new file mode 100644
index 0000000..3577808
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axil2axis.sby
@@ -0,0 +1,39 @@
+[tasks]
+prf           opt_sink opt_src opt_sign opt_sign opt_timeout
+prflps    prf opt_sink opt_src opt_sign opt_lowpower opt_sign
+prflpu    prf opt_sink opt_src opt_sign opt_lowpower
+prfsink   prf opt_sink opt_src opt_sign
+prfsource prf opt_sink opt_src opt_sign
+cvr           opt_sink opt_src opt_timeout
+
+[options]
+prf: mode prove
+prf: depth 12
+cvr: mode cover
+cvr: depth 40
+
+[engines]
+smtbmc
+
+[script]
+read -formal axil2axis.v
+read -formal skidbuffer.v
+read -formal sfifo.v
+read -formal faxil_slave.v
+--pycode-begin--
+cmd = "hierarchy -top axil2axis"
+cmd += " -chparam OPT_TIMEOUT %d" % (5 if "opt_timeout" in tags else 0)
+cmd += " -chparam LGFIFO %d" % (2 if "cvr" in tags else 5)
+cmd += " -chparam OPT_SINK %d" % (1 if "opt_sink" in tags else 0)
+cmd += " -chparam OPT_SOURCE %d" % (1 if "opt_src" in tags else 0)
+cmd += " -chparam OPT_LOWPOWER %d" % (1 if "opt_lowpower" in tags else 0)
+cmd += " -chparam OPT_SIGN_EXTEND %d" % (1 if "opt_sign" in tags else 0)
+output(cmd);
+--pycode-end--
+prep -top axil2axis
+
+[files]
+../../rtl/axil2axis.v
+../../rtl/skidbuffer.v
+../../rtl/sfifo.v
+faxil_slave.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axildouble.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axildouble.sby
new file mode 100644
index 0000000..d397a0b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axildouble.sby
@@ -0,0 +1,30 @@
+[tasks]
+prf
+cvr
+
+[options]
+prf: mode prove
+prf: depth 14
+cvr: mode cover
+cvr: depth 40
+
+[engines]
+smtbmc boolector
+# prf: abc pdr
+
+[script]
+read -formal addrdecode.v
+read -formal axildouble.v
+read -formal faxil_slave.v
+read -formal faxil_master.v
+read -formal sfifo.v
+read -formal skidbuffer.v
+prep -top axildouble
+
+[files]
+../../rtl/sfifo.v
+../../rtl/skidbuffer.v
+../../rtl/addrdecode.v
+../../rtl/axildouble.v
+faxil_slave.v
+faxil_master.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilrd2wbsp.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilrd2wbsp.gtkw
new file mode 100644
index 0000000..4d5dddb
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilrd2wbsp.gtkw
@@ -0,0 +1,69 @@
+[*]
+[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
+[*] Fri Dec 28 05:15:33 2018
+[*]
+[dumpfile] "(null)"
+[timestart] 0
+[size] 1898 600
+[pos] -1 -1
+*-5.054117 210 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 270
+[signals_width] 210
+[sst_expanded] 1
+[sst_vpaned_height] 143
+@28
+[color] 3
+axilrd2wbsp.i_axi_reset_n
+[color] 3
+axilrd2wbsp.i_clk
+@200
+-
+@28
+axilrd2wbsp.i_axi_arvalid
+axilrd2wbsp.o_axi_arready
+@22
+axilrd2wbsp.i_axi_araddr[27:0]
+axilrd2wbsp.i_axi_arcache[3:0]
+@28
+axilrd2wbsp.i_axi_arprot[2:0]
+@200
+-
+@28
+[color] 2
+axilrd2wbsp.o_axi_rvalid
+[color] 2
+axilrd2wbsp.i_axi_rready
+@22
+[color] 2
+axilrd2wbsp.o_axi_rdata[31:0]
+@28
+[color] 2
+axilrd2wbsp.o_axi_rresp[1:0]
+@200
+-
+@28
+axilrd2wbsp.o_wb_cyc
+axilrd2wbsp.o_wb_stb
+@22
+axilrd2wbsp.o_wb_addr[25:0]
+@28
+[color] 2
+axilrd2wbsp.i_wb_stall
+[color] 2
+axilrd2wbsp.i_wb_ack
+@23
+[color] 2
+axilrd2wbsp.i_wb_data[31:0]
+@28
+[color] 2
+axilrd2wbsp.i_wb_err
+@200
+-
+@28
+[color] 3
+axilrd2wbsp.r_stb
+@22
+[color] 3
+axilrd2wbsp.r_addr[25:0]
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilrd2wbsp.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilrd2wbsp.sby
new file mode 100644
index 0000000..502ee69
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilrd2wbsp.sby
@@ -0,0 +1,23 @@
+[tasks]
+cvr
+prf
+
+[options]
+prf: mode prove
+prf: depth 5
+cvr: mode cover
+cvr: depth 32
+
+[engines]
+smtbmc
+
+[script]
+read -formal -D AXILRD2WBSP axilrd2wbsp.v
+read -formal -D AXILRD2WBSP faxil_slave.v
+read -formal -D AXILRD2WBSP fwb_master.v
+prep -top axilrd2wbsp
+
+[files]
+../../rtl/axilrd2wbsp.v
+faxil_slave.v
+fwb_master.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilsafety.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilsafety.gtkw
new file mode 100644
index 0000000..ef72a19
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilsafety.gtkw
@@ -0,0 +1,199 @@
+[*]
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Wed Apr 22 14:55:50 2020
+[*]
+[dumpfile] "(null)"
+[timestart] 0
+[size] 1920 1021
+[pos] -1 -1
+*-6.333802 496 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] axilsafety.
+[sst_width] 270
+[signals_width] 246
+[sst_expanded] 1
+[sst_vpaned_height] 290
+@28
+axilsafety.S_AXI_ACLK
+axilsafety.S_AXI_ARESETN
+@c00200
+-Slave Write
+@28
+[color] 3
+axilsafety.S_AXI_AWVALID
+[color] 2
+axilsafety.S_AXI_AWREADY
+@22
+[color] 3
+axilsafety.S_AXI_AWADDR[27:0]
+@28
+[color] 3
+axilsafety.S_AXI_AWPROT[2:0]
+@200
+-
+@28
+[color] 3
+axilsafety.S_AXI_WVALID
+[color] 2
+axilsafety.S_AXI_WREADY
+@22
+[color] 3
+axilsafety.S_AXI_WDATA[31:0]
+[color] 3
+axilsafety.S_AXI_WSTRB[3:0]
+@200
+-
+@28
+[color] 2
+axilsafety.S_AXI_BVALID
+[color] 3
+axilsafety.S_AXI_BREADY
+[color] 2
+axilsafety.S_AXI_BRESP[1:0]
+@1401200
+-Slave Write
+@28
+[color] 1
+axilsafety.o_write_fault
+@c00201
+-Slave Read
+@28
+[color] 3
+axilsafety.S_AXI_ARVALID
+[color] 2
+axilsafety.S_AXI_ARREADY
+@22
+[color] 3
+axilsafety.S_AXI_ARADDR[27:0]
+@28
+[color] 3
+axilsafety.S_AXI_ARPROT[2:0]
+@200
+-
+@28
+[color] 2
+axilsafety.S_AXI_RVALID
+[color] 3
+axilsafety.S_AXI_RREADY
+@22
+[color] 2
+axilsafety.S_AXI_RDATA[31:0]
+@28
+[color] 2
+axilsafety.S_AXI_RRESP[1:0]
+@1401201
+-Slave Read
+@28
+[color] 1
+axilsafety.o_read_fault
+[color] 2
+axilsafety.M_AXI_ARESETN
+@c00200
+-Downstream Write
+@28
+[color] 2
+axilsafety.M_AXI_AWVALID
+[color] 3
+axilsafety.M_AXI_AWREADY
+@22
+[color] 2
+axilsafety.M_AXI_AWADDR[27:0]
+@28
+[color] 2
+axilsafety.M_AXI_AWPROT[2:0]
+@200
+-
+@28
+[color] 2
+axilsafety.M_AXI_WVALID
+[color] 3
+axilsafety.M_AXI_WREADY
+@22
+[color] 2
+axilsafety.M_AXI_WDATA[31:0]
+[color] 2
+axilsafety.M_AXI_WSTRB[3:0]
+@200
+-
+@28
+[color] 3
+axilsafety.M_AXI_BVALID
+[color] 2
+axilsafety.M_AXI_BREADY
+[color] 3
+axilsafety.M_AXI_BRESP[1:0]
+@1401200
+-Downstream Write
+@c00200
+-Downstream Read
+@28
+[color] 2
+axilsafety.M_AXI_ARVALID
+[color] 3
+axilsafety.M_AXI_ARREADY
+@22
+[color] 2
+axilsafety.M_AXI_ARADDR[27:0]
+@28
+[color] 2
+axilsafety.M_AXI_ARPROT[2:0]
+@200
+-
+@28
+[color] 3
+axilsafety.M_AXI_RVALID
+[color] 2
+axilsafety.M_AXI_RREADY
+@22
+[color] 3
+axilsafety.M_AXI_RDATA[31:0]
+@28
+[color] 3
+axilsafety.M_AXI_RRESP[1:0]
+@1401200
+-Downstream Read
+@22
+axilsafety.aw_stall_counter[3:0]
+@28
+axilsafety.aw_stall_limit
+@22
+axilsafety.w_stall_counter[3:0]
+@28
+axilsafety.w_stall_limit
+@200
+-
+@c00200
+-Read Fault
+@22
+axilsafety.r_stall_counter[3:0]
+axilsafety.r_ack_timer[3:0]
+axilsafety.downstream_r_count[3:0]
+@200
+-
+@28
+axilsafety.downstream_r_zero
+axilsafety.r_stall_limit
+axilsafety.r_ack_limit
+axilsafety.last_rvalid
+axilsafety.last_rchanged
+@22
+axilsafety.r_count[3:0]
+axilsafety.faxils_rd_outstanding[3:0]
+axilsafety.ASSUME_FAULTLESS.faxilm_rd_outstanding[3:0]
+@1401200
+-Read Fault
+@200
+-
+@22
+axilsafety.faxils_awr_outstanding[3:0]
+axilsafety.faxils_rd_outstanding[3:0]
+axilsafety.faxils_wr_outstanding[3:0]
+axilsafety.aw_count[3:0]
+axilsafety.aw_stall_counter[3:0]
+axilsafety.downstream_aw_count[3:0]
+axilsafety.downstream_w_count[3:0]
+axilsafety.r_count[3:0]
+axilsafety.r_stall_counter[3:0]
+axilsafety.w_count[3:0]
+axilsafety.w_stall_counter[3:0]
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilsafety.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilsafety.sby
new file mode 100644
index 0000000..1ff9854
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilsafety.sby
@@ -0,0 +1,38 @@
+[tasks]
+prf
+cvr    fault     opt_reset
+fault        prf
+prfr         prf opt_reset
+faultr fault prf opt_reset
+longr  fault prf opt_reset opt_long_reset
+prlong       prf opt_reset opt_long_reset
+
+[options]
+prf: mode prove
+prf: depth 23
+cvr: mode cover
+cvr: depth 32
+
+[engines]
+smtbmc
+
+[script]
+read -formal axilsafety.v
+read -formal skidbuffer.v
+read -formal faxil_slave.v
+read -formal faxil_master.v
+--pycode-begin--
+cmd = "hierarchy -top axilsafety"
+cmd += " -chparam F_OPT_FAULTLESS %d" % (0 if "fault"     in tags else 1)
+cmd += " -chparam OPT_SELF_RESET  %d" % (1 if "opt_reset" in tags else 0)
+cmd += " -chparam OPT_MIN_RESET   %d" % (16 if "opt_long_reset" in tags else 0)
+cmd += " -chparam OPT_TIMEOUT 10"
+output(cmd)
+--pycode-end--
+prep -top axilsafety
+
+[files]
+../../rtl/skidbuffer.v
+../../rtl/axilsafety.v
+faxil_slave.v
+faxil_master.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilsingle.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilsingle.gtkw
new file mode 100644
index 0000000..b33474f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilsingle.gtkw
@@ -0,0 +1,203 @@
+[*]
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Mon Aug 19 20:26:38 2019
+[*]
+[dumpfile_mtime] "Mon Aug 19 20:23:51 2019"
+[dumpfile_size] 31391
+[timestart] 0
+[size] 1920 1029
+[pos] -1 -1
+*-3.628906 40 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 196
+[signals_width] 238
+[sst_expanded] 1
+[sst_vpaned_height] 306
+@28
+axilsingle.S_AXI_ACLK
+axilsingle.S_AXI_ARESETN
+@200
+-
+@c00200
+-S_WRITE
+@28
+[color] 3
+axilsingle.S_AXI_AWVALID
+axilsingle.S_AXI_AWREADY
+@22
+[color] 3
+axilsingle.S_AXI_AWADDR[31:0]
+@28
+[color] 3
+axilsingle.S_AXI_AWPROT[2:0]
+@200
+-
+@28
+[color] 3
+axilsingle.S_AXI_WVALID
+axilsingle.S_AXI_WREADY
+@22
+[color] 3
+axilsingle.S_AXI_WDATA[31:0]
+[color] 3
+axilsingle.S_AXI_WSTRB[3:0]
+@200
+-
+@28
+[color] 3
+axilsingle.S_AXI_BVALID
+axilsingle.S_AXI_BREADY
+[color] 3
+axilsingle.S_AXI_BRESP[1:0]
+@1401200
+-S_WRITE
+@800200
+-S_READ
+@28
+[color] 3
+axilsingle.S_AXI_ARVALID
+axilsingle.S_AXI_ARREADY
+@22
+[color] 3
+axilsingle.S_AXI_ARADDR[31:0]
+@28
+[color] 3
+axilsingle.S_AXI_ARPROT[2:0]
+@200
+-
+@28
+[color] 3
+axilsingle.S_AXI_RVALID
+axilsingle.S_AXI_RREADY
+@22
+[color] 3
+axilsingle.S_AXI_RDATA[31:0]
+@28
+[color] 3
+axilsingle.S_AXI_RRESP[1:0]
+@1000200
+-S_READ
+@200
+-
+@c00201
+-M_WRITE
+@22
+[color] 2
+axilsingle.M_AXI_AWVALID[7:0]
+@28
+[color] 2
+axilsingle.M_AXI_AWPROT[2:0]
+@200
+-
+@22
+axilsingle.M_AXI_WDATA[31:0]
+axilsingle.M_AXI_WSTRB[3:0]
+@200
+-
+@22
+axilsingle.M_AXI_BRESP[15:0]
+@1401201
+-M_WRITE
+@200
+-
+@800200
+-M_READ
+@22
+[color] 2
+axilsingle.M_AXI_ARVALID[7:0]
+@28
+[color] 2
+axilsingle.M_AXI_ARPROT[2:0]
+@200
+-
+@22
+axilsingle.M_AXI_RDATA[255:0]
+axilsingle.M_AXI_RRESP[15:0]
+@1000200
+-M_READ
+@200
+-
+-
+@28
+axilsingle.awskid_valid
+@22
+axilsingle.awskid_addr[29:0]
+@28
+axilsingle.awskid_prot[2:0]
+@22
+axilsingle.awskid_sel[8:0]
+@200
+-
+@28
+axilsingle.arskid_valid
+@22
+axilsingle.arskid_addr[31:0]
+@28
+axilsingle.arskid_prot[2:0]
+@22
+axilsingle.arskid_sel[8:0]
+@200
+-
+@28
+axilsingle.wskid_valid
+axilsingle.write_resp[1:0]
+@22
+axilsingle.wskid_data[35:0]
+@200
+-
+@28
+axilsingle.write_ready
+@22
+axilsingle.wout_valids[8:0]
+axilsingle.wout_addr[29:0]
+@200
+-
+@28
+axilsingle.woskid_ready
+axilsingle.woskid_valid
+@22
+axilsingle.write_index[29:0]
+@200
+-
+@28
+axilsingle.write_bvalid
+axilsingle.bempty
+axilsingle.bffull
+axilsingle.bfill[2:0]
+axilsingle.bfull
+@200
+-
+@28
+axilsingle.read_rvalid
+axilsingle.rdfull
+@22
+axilsingle.read_index[29:0]
+axilsingle.read_rdata[31:0]
+@28
+axilsingle.read_ready
+axilsingle.read_resp[1:0]
+axilsingle.rempty
+axilsingle.rfill[2:0]
+axilsingle.rfull
+axilsingle.roskid_ready
+axilsingle.roskid_valid
+@22
+axilsingle.rout_addr[29:0]
+axilsingle.rout_valids[8:0]
+@200
+-
+@22
+[color] 1
+axilsingle.count_awr_outstanding[3:0]
+[color] 1
+axilsingle.count_rd_outstanding[3:0]
+@200
+-
+@22
+axilsingle.f_axi_awr_outstanding[3:0]
+axilsingle.f_axi_rd_outstanding[3:0]
+axilsingle.f_axi_wr_outstanding[3:0]
+@28
+axilsingle.f_past_valid
+axilsingle.unused
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilsingle.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilsingle.sby
new file mode 100644
index 0000000..c1ba760
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilsingle.sby
@@ -0,0 +1,27 @@
+[tasks]
+prf
+cvr
+
+[options]
+prf: mode prove
+prf: depth 14
+cvr: mode cover
+cvr: depth 40
+
+[engines]
+smtbmc boolector
+
+[script]
+read -formal axilsingle.v
+read -formal faxil_slave.v
+read -formal faxil_master.v
+read -formal sfifo.v
+read -formal skidbuffer.v
+prep -top axilsingle
+
+[files]
+../../rtl/sfifo.v
+../../rtl/skidbuffer.v
+../../rtl/axilsingle.v
+faxil_slave.v
+faxil_master.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilwr2wbsp.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilwr2wbsp.sby
new file mode 100644
index 0000000..3ca0f73
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilwr2wbsp.sby
@@ -0,0 +1,23 @@
+[tasks]
+prf
+cvr
+
+[options]
+prf: mode prove
+prf: depth 5
+cvr: mode cover
+cvr: depth 40
+
+[engines]
+smtbmc
+
+[script]
+read -formal -D AXILWR2WBSP axilwr2wbsp.v
+read -formal -D AXILWR2WBSP faxil_slave.v
+read -formal -D AXILWR2WBSP fwb_master.v
+prep -top axilwr2wbsp
+
+[files]
+../../rtl/axilwr2wbsp.v
+faxil_slave.v
+fwb_master.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilxbar.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilxbar.sby
new file mode 100644
index 0000000..6dbfb97
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilxbar.sby
@@ -0,0 +1,57 @@
+[tasks]
+prf4x8_lp   nxm opt_lowpower
+prf4x8      nxm
+cvr4x8_lp   nxl opt_lowpower cvr
+cvr4x8      nxl              cvr
+prf1x8_lp   oxm opt_lowpower
+prf1x8      oxm
+cvr1x3_lp   oxl opt_lowpower cvr
+cvr1x3      oxl              cvr
+
+prf4x1_lp   nxo opt_lowpower
+prf4x1      nxo
+cvr4x1_lp   nxo opt_lowpower cvr
+cvr4x1      nxo              cvr
+
+[options]
+~cvr: mode prove
+~cvr: depth 4
+cvr:  mode cover
+cvr:  depth 64
+
+[engines]
+smtbmc boolector
+# smtbmc
+# smtbmc z3
+
+
+[script]
+read -formal addrdecode.v
+read -formal skidbuffer.v
+read -formal axilxbar.v
+read -formal faxil_slave.v
+read -formal faxil_master.v
+--pycode-begin--
+cmd = "hierarchy -top axilxbar"
+if ("nxm" in tags):
+	cmd += " -chparam  NM 4 -chparam NS 8"
+if ("oxm" in tags):
+	cmd += " -chparam  NM 1 -chparam NS 8"
+if ("oxl" in tags):
+	cmd += " -chparam  NM 1 -chparam NS 3"
+if ("nxl" in tags):
+	cmd += " -chparam  NM 3 -chparam NS 3"
+if ("nxo" in tags):
+	cmd += " -chparam  NM 4 -chparam NS 1"
+cmd += " -chparam C_AXI_ADDR_WIDTH 16"
+cmd += " -chparam OPT_LOWPOWER %d" % (1 if "opt_lowpower" in tags else 0)
+output(cmd)
+--pycode-end--
+prep -top axilxbar
+
+[files]
+../../rtl/skidbuffer.v
+../../rtl/addrdecode.v
+../../rtl/axilxbar.v
+faxil_slave.v
+faxil_master.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilxbar_4x1.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilxbar_4x1.gtkw
new file mode 100644
index 0000000..ce0f2fe
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilxbar_4x1.gtkw
@@ -0,0 +1,126 @@
+[*]
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Thu Dec 12 18:40:05 2019
+[*]
+[dumpfile_mtime] "Thu Dec 12 18:30:15 2019"
+[dumpfile_size] 197418
+[timestart] 0
+[size] 1920 1029
+[pos] -1 -429
+*-5.474993 38 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 196
+[signals_width] 182
+[sst_expanded] 1
+[sst_vpaned_height] 306
+@28
+axilxbar.S_AXI_ACLK
+axilxbar.S_AXI_ARESETN
+@200
+-
+@800200
+-Slave interface
+@22
+[color] 3
+axilxbar.S_AXI_AWVALID[3:0]
+@23
+[color] 2
+axilxbar.S_AXI_AWREADY[3:0]
+@22
+[color] 3
+axilxbar.S_AXI_AWADDR[63:0]
+[color] 3
+axilxbar.S_AXI_AWPROT[11:0]
+@200
+-
+@22
+[color] 3
+axilxbar.S_AXI_WVALID[3:0]
+@23
+[color] 2
+axilxbar.S_AXI_WREADY[3:0]
+@22
+[color] 3
+axilxbar.S_AXI_WDATA[127:0]
+[color] 3
+axilxbar.S_AXI_WSTRB[15:0]
+@200
+-
+@22
+[color] 2
+axilxbar.S_AXI_BVALID[3:0]
+[color] 3
+axilxbar.S_AXI_BREADY[3:0]
+[color] 2
+axilxbar.S_AXI_BRESP[7:0]
+@200
+-
+@22
+[color] 3
+axilxbar.S_AXI_ARVALID[3:0]
+[color] 2
+axilxbar.S_AXI_ARREADY[3:0]
+[color] 3
+axilxbar.S_AXI_ARADDR[63:0]
+[color] 3
+axilxbar.S_AXI_ARPROT[11:0]
+@200
+-
+@22
+[color] 2
+axilxbar.S_AXI_RVALID[3:0]
+[color] 3
+axilxbar.S_AXI_RREADY[3:0]
+[color] 2
+axilxbar.S_AXI_RDATA[127:0]
+[color] 2
+axilxbar.S_AXI_RRESP[7:0]
+@1000200
+-Slave interface
+@c00200
+-Master interface
+@28
+axilxbar.M_AXI_AWVALID
+axilxbar.M_AXI_AWREADY
+@22
+axilxbar.M_AXI_AWADDR[15:0]
+@28
+axilxbar.M_AXI_AWPROT[2:0]
+@200
+-
+@28
+axilxbar.M_AXI_WVALID
+axilxbar.M_AXI_WREADY
+@22
+axilxbar.M_AXI_WDATA[31:0]
+axilxbar.M_AXI_WSTRB[3:0]
+@200
+-
+@28
+axilxbar.M_AXI_BVALID
+axilxbar.M_AXI_BREADY
+axilxbar.M_AXI_BRESP[1:0]
+@200
+-
+@28
+axilxbar.M_AXI_ARVALID
+axilxbar.M_AXI_ARREADY
+@22
+axilxbar.M_AXI_ARADDR[15:0]
+@28
+axilxbar.M_AXI_ARPROT[2:0]
+@200
+-
+@28
+axilxbar.M_AXI_RVALID
+axilxbar.M_AXI_RREADY
+@22
+axilxbar.M_AXI_RDATA[31:0]
+@28
+axilxbar.M_AXI_RRESP[1:0]
+@1401200
+-Master interface
+@200
+-
+-
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilxbar_cvr1x3.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilxbar_cvr1x3.gtkw
new file mode 100644
index 0000000..ccdefb5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilxbar_cvr1x3.gtkw
@@ -0,0 +1,128 @@
+[*]
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Thu Dec 12 18:45:50 2019
+[*]
+[dumpfile_mtime] "Thu Dec 12 18:22:49 2019"
+[dumpfile_size] 187868
+[timestart] 0
+[size] 1920 1029
+[pos] 3839 0
+*-6.088337 260 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] axilxbar.
+[sst_width] 196
+[signals_width] 230
+[sst_expanded] 1
+[sst_vpaned_height] 324
+@28
+axilxbar.S_AXI_ACLK
+axilxbar.S_AXI_ARESETN
+@800200
+-Master write
+@28
+axilxbar.S_AXI_WVALID
+@22
+axilxbar.S_AXI_AWADDR[15:0]
+@28
+axilxbar.S_AXI_AWPROT[2:0]
+axilxbar.S_AXI_AWREADY
+axilxbar.S_AXI_AWVALID
+axilxbar.S_AXI_BREADY
+axilxbar.S_AXI_BRESP[1:0]
+axilxbar.S_AXI_BVALID
+@22
+axilxbar.S_AXI_WDATA[31:0]
+@28
+axilxbar.S_AXI_WREADY
+@22
+axilxbar.S_AXI_WSTRB[3:0]
+@200
+-
+-
+@1000200
+-Master write
+@800200
+-Master read
+@29
+axilxbar.S_AXI_ARVALID
+@22
+axilxbar.S_AXI_ARADDR[15:0]
+@28
+axilxbar.S_AXI_ARPROT[2:0]
+axilxbar.S_AXI_ARREADY
+@200
+-
+@28
+axilxbar.S_AXI_RVALID
+axilxbar.S_AXI_RREADY
+@22
+axilxbar.S_AXI_RDATA[31:0]
+@28
+axilxbar.S_AXI_RRESP[1:0]
+@1000200
+-Master read
+@800200
+-Slave write
+@28
+axilxbar.M_AXI_AWVALID[2:0]
+axilxbar.M_AXI_AWREADY[2:0]
+@22
+axilxbar.M_AXI_AWADDR[47:0]
+axilxbar.M_AXI_AWPROT[8:0]
+@200
+-
+@22
+axilxbar.M_AXI_WDATA[95:0]
+@28
+axilxbar.M_AXI_WREADY[2:0]
+@22
+axilxbar.M_AXI_WSTRB[11:0]
+@28
+axilxbar.M_AXI_WVALID[2:0]
+@200
+-
+@28
+axilxbar.M_AXI_BVALID[2:0]
+axilxbar.M_AXI_BREADY[2:0]
+@22
+axilxbar.M_AXI_BRESP[5:0]
+@1000200
+-Slave write
+@800200
+-Slave read
+@28
+axilxbar.M_AXI_ARVALID[2:0]
+axilxbar.M_AXI_ARREADY[2:0]
+@22
+axilxbar.M_AXI_ARADDR[47:0]
+axilxbar.M_AXI_ARPROT[8:0]
+@200
+-
+@22
+axilxbar.M_AXI_RDATA[95:0]
+@28
+axilxbar.M_AXI_RREADY[2:0]
+@22
+axilxbar.M_AXI_RRESP[5:0]
+@28
+axilxbar.M_AXI_RVALID[2:0]
+@1000200
+-Slave read
+@200
+-
+@28
+axilxbar.COVER_CONNECTIVITY_FROM_MASTER<0>.err_wr_return
+@22
+axilxbar.COVER_CONNECTIVITY_FROM_MASTER<0>.r_returns[3:0]
+axilxbar.COVER_CONNECTIVITY_FROM_MASTER<0>.w_returns[3:0]
+@28
+axilxbar.COVER_CONNECTIVITY_FROM_MASTER<0>.was_revery
+axilxbar.COVER_CONNECTIVITY_FROM_MASTER<0>.was_wevery
+axilxbar.COVER_CONNECTIVITY_FROM_MASTER<0>.err_wr_return
+@22
+axilxbar.COVER_CONNECTIVITY_FROM_MASTER<0>.r_returns[3:0]
+axilxbar.COVER_CONNECTIVITY_FROM_MASTER<0>.w_returns[3:0]
+@28
+axilxbar.COVER_CONNECTIVITY_FROM_MASTER<0>.was_revery
+axilxbar.COVER_CONNECTIVITY_FROM_MASTER<0>.was_wevery
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilxbar_prf1x8.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilxbar_prf1x8.gtkw
new file mode 100644
index 0000000..2128c59
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axilxbar_prf1x8.gtkw
@@ -0,0 +1,182 @@
+[*]
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Wed Apr 10 17:07:04 2019
+[*]
+[dumpfile] "(null)"
+[dumpfile_mtime] "Wed Apr 10 16:32:28 2019"
+[dumpfile_size] 94139
+[timestart] 0
+[size] 1920 1054
+[pos] -1 -1
+*-4.270011 30 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] axilxbar.
+[sst_width] 196
+[signals_width] 270
+[sst_expanded] 1
+[sst_vpaned_height] 315
+@28
+axilxbar.S_AXI_ACLK
+axilxbar.S_AXI_ARESETN
+@c00200
+-Master write
+@28
+[color] 3
+axilxbar.M_AXI_AWVALID
+[color] 2
+axilxbar.M_AXI_AWREADY
+@22
+[color] 3
+axilxbar.M_AXI_AWADDR[31:0]
+@28
+[color] 3
+axilxbar.M_AXI_AWPROT[2:0]
+@200
+-
+@28
+[color] 3
+axilxbar.M_AXI_WVALID
+[color] 2
+axilxbar.M_AXI_WREADY
+@22
+[color] 3
+axilxbar.M_AXI_WDATA[31:0]
+[color] 3
+axilxbar.M_AXI_WSTRB[3:0]
+@200
+-
+@28
+[color] 2
+axilxbar.M_AXI_BVALID
+[color] 3
+axilxbar.M_AXI_BREADY
+[color] 2
+axilxbar.M_AXI_BRESP[1:0]
+@1401200
+-Master write
+@800200
+-Master read
+@29
+[color] 3
+axilxbar.M_AXI_ARVALID
+@28
+[color] 2
+axilxbar.M_AXI_ARREADY
+@22
+[color] 3
+axilxbar.M_AXI_ARADDR[31:0]
+@28
+[color] 3
+axilxbar.M_AXI_ARPROT[2:0]
+@200
+-
+@28
+[color] 2
+axilxbar.M_AXI_RVALID
+[color] 3
+axilxbar.M_AXI_RREADY
+@22
+[color] 2
+axilxbar.M_AXI_RDATA[31:0]
+@28
+[color] 2
+axilxbar.M_AXI_RRESP[1:0]
+@1000200
+-Master read
+@22
+axilxbar.fm_awr_outstanding<0>[5:0]
+axilxbar.fm_wr_outstanding<0>[5:0]
+axilxbar.fm_rd_outstanding<0>[5:0]
+@28
+axilxbar.slave_awaccepts
+axilxbar.slave_raccepts
+axilxbar.slave_waccepts
+@800200
+-Slave write
+@22
+[color] 2
+axilxbar.S_AXI_AWVALID[7:0]
+[color] 3
+axilxbar.S_AXI_AWREADY[7:0]
+[color] 2
+axilxbar.S_AXI_AWADDR[255:0]
+[color] 2
+axilxbar.S_AXI_AWPROT[23:0]
+@200
+-
+@22
+[color] 2
+axilxbar.S_AXI_WVALID[7:0]
+[color] 3
+axilxbar.S_AXI_WREADY[7:0]
+[color] 2
+axilxbar.S_AXI_WDATA[255:0]
+[color] 2
+axilxbar.S_AXI_WSTRB[31:0]
+@200
+-
+@22
+[color] 3
+axilxbar.S_AXI_BVALID[7:0]
+[color] 2
+axilxbar.S_AXI_BREADY[7:0]
+[color] 3
+axilxbar.S_AXI_BRESP[15:0]
+@1000200
+-Slave write
+@200
+-
+@800200
+-Slave reads
+@22
+[color] 2
+axilxbar.S_AXI_ARVALID[7:0]
+[color] 3
+axilxbar.S_AXI_ARREADY[7:0]
+[color] 2
+axilxbar.S_AXI_RDATA[255:0]
+[color] 2
+axilxbar.S_AXI_ARPROT[23:0]
+@200
+-
+@22
+[color] 3
+axilxbar.S_AXI_RVALID[7:0]
+[color] 2
+axilxbar.S_AXI_RREADY[7:0]
+[color] 3
+axilxbar.S_AXI_RRESP[15:0]
+axilxbar.S_AXI_ARADDR[255:0]
+@1000200
+-Slave reads
+@28
+axilxbar.mrgrant
+@22
+axilxbar.mrindex<0>[3:0]
+@28
+axilxbar.WRITE_RETURN_CHANNEL<0>.r_bvalid
+axilxbar.WRITE_RETURN_CHANNEL<0>.r_bresp[1:0]
+axilxbar.WRITE_RETURN_CHANNEL<0>.axi_bvalid
+@22
+axilxbar.rgrant<0>[8:0]
+axilxbar.rrequest<0>[8:0]
+@28
+axilxbar.mrempty
+axilxbar.ARBITRATE_READ_REQUESTS<0>.leave_channel
+axilxbar.ARBITRATE_READ_REQUESTS<0>.requested_channel_is_available
+axilxbar.ARBITRATE_READ_REQUESTS<0>.stay_on_channel
+@200
+-
+@28
+axilxbar.mwgrant
+@22
+axilxbar.mwindex<0>[3:0]
+axilxbar.w_mwpending<0>[4:0]
+axilxbar.wrequest<0>[8:0]
+axilxbar.wgrant<0>[8:0]
+@28
+axilxbar.mwempty
+axilxbar.ARBITRATE_WRITE_REQUESTS<0>.stay_on_channel
+axilxbar.ARBITRATE_WRITE_REQUESTS<0>.leave_channel
+axilxbar.ARBITRATE_WRITE_REQUESTS<0>.requested_channel_is_available
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axim2wbsp.ys b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axim2wbsp.ys
new file mode 100644
index 0000000..c28f6f5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axim2wbsp.ys
@@ -0,0 +1,10 @@
+read_verilog -D AXIM2WBSP -formal ../../rtl/axim2wbsp.v
+read_verilog -D AXIM2WBSP -formal ../../rtl/aximwr2wbsp.v
+read_verilog -D AXIM2WBSP -formal ../../rtl/aximrd2wbsp.v
+read_verilog -D AXIM2WBSP -formal ../../rtl/wbarbiter.v
+read_verilog -D AXIM2WBSP -formal fwb_master.v
+read_verilog -D AXIM2WBSP -formal fwb_slave.v
+read_verilog -D AXIM2WBSP -formal faxi_slave.v
+read_verilog -D AXIM2WBSP -formal f_order.v
+prep -top axim2wbsp -nordff
+write_smt2 -wires axim2wbsp.smt2
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/aximrd2wbsp.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/aximrd2wbsp.gtkw
new file mode 100644
index 0000000..cc380a6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/aximrd2wbsp.gtkw
@@ -0,0 +1,88 @@
+[*]
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Fri Jan 25 20:03:10 2019
+[*]
+[dumpfile] "(null)"
+[timestart] 0
+[size] 1355 914
+[pos] -1 -1
+*-6.024491 180 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] tmpaximrd.
+[sst_width] 196
+[signals_width] 174
+[sst_expanded] 1
+[sst_vpaned_height] 265
+@28
+tmpaximrd.i_axi_reset_n
+tmpaximrd.i_axi_clk
+@200
+-
+@28
+[color] 3
+tmpaximrd.i_axi_arvalid
+[color] 1
+tmpaximrd.o_axi_arready
+@22
+[color] 3
+tmpaximrd.i_axi_araddr[27:0]
+@28
+[color] 3
+tmpaximrd.i_axi_arburst[1:0]
+@22
+[color] 3
+tmpaximrd.i_axi_arcache[3:0]
+[color] 3
+tmpaximrd.i_axi_arid[5:0]
+[color] 3
+tmpaximrd.i_axi_arlen[7:0]
+@28
+[color] 3
+tmpaximrd.i_axi_arlock
+[color] 3
+tmpaximrd.i_axi_arprot[2:0]
+@22
+[color] 3
+tmpaximrd.i_axi_arqos[3:0]
+@28
+[color] 3
+tmpaximrd.i_axi_arsize[2:0]
+@200
+-
+@28
+tmpaximrd.o_wb_cyc
+tmpaximrd.o_wb_stb
+@22
+tmpaximrd.o_wb_addr[25:0]
+@200
+-
+@28
+[color] 2
+tmpaximrd.i_wb_stall
+[color] 2
+tmpaximrd.i_wb_ack
+@22
+[color] 2
+tmpaximrd.i_wb_data[31:0]
+@28
+[color] 2
+tmpaximrd.i_wb_err
+@200
+-
+@28
+[color] 3
+tmpaximrd.o_axi_rvalid
+@29
+[color] 1
+tmpaximrd.i_axi_rready
+@22
+[color] 3
+tmpaximrd.o_axi_rid[5:0]
+[color] 3
+tmpaximrd.o_axi_rdata[31:0]
+@28
+[color] 3
+tmpaximrd.o_axi_rresp[1:0]
+[color] 3
+tmpaximrd.o_axi_rlast
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/aximrd2wbsp.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/aximrd2wbsp.sby
new file mode 100644
index 0000000..be4b26b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/aximrd2wbsp.sby
@@ -0,0 +1,29 @@
+[tasks]
+prf
+cvr
+
+[options]
+prf: mode prove
+cvr: mode cover
+depth 40
+
+[engines]
+smtbmc boolector
+
+[script]
+read -formal skidbuffer.v
+read -formal sfifo.v
+read -formal axi_addr.v
+read -formal aximrd2wbsp.v
+read -formal fwb_master.v
+read -formal faxi_slave.v
+prep -top aximrd2wbsp
+
+
+[files]
+../../rtl/sfifo.v
+../../rtl/skidbuffer.v
+../../rtl/axi_addr.v
+../../rtl/aximrd2wbsp.v
+fwb_master.v
+faxi_slave.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axiperf.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axiperf.sby
new file mode 100644
index 0000000..749108c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axiperf.sby
@@ -0,0 +1,23 @@
+[tasks]
+prf
+cvr
+
+[options]
+prf: mode prove
+prf: depth 3
+cvr: mode cover
+cvr: depth 40
+
+[engines]
+smtbmc
+
+[script]
+read -formal axiperf.v
+read -formal skidbuffer.v
+read -formal faxil_slave.v
+prep -top axiperf
+
+[files]
+../../rtl/axiperf.v
+../../rtl/skidbuffer.v
+faxil_slave.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axisgfsm.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axisgfsm.gtkw
new file mode 100644
index 0000000..1dbfec3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axisgfsm.gtkw
@@ -0,0 +1,209 @@
+[*]
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Fri Aug 28 23:47:05 2020
+[*]
+[dumpfile_mtime] "Fri Aug 28 22:59:36 2020"
+[dumpfile_size] 11128
+[timestart] 0
+[size] 1587 600
+[pos] -1 -1
+*-4.628906 50 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] axisgfsm.
+[sst_width] 196
+[signals_width] 174
+[sst_expanded] 1
+[sst_vpaned_height] 155
+@28
+axisgfsm.S_AXI_ACLK
+axisgfsm.S_AXI_ARESETN
+axisgfsm.i_start
+axisgfsm.i_abort
+axisgfsm.o_busy
+axisgfsm.dma_err
+@800200
+-Prefetch
+@28
+axisgfsm.o_pf_clear_cache
+axisgfsm.o_new_pc
+@22
+axisgfsm.o_pf_pc[29:0]
+@28
+[color] 3
+axisgfsm.i_pf_valid
+[color] 2
+axisgfsm.o_pf_ready
+@22
+[color] 3
+axisgfsm.i_pf_insn[31:0]
+[color] 3
+axisgfsm.o_pf_pc[29:0]
+@28
+[color] 3
+axisgfsm.i_pf_illegal
+@1000200
+-Prefetch
+@23
+axisgfsm.o_tbl_addr[29:0]
+@22
+axisgfsm.f_pc[29:0]
+@800200
+-DMA Control
+@22
+axisgfsm.f_tbladdr[29:0]
+@28
+axisgfsm.o_dmac_wvalid
+axisgfsm.i_dmac_wready
+@22
+axisgfsm.o_dmac_waddr[4:0]
+axisgfsm.o_dmac_wdata[31:0]
+axisgfsm.o_dmac_wstrb[3:0]
+axisgfsm.i_dmac_rdata[31:0]
+@1000200
+-DMA Control
+@22
+axisgfsm.SMALL_ADDRESS_SPACE.f_dma_seq[5:0]
+@c00022
+axisgfsm.f_tblentry[95:0]
+@28
+(0)axisgfsm.f_tblentry[95:0]
+(1)axisgfsm.f_tblentry[95:0]
+(2)axisgfsm.f_tblentry[95:0]
+(3)axisgfsm.f_tblentry[95:0]
+(4)axisgfsm.f_tblentry[95:0]
+(5)axisgfsm.f_tblentry[95:0]
+(6)axisgfsm.f_tblentry[95:0]
+(7)axisgfsm.f_tblentry[95:0]
+(8)axisgfsm.f_tblentry[95:0]
+(9)axisgfsm.f_tblentry[95:0]
+(10)axisgfsm.f_tblentry[95:0]
+(11)axisgfsm.f_tblentry[95:0]
+(12)axisgfsm.f_tblentry[95:0]
+(13)axisgfsm.f_tblentry[95:0]
+(14)axisgfsm.f_tblentry[95:0]
+(15)axisgfsm.f_tblentry[95:0]
+(16)axisgfsm.f_tblentry[95:0]
+(17)axisgfsm.f_tblentry[95:0]
+(18)axisgfsm.f_tblentry[95:0]
+(19)axisgfsm.f_tblentry[95:0]
+(20)axisgfsm.f_tblentry[95:0]
+(21)axisgfsm.f_tblentry[95:0]
+(22)axisgfsm.f_tblentry[95:0]
+(23)axisgfsm.f_tblentry[95:0]
+(24)axisgfsm.f_tblentry[95:0]
+(25)axisgfsm.f_tblentry[95:0]
+(26)axisgfsm.f_tblentry[95:0]
+(27)axisgfsm.f_tblentry[95:0]
+(28)axisgfsm.f_tblentry[95:0]
+(29)axisgfsm.f_tblentry[95:0]
+(30)axisgfsm.f_tblentry[95:0]
+(31)axisgfsm.f_tblentry[95:0]
+(32)axisgfsm.f_tblentry[95:0]
+(33)axisgfsm.f_tblentry[95:0]
+(34)axisgfsm.f_tblentry[95:0]
+(35)axisgfsm.f_tblentry[95:0]
+(36)axisgfsm.f_tblentry[95:0]
+(37)axisgfsm.f_tblentry[95:0]
+(38)axisgfsm.f_tblentry[95:0]
+(39)axisgfsm.f_tblentry[95:0]
+(40)axisgfsm.f_tblentry[95:0]
+(41)axisgfsm.f_tblentry[95:0]
+(42)axisgfsm.f_tblentry[95:0]
+(43)axisgfsm.f_tblentry[95:0]
+(44)axisgfsm.f_tblentry[95:0]
+(45)axisgfsm.f_tblentry[95:0]
+(46)axisgfsm.f_tblentry[95:0]
+(47)axisgfsm.f_tblentry[95:0]
+(48)axisgfsm.f_tblentry[95:0]
+(49)axisgfsm.f_tblentry[95:0]
+(50)axisgfsm.f_tblentry[95:0]
+(51)axisgfsm.f_tblentry[95:0]
+(52)axisgfsm.f_tblentry[95:0]
+(53)axisgfsm.f_tblentry[95:0]
+(54)axisgfsm.f_tblentry[95:0]
+(55)axisgfsm.f_tblentry[95:0]
+(56)axisgfsm.f_tblentry[95:0]
+(57)axisgfsm.f_tblentry[95:0]
+(58)axisgfsm.f_tblentry[95:0]
+(59)axisgfsm.f_tblentry[95:0]
+(60)axisgfsm.f_tblentry[95:0]
+(61)axisgfsm.f_tblentry[95:0]
+(62)axisgfsm.f_tblentry[95:0]
+(63)axisgfsm.f_tblentry[95:0]
+(64)axisgfsm.f_tblentry[95:0]
+(65)axisgfsm.f_tblentry[95:0]
+(66)axisgfsm.f_tblentry[95:0]
+(67)axisgfsm.f_tblentry[95:0]
+(68)axisgfsm.f_tblentry[95:0]
+(69)axisgfsm.f_tblentry[95:0]
+(70)axisgfsm.f_tblentry[95:0]
+(71)axisgfsm.f_tblentry[95:0]
+(72)axisgfsm.f_tblentry[95:0]
+(73)axisgfsm.f_tblentry[95:0]
+(74)axisgfsm.f_tblentry[95:0]
+(75)axisgfsm.f_tblentry[95:0]
+(76)axisgfsm.f_tblentry[95:0]
+(77)axisgfsm.f_tblentry[95:0]
+(78)axisgfsm.f_tblentry[95:0]
+(79)axisgfsm.f_tblentry[95:0]
+(80)axisgfsm.f_tblentry[95:0]
+(81)axisgfsm.f_tblentry[95:0]
+(82)axisgfsm.f_tblentry[95:0]
+(83)axisgfsm.f_tblentry[95:0]
+(84)axisgfsm.f_tblentry[95:0]
+(85)axisgfsm.f_tblentry[95:0]
+(86)axisgfsm.f_tblentry[95:0]
+(87)axisgfsm.f_tblentry[95:0]
+(88)axisgfsm.f_tblentry[95:0]
+(89)axisgfsm.f_tblentry[95:0]
+(90)axisgfsm.f_tblentry[95:0]
+(91)axisgfsm.f_tblentry[95:0]
+(92)axisgfsm.f_tblentry[95:0]
+(93)axisgfsm.f_tblentry[95:0]
+(94)axisgfsm.f_tblentry[95:0]
+(95)axisgfsm.f_tblentry[95:0]
+@1401200
+-group_end
+@28
+axisgfsm.f_dma_busy
+axisgfsm.dma_abort
+axisgfsm.dma_busy
+axisgfsm.dma_done
+axisgfsm.dma_err
+axisgfsm.o_busy
+axisgfsm.o_done
+axisgfsm.o_err
+axisgfsm.o_int
+axisgfsm.f_dma_complete
+axisgfsm.i_dma_complete
+@200
+-
+@28
+axisgfsm.sgstate[2:0]
+@200
+-
+@28
+axisgfsm.f_dma_busy
+axisgfsm.f_dma_complete
+axisgfsm.f_past_valid
+axisgfsm.i_dma_complete
+axisgfsm.i_pf_illegal
+@22
+axisgfsm.i_pf_insn[31:0]
+@28
+axisgfsm.i_pf_valid
+@c00028
+axisgfsm.i_prot[2:0]
+@28
+(0)axisgfsm.i_prot[2:0]
+(1)axisgfsm.i_prot[2:0]
+(2)axisgfsm.i_prot[2:0]
+@1401200
+-group_end
+@22
+axisgfsm.i_qos[3:0]
+axisgfsm.r_pf_pc[59:0]
+@28
+axisgfsm.tbl_int_enable
+axisgfsm.tbl_last
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axisgfsm.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axisgfsm.sby
new file mode 100644
index 0000000..502eaf7
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axisgfsm.sby
@@ -0,0 +1,27 @@
+[tasks]
+prf
+cvr
+
+[options]
+prf: mode prove
+prf: depth 20
+cvr: mode cover
+cvr: depth 40
+
+[engines]
+smtbmc
+
+[script]
+read -formal axisgfsm.v
+read -formal faxil_master.v
+# --pycode-begin--
+# cmd = "hierarchy -top easyaxil"
+# cmd += " -chparam OPT_SKIDBUFFER %d" % (1 if "opt_skidbuffer" in tags else 0)
+# cmd += " -chparam OPT_LOWPOWER %d" % (1 if "opt_lowpower" in tags else 0)
+# output(cmd);
+# --pycode-end--
+prep -top axisgfsm
+
+[files]
+../../rtl/axisgfsm.v
+faxil_master.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axisrandom.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axisrandom.sby
new file mode 100644
index 0000000..9ba6ec8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axisrandom.sby
@@ -0,0 +1,18 @@
+[tasks]
+prf
+
+[options]
+prf: mode prove
+prf: depth 3
+# cvr: mode cover
+# cvr: depth 40
+
+[engines]
+smtbmc
+
+[script]
+read -formal axisrandom.v
+prep -top axisrandom
+
+[files]
+../../rtl/axisrandom.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axissafety.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axissafety.gtkw
new file mode 100644
index 0000000..3c3c145
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axissafety.gtkw
@@ -0,0 +1,72 @@
+[*]
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Sat Sep 26 21:22:11 2020
+[*]
+[timestart] 0
+[size] 1468 599
+[pos] -1 -1
+*-6.594141 56 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] axissafety.
+[sst_width] 196
+[signals_width] 206
+[sst_expanded] 1
+[sst_vpaned_height] 155
+@28
+axissafety.S_AXI_ACLK
+axissafety.S_AXI_ARESETN
+@800200
+-Incoming slave
+@28
+axissafety.S_AXIS_TVALID
+axissafety.S_AXIS_TREADY
+@22
+axissafety.S_AXIS_TDATA[7:0]
+@28
+axissafety.S_AXIS_TLAST
+axissafety.S_AXIS_TUSER
+@1000200
+-Incoming slave
+@c00200
+-Skid buffer
+@28
+axissafety.skd_valid
+axissafety.skd_ready
+@22
+axissafety.skd_data[7:0]
+@28
+axissafety.skd_last
+axissafety.skd_user
+axissafety.skdr_valid
+@1401200
+-Skid buffer
+@800200
+-Outgoing master
+@28
+axissafety.M_AXIS_TVALID
+axissafety.M_AXIS_TREADY
+@22
+axissafety.M_AXIS_TDATA[7:0]
+@28
+axissafety.M_AXIS_TLAST
+axissafety.M_AXIS_TUSER
+@1000200
+-Outgoing master
+@28
+axissafety.m_end_of_packet
+@c00200
+-Faults
+@28
+axissafety.r_stalled
+axissafety.change_fault
+axissafety.packet_fault
+axissafety.stall_fault
+axissafety.o_fault
+@1401200
+-Faults
+@28
+axissafety.fm_packet_counter[2:0]
+axissafety.fs_packet_counter[2:0]
+axissafety.m_packet_count[2:0]
+axissafety.s_packet_counter[2:0]
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axissafety.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axissafety.sby
new file mode 100644
index 0000000..67cc372
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axissafety.sby
@@ -0,0 +1,43 @@
+[tasks]
+prf
+prfr               prf opt_reset
+prfrpkt            prf opt_reset opt_packet
+prfpkt             prf           opt_packet
+prfs               prf                      opt_mxstall
+prfrs              prf opt_reset            opt_mxstall
+prfrpkts           prf opt_reset opt_packet opt_mxstall
+prfpkts            prf           opt_packet opt_mxstall
+fault              prf
+faultr       fault prf opt_reset
+faultrpkt    fault prf opt_reset opt_packet
+faultpkt     fault prf           opt_packet
+faults       fault prf                      opt_mxstall
+faultrs      fault prf opt_reset            opt_mxstall
+faultrpkts   fault prf opt_reset opt_packet opt_mxstall
+faultpkts    fault prf           opt_packet opt_mxstall
+cvr          fault     opt_reset opt_packet opt_mxstall
+cvrnopkt cvr fault     opt_reset            opt_mxstall
+
+[options]
+prf: mode prove
+prf: depth 4
+cvr: mode cover
+cvr: depth 32
+
+[engines]
+smtbmc
+
+[script]
+read -formal axissafety.v
+--pycode-begin--
+cmd = "hierarchy -top axissafety"
+cmd += " -chparam F_OPT_FAULTLESS   %d" % ( 0 if "fault"       in tags else 1)
+cmd += " -chparam OPT_SELF_RESET    %d" % ( 1 if "opt_reset"   in tags else 0)
+cmd += " -chparam OPT_PACKET_LENGTH %d" % ( 5 if "opt_packet"  in tags else 0)
+cmd += " -chparam OPT_MAX_STALL     %d" % (10 if "opt_mxstall" in tags else 0)
+output(cmd)
+--pycode-end--
+prep -top axissafety
+
+[files]
+../../rtl/axissafety.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axisswitch.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axisswitch.gtkw
new file mode 100644
index 0000000..d5db567
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axisswitch.gtkw
@@ -0,0 +1,81 @@
+[*]
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Thu Aug 27 22:04:38 2020
+[*]
+[dumpfile] "(null)"
+[size] 1303 600
+[pos] -1 -1
+*-4.190785 35 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 196
+[signals_width] 198
+[sst_expanded] 1
+[sst_vpaned_height] 155
+@28
+axisswitch.S_AXI_ACLK
+axisswitch.S_AXI_ARESETN
+@800200
+-Outgoing stream
+@28
+axisswitch.M_AXIS_TVALID
+axisswitch.M_AXIS_TREADY
+@22
+axisswitch.M_AXIS_TDATA[31:0]
+@28
+axisswitch.M_AXIS_TLAST
+@1000200
+-Outgoing stream
+@800200
+-Incoming streams
+@22
+axisswitch.S_AXIS_TVALID[3:0]
+axisswitch.S_AXIS_TREADY[3:0]
+axisswitch.S_AXIS_TDATA[127:0]
+axisswitch.S_AXIS_TLAST[3:0]
+@1000200
+-Incoming streams
+@c00201
+-AXI-Lite control
+@28
+axisswitch.S_AXI_AWVALID
+axisswitch.S_AXI_AWREADY
+@200
+-
+@28
+axisswitch.S_AXI_WVALID
+axisswitch.S_AXI_WREADY
+@22
+axisswitch.S_AXI_WDATA[31:0]
+axisswitch.S_AXI_WSTRB[3:0]
+@28
+axisswitch.S_AXI_BREADY
+axisswitch.S_AXI_BVALID
+@200
+-
+@28
+axisswitch.S_AXI_ARVALID
+axisswitch.S_AXI_ARREADY
+@200
+-
+@28
+axisswitch.S_AXI_RVALID
+axisswitch.S_AXI_RREADY
+@22
+axisswitch.S_AXI_RDATA[31:0]
+@1401201
+-AXI-Lite control
+@22
+axisswitch.skd_valid[3:0]
+axisswitch.skd_switch_ready[3:0]
+@28
+axisswitch.r_index[1:0]
+axisswitch.switch_index[1:0]
+axisswitch.f_const_index[1:0]
+axisswitch.f_this_index[1:0]
+@22
+axisswitch.f_count[3:0]
+axisswitch.f_recount[3:0]
+@28
+axisswitch.f_accepts
+axisswitch.f_delivers
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axisswitch.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axisswitch.sby
new file mode 100644
index 0000000..6e38ea6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axisswitch.sby
@@ -0,0 +1,29 @@
+[tasks]
+prf
+# cvr
+
+[options]
+prf: mode prove
+prf: depth 3
+# cvr: mode cover
+# cvr: depth 40
+
+[engines]
+smtbmc
+
+[script]
+read -formal axisswitch.v
+read -formal skidbuffer.v
+read -formal faxil_slave.v
+# --pycode-begin--
+# cmd = "hierarchy -top easyaxil"
+# cmd += " -chparam OPT_SKIDBUFFER %d" % (1 if "opt_skidbuffer" in tags else 0)
+# cmd += " -chparam OPT_LOWPOWER %d" % (1 if "opt_lowpower" in tags else 0)
+# output(cmd);
+# --pycode-end--
+prep -top axisswitch
+
+[files]
+../../rtl/axisswitch.v
+../../rtl/skidbuffer.v
+faxil_slave.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axlite2wbsp.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axlite2wbsp.gtkw
new file mode 100644
index 0000000..90019a1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axlite2wbsp.gtkw
@@ -0,0 +1,121 @@
+[*]
+[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
+[*] Fri Dec 28 11:45:02 2018
+[*]
+[dumpfile] "(null)"
+[timestart] 0
+[size] 1920 1021
+[pos] -1 -1
+*-6.124164 160 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] axlite2wbsp.
+[treeopen] axlite2wbsp.ARB_WB.
+[treeopen] axlite2wbsp.AXI_RD.
+[treeopen] axlite2wbsp.AXI_RD.axi_read_decoder.
+[treeopen] axlite2wbsp.AXI_WR.
+[treeopen] axlite2wbsp.AXI_WR.axi_write_decoder.
+[sst_width] 270
+[signals_width] 210
+[sst_expanded] 1
+[sst_vpaned_height] 290
+@28
+[color] 3
+axlite2wbsp.i_axi_reset_n
+[color] 3
+axlite2wbsp.o_reset
+[color] 3
+axlite2wbsp.i_clk
+@200
+-
+@28
+[color] 2
+axlite2wbsp.i_axi_awvalid
+[color] 2
+axlite2wbsp.o_axi_awready
+@22
+[color] 2
+axlite2wbsp.i_axi_awaddr[27:0]
+@c00022
+[color] 2
+axlite2wbsp.i_axi_awcache[3:0]
+@28
+(0)axlite2wbsp.i_axi_awcache[3:0]
+(1)axlite2wbsp.i_axi_awcache[3:0]
+(2)axlite2wbsp.i_axi_awcache[3:0]
+(3)axlite2wbsp.i_axi_awcache[3:0]
+@1401200
+-group_end
+@28
+[color] 2
+axlite2wbsp.i_axi_awprot[2:0]
+@200
+-
+@28
+[color] 2
+axlite2wbsp.i_axi_wvalid
+[color] 2
+axlite2wbsp.o_axi_wready
+@22
+[color] 2
+axlite2wbsp.i_axi_wdata[31:0]
+[color] 2
+axlite2wbsp.i_axi_wstrb[3:0]
+@28
+[color] 2
+axlite2wbsp.AXI_WR.axi_write_decoder.err_state
+@200
+-
+@28
+[color] 3
+axlite2wbsp.o_axi_bvalid
+[color] 3
+axlite2wbsp.i_axi_bready
+[color] 3
+axlite2wbsp.o_axi_bresp[1:0]
+@200
+-
+@28
+axlite2wbsp.i_axi_arvalid
+axlite2wbsp.o_axi_arready
+@22
+axlite2wbsp.i_axi_araddr[27:0]
+axlite2wbsp.i_axi_arcache[3:0]
+@28
+axlite2wbsp.i_axi_arprot[2:0]
+@200
+-
+@28
+[color] 2
+axlite2wbsp.o_axi_rvalid
+[color] 2
+axlite2wbsp.i_axi_rready
+@22
+[color] 2
+axlite2wbsp.o_axi_rdata[31:0]
+@28
+[color] 2
+axlite2wbsp.o_axi_rresp[1:0]
+[color] 2
+axlite2wbsp.AXI_RD.axi_read_decoder.err_state
+@200
+-
+@28
+axlite2wbsp.o_wb_cyc
+axlite2wbsp.o_wb_stb
+axlite2wbsp.o_wb_we
+@22
+axlite2wbsp.o_wb_addr[25:0]
+axlite2wbsp.o_wb_data[31:0]
+axlite2wbsp.o_wb_sel[3:0]
+@28
+[color] 2
+axlite2wbsp.i_wb_stall
+[color] 2
+axlite2wbsp.i_wb_ack
+@22
+[color] 2
+axlite2wbsp.i_wb_data[31:0]
+@28
+[color] 2
+axlite2wbsp.i_wb_err
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axlite2wbsp.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axlite2wbsp.sby
new file mode 100644
index 0000000..5e517a6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/axlite2wbsp.sby
@@ -0,0 +1,31 @@
+[tasks]
+cvr
+prf
+
+[options]
+prf: mode prove
+prf: depth 5
+cvr: mode cover
+cvr: depth 40
+
+[engines]
+smtbmc
+
+[script]
+read -formal -D AXLITE2WBSP axlite2wbsp.v
+read -formal -D AXLITE2WBSP axilrd2wbsp.v
+read -formal -D AXLITE2WBSP axilwr2wbsp.v
+read -formal -D AXLITE2WBSP wbarbiter.v
+read -formal -D AXLITE2WBSP faxil_slave.v
+read -formal -D AXLITE2WBSP fwb_master.v
+read -formal -D AXLITE2WBSP fwb_slave.v
+prep -top axlite2wbsp
+
+[files]
+../../rtl/axlite2wbsp.v
+../../rtl/axilrd2wbsp.v
+../../rtl/axilwr2wbsp.v
+../../rtl/wbarbiter.v
+faxil_slave.v
+fwb_master.v
+fwb_slave.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/demoaxi.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/demoaxi.gtkw
new file mode 100644
index 0000000..d835c15
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/demoaxi.gtkw
@@ -0,0 +1,70 @@
+[*]
+[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
+[*] Wed Dec 26 15:57:11 2018
+[*]
+[dumpfile] "(null)"
+[dumpfile_mtime] "Wed Dec 26 15:51:31 2018"
+[dumpfile_size] 26484
+[timestart] 0
+[size] 1600 600
+[pos] -1 -1
+*-6.254814 180 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 270
+[signals_width] 200
+[sst_expanded] 1
+[sst_vpaned_height] 143
+@29
+[color] 3
+demoaxi.S_AXI_ARESETN
+[color] 3
+demoaxi.S_AXI_ACLK
+@200
+-
+@28
+demoaxi.S_AXI_AWVALID
+demoaxi.S_AXI_AWREADY
+@22
+demoaxi.S_AXI_AWADDR[7:0]
+@28
+demoaxi.S_AXI_AWPROT[2:0]
+@200
+-
+@28
+demoaxi.S_AXI_WVALID
+demoaxi.S_AXI_WREADY
+@22
+demoaxi.S_AXI_WDATA[31:0]
+demoaxi.S_AXI_WSTRB[3:0]
+@200
+-
+@28
+[color] 2
+demoaxi.S_AXI_BVALID
+[color] 2
+demoaxi.S_AXI_BREADY
+[color] 2
+demoaxi.S_AXI_BRESP[1:0]
+@200
+-
+@28
+demoaxi.S_AXI_ARVALID
+demoaxi.S_AXI_ARREADY
+@22
+demoaxi.S_AXI_ARADDR[7:0]
+@28
+demoaxi.S_AXI_ARPROT[2:0]
+@200
+-
+@28
+[color] 2
+demoaxi.S_AXI_RVALID
+[color] 2
+demoaxi.S_AXI_RREADY
+@22
+[color] 2
+demoaxi.S_AXI_RDATA[31:0]
+@28
+[color] 2
+demoaxi.S_AXI_RRESP[1:0]
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/demoaxi.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/demoaxi.sby
new file mode 100644
index 0000000..8537eb1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/demoaxi.sby
@@ -0,0 +1,21 @@
+[tasks]
+prf
+cvr
+
+[options]
+prf: mode prove
+prf: depth 26
+cvr: mode cover
+cvr: depth 40
+
+[engines]
+smtbmc
+
+[script]
+read -formal demoaxi.v
+read -formal faxil_slave.v
+prep -top demoaxi
+
+[files]
+../../rtl/demoaxi.v
+faxil_slave.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/easyaxil.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/easyaxil.gtkw
new file mode 100644
index 0000000..9216e46
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/easyaxil.gtkw
@@ -0,0 +1,82 @@
+[*]
+[*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI
+[*] Thu Mar  5 18:47:26 2020
+[*]
+[dumpfile_mtime] "Thu Mar  5 18:41:39 2020"
+[dumpfile_size] 18650
+[timestart] 0
+[size] 1920 1021
+[pos] -919 -1
+*-5.333901 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 270
+[signals_width] 200
+[sst_expanded] 1
+[sst_vpaned_height] 287
+@28
+easyaxil.S_AXI_ACLK
+easyaxil.S_AXI_ARESETN
+@200
+-
+@28
+[color] 3
+easyaxil.S_AXI_AWVALID
+[color] 2
+easyaxil.S_AXI_AWREADY
+@22
+[color] 3
+easyaxil.S_AXI_AWADDR[3:0]
+[color] 3
+easyaxil.S_AXI_AWPROT[3:0]
+@200
+-
+@28
+[color] 3
+easyaxil.S_AXI_WVALID
+[color] 2
+easyaxil.S_AXI_WREADY
+@22
+[color] 3
+easyaxil.S_AXI_WDATA[31:0]
+[color] 3
+easyaxil.S_AXI_WSTRB[3:0]
+@200
+-
+@28
+[color] 2
+easyaxil.S_AXI_BVALID
+[color] 3
+easyaxil.S_AXI_BREADY
+[color] 2
+easyaxil.S_AXI_BRESP[1:0]
+@200
+-
+@28
+[color] 3
+easyaxil.S_AXI_ARVALID
+[color] 2
+easyaxil.S_AXI_ARREADY
+@22
+[color] 3
+easyaxil.S_AXI_ARADDR[3:0]
+[color] 3
+easyaxil.S_AXI_ARPROT[3:0]
+@200
+-
+@28
+[color] 2
+easyaxil.S_AXI_RVALID
+[color] 3
+easyaxil.S_AXI_RREADY
+@22
+[color] 2
+easyaxil.S_AXI_RDATA[31:0]
+@28
+[color] 2
+easyaxil.S_AXI_RRESP[1:0]
+@201
+-
+@28
+easyaxil.axil_read_ready
+easyaxil.axil_write_ready
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/easyaxil.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/easyaxil.sby
new file mode 100644
index 0000000..2f7dc4d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/easyaxil.sby
@@ -0,0 +1,33 @@
+[tasks]
+prfreg prf
+cvrreg cvr
+prfskd prf opt_skidbuffer
+cvrskd cvr opt_skidbuffer
+prfreglp prf                opt_lowpower
+prfskdlp prf opt_skidbuffer opt_lowpower
+
+[options]
+prf: mode prove
+prf: depth 3
+cvr: mode cover
+cvr: depth 40
+
+[engines]
+smtbmc
+
+[script]
+read -formal easyaxil.v
+opt_skidbuffer: read -formal skidbuffer.v
+read -formal faxil_slave.v
+--pycode-begin--
+cmd = "hierarchy -top easyaxil"
+cmd += " -chparam OPT_SKIDBUFFER %d" % (1 if "opt_skidbuffer" in tags else 0)
+cmd += " -chparam OPT_LOWPOWER %d" % (1 if "opt_lowpower" in tags else 0)
+output(cmd);
+--pycode-end--
+prep -top easyaxil
+
+[files]
+../../rtl/easyaxil.v
+opt_skidbuffer: ../../rtl/skidbuffer.v
+faxil_slave.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/f_order.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/f_order.v
new file mode 100644
index 0000000..ebb6ad6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/f_order.v
@@ -0,0 +1,104 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	f_order.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2015-2016, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+//
+`default_nettype	none
+//
+//
+module	f_order(i_clk, i_reset, i_head, i_neck, i_torso, i_tail);
+	parameter	LGFIFO = 8;
+	//
+	input	wire	i_clk, i_reset;
+	//
+	input	wire	[(LGFIFO-1):0]	i_head, i_neck, i_torso, i_tail;
+
+
+	reg	f_past_valid;
+
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+
+	always @(posedge i_clk)
+	if ((f_past_valid)&&($past(i_reset)))
+	begin
+		assert(i_head  == 0);
+		assert(i_neck  == 0);
+		assert(i_torso == 0);
+		assert(i_tail  == 0);
+	end
+
+	always @(posedge i_clk)
+	if (f_past_valid)
+	begin
+		if (i_head == i_tail)
+		begin
+			assert(i_neck  == i_head);
+			assert(i_torso == i_head);
+		end else if (i_head > i_tail)
+		begin
+			assert((i_neck  <= i_head)&&(i_neck >= i_tail));
+			assert((i_torso <= i_head)&&(i_torso >= i_tail));
+			assert(i_neck >= i_torso);
+		end else if (i_head < i_tail)
+		begin
+			assert((i_neck  <= i_head)||(i_neck  >= i_tail));
+			assert((i_torso <= i_head)||(i_torso >= i_tail));
+
+			if (i_neck < i_head)
+				assert((i_torso<= i_neck)||(i_torso >= i_tail));
+			else if (i_neck >= i_tail)
+				assert(i_torso <= i_neck);
+		end
+	end
+
+	wire	[(LGFIFO-1):0]	f_next_head, f_next_neck,
+				f_next_torso, f_next_tail;
+	assign	f_next_head  = i_head + 1'b1;
+	assign	f_next_neck  = i_neck + 1'b1;
+	assign	f_next_torso = i_torso + 1'b1;
+	assign	f_next_tail  = i_tail + 1'b1;
+
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_reset)))
+	begin
+		if ($past(f_next_head) == $past(i_tail))
+			assert(i_head != f_next_head);
+		assert((i_head== $past(i_head))||(i_head== $past(f_next_head)));
+		assert((i_neck== $past(i_neck))||(i_neck== $past(f_next_neck)));
+		assert((i_torso==$past(i_torso))
+			||(i_torso== $past(f_next_torso)));
+		assert((i_tail== $past(i_tail))||(i_tail== $past(f_next_tail)));
+	end
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fapb_master.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fapb_master.v
new file mode 100644
index 0000000..2d7cc5b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fapb_master.v
@@ -0,0 +1,179 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	fapb_master.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Formal properties to describe a slave of the APB bus.  These
+//		have been built based upon the AMBA 3 specification, dated
+//	2003 and labeled as ARM IHI 0024B.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// }}}
+module	fapb_master #(
+		// {{{
+		parameter	AW =32,	// Address width
+				DW = 32, // Data width
+		parameter F_OPT_MAXSTALL = 4,
+		// Set F_OPT_SLVERR to 1 if your slave supports PSLVERR
+		// assertion, otherwise we'll assert it remains false.
+		parameter [0:0] F_OPT_SLVERR = 1'b1
+		// }}}
+	) (
+		// {{{
+		input	wire			PCLK, PRESETn,
+		input	wire			PSEL,
+		input	wire			PENABLE,
+		input	wire			PREADY,	// From the slave
+		input	wire	[AW-1:0]	PADDR,
+		input	wire			PWRITE,
+		input	wire	[DW-1:0]	PWDATA,
+		input	wire	[DW/8-1:0]	PWSTRB,
+		input	wire	[2:0]		PPROT,
+		input	wire	[DW-1:0]	PRDATA, // Following from slave
+		input	wire			PSLVERR
+		// }}}
+	);
+
+`define	SLAVE_ASSUME	assert
+`define	SLAVE_ASSERT	assume
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Reset
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	f_past_valid;
+	initial	f_past_valid = 1'b0;
+	always @(posedge PCLK)
+		f_past_valid <= 1'b1;
+
+	always @(posedge PCLK)
+	if (!f_past_valid)
+		`SLAVE_ASSUME(!PRESETn);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	//
+
+	//
+	// PSEL
+	// {{{
+	always @(posedge PCLK)
+	if (!f_past_valid || !$past(PRESETn))
+		`SLAVE_ASSUME(!PSEL);
+	else if ($past(PSEL) && !$past(PENABLE && PREADY))
+		`SLAVE_ASSUME(PSEL);
+	// }}}
+
+	//
+	// PENABLE
+	// {{{
+	always @(posedge PCLK)
+	if (!f_past_valid || !$past(PRESETn))
+		`SLAVE_ASSUME(!PENABLE);
+	else if (PSEL)
+	begin
+		if (!$past(PSEL))
+			// PSEL rose, this is therefore the setup phase and
+			// so PENABLE is must be false
+			`SLAVE_ASSUME(!PENABLE);
+		else if ($past(PENABLE))
+			// Last cycle was an access phase.  PENABLE can only
+			// stay high if the slave wasn't ready
+			//
+			// PENABLE holds if we were stalled, otherwise
+			// it needs to fall to start a new transaction
+			`SLAVE_ASSUME(PENABLE == !$past(PREADY));
+		else
+			// The last cycle was the setup phase, so we must
+			// now be in the access phase.  In the access phase,
+			// PENABLE should always be high
+			`SLAVE_ASSUME(PENABLE);
+	end // else if !PSEL -- the master might be talking to a different
+		// slave, and so we don't care about PENABLE
+	// }}}
+
+
+	// PADDR, PWRITE, and PWDATA need to hold while stalled
+	// {{{
+	always @(posedge PCLK)
+	if ((!f_past_valid)||(!$past(PRESETn)))
+	begin
+		`SLAVE_ASSERT(!PREADY);
+	end else if ($past(PSEL) && (!$past(PENABLE) || !$past(PREADY)))
+	begin
+		// Stall condition.  Nothing is allowed to change
+		`SLAVE_ASSUME($stable(PADDR));
+		`SLAVE_ASSUME($stable(PWRITE));
+		`SLAVE_ASSUME($stable(PPROT));
+		if (PWRITE)
+		begin
+			`SLAVE_ASSUME($stable(PWDATA));
+			`SLAVE_ASSUME($stable(PWSTRB));
+		end
+	end
+	// }}}
+
+	//
+	// PREADY, and maximum stall check
+	// {{{
+	//	Can take on any value when PSEL is low
+	//	Can take on any value when PENABLE is low
+	//	If PSEL and PENABLE, can only stall F_OPT_MAXSTALL cycles before
+	//	  raising PREADY
+	generate if (F_OPT_MAXSTALL > 0)
+	begin : MAX_STALL_CHECK
+
+		reg	[$clog2(F_OPT_MAXSTALL+1)-1:0]	f_stall_count;
+
+		initial	f_stall_count = 0;
+		always @(posedge PCLK)
+		if (!PRESETn || !PSEL || !PENABLE)
+			f_stall_count <= 0;
+		else if (!PREADY)
+			f_stall_count <= f_stall_count + 1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_stall_count < F_OPT_MAXSTALL);
+	end endgenerate
+	// }}}
+
+	// PSLVERR
+	// {{{
+	// "Recommended" that PSLVERR be low when any of PSEL, PENABLE, or
+	// PREADY are low
+	// Can't generate a slave error when not ready
+	always @(*)
+	if (!PSEL || !PENABLE || !PREADY || !F_OPT_SLVERR)
+		`SLAVE_ASSERT(!PSLVERR);
+	// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fapb_slave.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fapb_slave.v
new file mode 100644
index 0000000..ecd5b0f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fapb_slave.v
@@ -0,0 +1,179 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	fapb_slave.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Formal properties to describe a slave of the APB bus.  These
+//		have been built based upon the AMBA 3 specification, dated
+//	2003 and labeled as ARM IHI 0024B.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// }}}
+module	fapb_slave #(
+		// {{{
+		parameter	AW =32,	// Address width
+				DW = 32, // Data width
+		parameter F_OPT_MAXSTALL = 4,
+		// Set F_OPT_SLVERR to 1 if your slave supports PSLVERR
+		// assertion, otherwise we'll assert it remains false.
+		parameter [0:0] F_OPT_SLVERR = 1'b0
+		// }}}
+	) (
+		// {{{
+		input	wire			PCLK, PRESETn,
+		input	wire			PSEL,
+		input	wire			PENABLE,
+		input	wire			PREADY,	// From the slave
+		input	wire	[AW-1:0]	PADDR,
+		input	wire			PWRITE,
+		input	wire	[DW-1:0]	PWDATA,
+		input	wire	[DW/8-1:0]	PWSTRB,
+		input	wire	[2:0]		PPROT,
+		input	wire	[DW-1:0]	PRDATA, // Following from slave
+		input	wire			PSLVERR
+		// }}}
+	);
+
+`define	SLAVE_ASSUME	assume
+`define	SLAVE_ASSERT	assert
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Reset
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	f_past_valid;
+	initial	f_past_valid = 1'b0;
+	always @(posedge PCLK)
+		f_past_valid <= 1'b1;
+
+	always @(posedge PCLK)
+	if (!f_past_valid)
+		`SLAVE_ASSUME(!PRESETn);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	//
+
+	//
+	// PSEL
+	// {{{
+	always @(posedge PCLK)
+	if (!f_past_valid || !$past(PRESETn))
+		`SLAVE_ASSUME(!PSEL);
+	else if ($past(PSEL) && !$past(PENABLE && PREADY))
+		`SLAVE_ASSUME(PSEL);
+	// }}}
+
+	//
+	// PENABLE
+	// {{{
+	always @(posedge PCLK)
+	if (!f_past_valid || !$past(PRESETn))
+		`SLAVE_ASSUME(!PENABLE);
+	else if (PSEL)
+	begin
+		if (!$past(PSEL))
+			// PSEL rose, this is therefore the setup phase and
+			// so PENABLE is must be false
+			`SLAVE_ASSUME(!PENABLE);
+		else if ($past(PENABLE))
+			// Last cycle was an access phase.  PENABLE can only
+			// stay high if the slave wasn't ready
+			//
+			// PENABLE holds if we were stalled, otherwise
+			// it needs to fall to start a new transaction
+			`SLAVE_ASSUME(PENABLE == !$past(PREADY));
+		else
+			// The last cycle was the setup phase, so we must
+			// now be in the access phase.  In the access phase,
+			// PENABLE should always be high
+			`SLAVE_ASSUME(PENABLE);
+	end // else if !PSEL -- the master might be talking to a different
+		// slave, and so we don't care about PENABLE
+	// }}}
+
+
+	// PADDR, PWRITE, and PWDATA need to hold while stalled
+	// {{{
+	always @(posedge PCLK)
+	if ((!f_past_valid)||(!$past(PRESETn)))
+	begin
+		`SLAVE_ASSERT(!PREADY);
+	end else if ($past(PSEL) && (!$past(PENABLE) || !$past(PREADY)))
+	begin
+		// Stall condition.  Nothing is allowed to change
+		`SLAVE_ASSUME($stable(PADDR));
+		`SLAVE_ASSUME($stable(PWRITE));
+		`SLAVE_ASSUME($stable(PPROT));
+		if (PWRITE)
+		begin
+			`SLAVE_ASSUME($stable(PWDATA));
+			`SLAVE_ASSUME($stable(PWSTRB));
+		end
+	end
+	// }}}
+
+	//
+	// PREADY, and maximum stall check
+	// {{{
+	//	Can take on any value when PSEL is low
+	//	Can take on any value when PENABLE is low
+	//	If PSEL and PENABLE, can only stall F_OPT_MAXSTALL cycles before
+	//	  raising PREADY
+	generate if (F_OPT_MAXSTALL > 0)
+	begin : MAX_STALL_CHECK
+
+		reg	[$clog2(F_OPT_MAXSTALL+1)-1:0]	f_stall_count;
+
+		initial	f_stall_count = 0;
+		always @(posedge PCLK)
+		if (!PRESETn || !PSEL || !PENABLE)
+			f_stall_count <= 0;
+		else if (!PREADY)
+			f_stall_count <= f_stall_count + 1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_stall_count < F_OPT_MAXSTALL);
+	end endgenerate
+	// }}}
+
+	// PSLVERR
+	// {{{
+	// "Recommended" that PSLVERR be low when any of PSEL, PENABLE, or
+	// PREADY are low
+	// Can't generate a slave error when not ready
+	always @(*)
+	if (!PSEL || !PENABLE || !PREADY || !F_OPT_SLVERR)
+		`SLAVE_ASSERT(!PSLVERR);
+	// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fav_slave.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fav_slave.v
new file mode 100644
index 0000000..bdf47d2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fav_slave.v
@@ -0,0 +1,332 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	fav_slave.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Formal properties of an Avalon slave.  These are the properties
+//		the module owning the slave should use: they assume inputs from
+//	the bus master, and assert that the outputs from the slave are valid.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2015-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module	fav_slave(i_clk, i_reset,
+		i_av_read,
+		i_av_write,
+		i_av_address,
+		i_av_writedata,
+			i_av_byteenable,
+		i_av_lock,
+		i_av_waitrequest,	// = wb_stall
+		//
+		i_av_writeresponsevalid,
+		//
+		i_av_readdatavalid,
+		i_av_readdata,
+		i_av_response,	// Error response = 2'b11
+		f_rd_nreqs, f_rd_nacks, f_rd_outstanding,
+		f_wr_nreqs, f_wr_nacks, f_wr_outstanding);
+	parameter	DW=32, AW=14;
+	parameter	F_LGDEPTH=6;
+	parameter	[(F_LGDEPTH-1):0]	F_MAX_REQUESTS = 62;
+	input	wire			i_clk, i_reset;
+	input	wire			i_av_read;
+	input	wire			i_av_write;
+	input	wire	[(AW-1):0]	i_av_address;
+	input	wire	[(DW-1):0]	i_av_writedata;
+	input	wire	[(DW/8-1):0]	i_av_byteenable;
+	input	wire			i_av_lock;
+	//
+	input	wire			i_av_waitrequest;
+	input	wire			i_av_writeresponsevalid;
+	input	wire			i_av_readdatavalid;
+	input	wire	[(DW-1):0]	i_av_readdata;
+	input	wire	[1:0]		i_av_response;
+	//
+	output	reg	[(F_LGDEPTH-1):0] f_rd_nreqs, f_rd_nacks;
+	output	wire	[(F_LGDEPTH-1):0] f_rd_outstanding;
+	output	reg	[(F_LGDEPTH-1):0] f_wr_nreqs, f_wr_nacks;
+	output	wire	[(F_LGDEPTH-1):0] f_wr_outstanding;
+
+	assert	property(F_MAX_REQUESTS < {(F_LGDEPTH){1'b1}});
+
+
+
+	reg	f_past_valid;
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+	always @(*)
+		assert((f_past_valid) || (i_reset));
+
+	wire	[AW+(DW/8):0]	f_rd_request;
+	assign	f_rd_request = { i_av_read,  i_av_byteenable, i_av_address };
+
+	wire	[(AW+DW+(DW/8)):0]	f_wr_request;
+	assign	f_wr_request = { i_av_write, i_av_address, i_av_writedata,
+					i_av_byteenable };
+
+	/////////////////////////////
+	//
+	// Require that nothing changes, save on a clock tick.
+	//
+	// This is only required if yosys is using the clk2fflogic
+	// command, a command only required if multiple clocks are
+	// in use.  Since this can greatly slow down formal proofs,
+	// we limit any code associated with this option to only
+	// those times the option is in play.
+	//
+	/////////////////////////////
+
+	generate if (F_OPT_CLK2FFLOGIC)
+	begin
+		always @($global_clock)
+		if ((f_past_valid)&&(!$rose(i_clk)))
+		begin
+			assume($stable(f_rd_request));
+			assume($stable(f_wr_request));
+			assume($stable(i_av_lock));
+
+			assert($stable(i_av_readdatavalid));
+			assert($stable(i_av_writeresponsevalid));
+			assert($stable(i_av_readdata));
+			assert($stable(i_av_response));
+		end
+	end endgenerate
+
+	/////////////////////////////
+	//
+	// Assumptions about a slave's inputs
+	//
+	/////////////////////////////
+
+
+	initial	assume(!i_av_read);
+	initial	assume(!i_av_write);
+	initial	assume(!i_av_lock);
+	//
+	initial	assert(!i_av_readdatavalid);
+	initial	assert(!i_av_writeresponsevalid);
+	//
+
+	always @(posedge i_clk)
+		if (i_reset)
+		begin
+			assume(!i_av_read);
+			assume(!i_av_write);
+			assume(!i_av_lock);
+		end
+
+	always @(*)
+		if (i_av_write)
+			assume(|i_av_byteenable);
+
+	// It is a protocol violation to issue both read and write requests
+	// on the same clock
+	always @(*)
+		assume((!i_av_read)||(!i_av_write));
+
+	// Once a read request has been placed upon the bus, it will remain
+	// there until wait request goes low
+	always @(posedge i_clk)
+	if ((f_past_valid)&&($past(i_av_waitrequest))&&($past(i_av_read)))
+		assume((i_reset)||(f_rd_request == $past(f_rd_request)));
+
+	// Same thing for a write request
+	always @(posedge i_clk)
+	if ((f_past_valid)&&($past(i_av_waitrequest))&&($past(i_av_write)))
+		assume((i_reset)||(f_wr_request == $past(f_wr_request)));
+
+	// A lock request can only be asserted at the same time a read or
+	// write request is being made.
+	always @(posedge i_clk)
+		if ((f_past_valid)&&(!$past(i_av_lock)))
+			assume((!i_av_lock)||(i_av_read)||(i_av_write));
+
+	// A lock request can only be de-asserted following the last read
+	// or write request made with it asserted
+	always @(posedge i_clk)
+		if ((f_past_valid)&&($past(i_av_lock)
+				&&(!i_av_read)&&(!i_av_write)))
+			assume((i_reset)||(i_av_lock)
+				||(i_av_read)||(i_av_write));
+
+
+	/////////////////////////////
+	//
+	// Internal state variables
+	//
+	/////////////////////////////
+
+	// Count the number of read requests
+	initial	f_rd_nreqs = 0;
+	always @(posedge i_clk)
+		if (i_reset)
+			f_rd_nreqs <= 0;
+		else if ((i_av_read)&&(!i_av_waitrequest))
+			f_rd_nreqs <= f_rd_nreqs + 1'b1;
+
+	// Count the number of read acknowledgements
+	initial	f_rd_nacks = 0;
+	always @(posedge i_clk)
+		if (i_reset)
+			f_rd_nacks <= 0;
+		else if (i_av_readdatavalid)
+			f_rd_nacks <= f_rd_nacks + 1'b1;
+
+	// The difference between read requests and acknowledgements is
+	// the number of outstanding read requests
+	assign	f_rd_outstanding = (i_reset) ? 0 : (f_rd_nreqs - f_rd_nacks);
+
+	// Count the number of write requests
+	initial	f_wr_nreqs = 0;
+	always @(posedge i_clk)
+		if (i_reset)
+			f_wr_nreqs <= 0;
+		else if ((i_av_write)&&(!i_av_waitrequest))
+			f_wr_nreqs <= f_wr_nreqs + 1'b1;
+
+	// Count the number of write acknowledgements/responses
+	initial	f_wr_nacks = 0;
+	always @(posedge i_clk)
+		if (i_reset)
+			f_wr_nacks <= 0;
+		else if (i_av_writeresponsevalid)
+			f_wr_nacks <= f_wr_nacks + 1'b1;
+
+	assign	f_wr_outstanding = f_wr_nreqs - f_wr_nacks;
+
+
+	initial	assume(!i_av_read);
+	initial	assume(!i_av_write);
+	initial	assume(!i_av_lock);
+	//
+	initial	assert(!i_av_readdatavalid);
+	initial	assert(!i_av_writeresponsevalid);
+	//
+
+	always @(posedge i_clk)
+		if (i_reset)
+		begin
+			assume(!i_av_read);
+			assume(!i_av_write);
+		end
+
+	always @(posedge i_clk)
+		if ((f_past_valid)&&($past(i_reset)))
+		begin
+			assert(!i_av_readdatavalid);
+			assert(!i_av_writeresponsevalid);
+			assert(f_rd_nreqs == 0);
+			assert(f_rd_nacks == 0);
+			assert(f_wr_nreqs == 0);
+			assert(f_wr_nacks == 0);
+		end
+
+	// Just like a read and write request cannot both be made at the same
+	// time, neither can both responses come back at the same time
+	always @(*)
+		assert((!i_av_writeresponsevalid)||(!i_av_readdatavalid));
+
+	// If nothing is outstanding, then there should be no responses.
+	// If i_reset is asserted, a response may have been registered, and
+	// so may still return on this clock.
+	always @(posedge i_clk)
+		if ((f_rd_outstanding == 0)&&(!i_reset)
+				&&((!i_av_read)||(i_av_waitrequest)))
+			assert(!i_av_readdatavalid);
+
+	always @(posedge i_clk)
+		if ((f_wr_outstanding == 0)&&(!i_reset)
+				&&((!i_av_write)||(i_av_waitrequest)))
+			assert(!i_av_writeresponsevalid);
+
+	always @(*)
+		assert({1'b0, f_wr_outstanding} + { 1'b0, f_rd_outstanding }
+			< F_MAX_REQUESTS);
+
+	generate if (F_OPT_MAX_STALL > 0)
+	begin
+		reg	[(LGWAIT-1):0]	stall_count;
+
+		initial	stall_count = 0;
+		always @(posedge i_clk)
+			if (i_reset)
+				stall_count <= 0;
+			else if (((i_av_read)||(i_av_write))&&(i_av_waitrequest))
+				stall_count <= stall_count + 1'b1;
+			else
+				stall_count <= 0;
+
+		always @(*)
+			assert((i_reset)||(stall_count < F_OPT_MAX_STALL));
+	end endgenerate
+
+	generate if (F_OPT_MAX_WAIT > 0)
+	begin
+		reg	[(LGWAIT-1):0]	read_wait, write_wait;
+
+		//
+		// Insist on a minimum amount of time to wait for a *read*
+		// response.
+		//
+		always @(posedge i_clk)
+			if (i_reset)
+				read_wait <= 0;
+			else if ((i_av_readdatavalid)
+					||((i_av_read)&&(!i_av_waitrequest)))
+				read_wait <= 0;
+			else if (f_rd_outstanding > 0)
+				read_wait <= read_wait + 1'b1;
+
+		always @(*)
+			assert((i_av_readdatavalid)
+				||(f_rd_outstanding == 0)
+				||(read_wait < F_OPT_MAX_WAIT));
+
+
+		//
+		// Insist on a minimum amount of time to wait for a *write*
+		// response.
+		//
+		always @(posedge i_clk)
+			if (i_reset)
+				write_wait <= 0;
+			else if ((i_av_writeresponsevalid)
+					||((i_av_write)&&(!i_av_waitrequest)))
+				write_wait <= 0;
+			else if (f_wr_outstanding > 0)
+				write_wait <= write_wait + 1'b1;
+
+		always @(*)
+			assert((i_av_writeresponsevalid)
+				||(f_wr_outstanding == 0)
+				||(write_wait < F_OPT_MAX_WAIT));
+	end endgenerate
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxi_addr.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxi_addr.v
new file mode 100644
index 0000000..0d95a51
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxi_addr.v
@@ -0,0 +1,140 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	faxi_addr.v
+//
+// Project:	Pipelined Wishbone to AXI converter
+//
+// Purpose:	The AXI (full) standard has some rather complicated addressing
+//		modes, where the address can either be FIXED, INCRementing, or
+//	even where it can WRAP around some boundary.  When in either INCR or
+//	WRAP modes, the next address must always be aligned.  In WRAP mode,
+//	the next address calculation needs to wrap around a given value, and
+//	that value is dependent upon the burst size (i.e. bytes per beat) and
+//	length (total numbers of beats).  Since this calculation can be
+//	non-trivial, and since it needs to be done multiple times, the logic
+//	below captures it for every time it might be needed.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This program is free software (firmware): you can redistribute it and/or
+// modify it under the terms of  the GNU General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or (at
+// your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program.  (It's in the $(ROOT)/doc directory, run make with no
+// target there if the PDF file isn't present.)  If not, see
+// <http://www.gnu.org/licenses/> for a copy.
+//
+// License:	GPL, v3, as defined and found on www.gnu.org,
+//		http://www.gnu.org/licenses/gpl.html
+//
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+//
+module	faxi_addr(i_last_addr,
+		i_size,
+		i_burst,
+		i_len,
+		o_incr,
+		o_next_addr);
+	parameter	AW=32;
+	input	wire	[AW-1:0]	i_last_addr;
+	input	wire	[2:0]		i_size; // 1b, 2b, 4b, 8b, etc
+	input	wire	[1:0]		i_burst; // fixed, incr, wrap, reserved
+	input	wire	[7:0]		i_len;
+	output	reg	[7:0]		o_incr;
+	output	reg	[AW-1:0]	o_next_addr;
+
+	(* keep *) reg	[AW-1:0]	wrap_mask, increment;
+
+	always @(*)
+	begin
+		increment = 0;
+		if (i_burst != 0)
+		begin
+			// verilator lint_off WIDTH
+			case(i_size)
+			0: increment =  1;
+			1: increment =  2;
+			2: increment =  4;
+			3: increment =  8;
+			4: increment = 16;
+			5: increment = 32;
+			6: increment = 64;
+			7: increment = 128;
+			default: increment = 0;
+			endcase
+			// verilator lint_on WIDTH
+		end
+	end
+
+	always @(*)
+	begin
+		wrap_mask = 0;
+		if (i_burst == 2'b10)
+		begin
+			if (i_len == 1)
+				wrap_mask = (1<<(i_size+1));
+			else if (i_len == 3)
+				wrap_mask = (1<<(i_size+2));
+			else if (i_len == 7)
+				wrap_mask = (1<<(i_size+3));
+			else if (i_len == 15)
+				wrap_mask = (1<<(i_size+4));
+			wrap_mask = wrap_mask - 1;
+		end
+	end
+
+	always @(*)
+	begin
+		o_next_addr = i_last_addr + increment;
+		if (i_burst != 2'b00)
+		begin
+			// Align any subsequent address
+			// verilator lint_off SELRANGE
+			if(i_size == 1)
+				o_next_addr[0] = 0;
+			else if ((i_size == 2)&&(AW>=2))
+				o_next_addr[1:0] = 0;
+			else if ((i_size == 3)&&(AW>=3))
+				o_next_addr[2:0] = 0;
+			else if ((i_size == 4)&&(AW>=4))
+				o_next_addr[3:0] = 0;
+			else if ((i_size == 5)&&(AW>=5))
+				o_next_addr[4:0] = 0;
+			else if ((i_size == 6)&&(AW>=6))
+				o_next_addr[((AW>6)?5:AW-1):0] = 0;
+			else if ((i_size == 7)&&(AW>=7))
+				o_next_addr[((AW>7)?6:AW-1):0] = 0;
+			// verilator lint_on  SELRANGE
+		end
+		if (i_burst == 2'b10)
+		begin
+			// WRAP!
+			o_next_addr[AW-1:0] = (i_last_addr & ~wrap_mask)
+					| (o_next_addr & wrap_mask);;
+		end
+	end
+
+	always @(*)
+	begin
+		o_incr = 0;
+		o_incr[((AW>7)?7:AW-1):0] = increment[((AW>7)?7:AW-1):0];
+	end
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxi_master.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxi_master.v
new file mode 100644
index 0000000..6112631
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxi_master.v
@@ -0,0 +1,971 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	faxi_master.v (Formal properties of an AXI4 (full) master)
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	This file contains a subset of the formal properties which I've
+//		used to formally verify that a core truly follows the full
+//	AXI4 specification.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2017-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module faxi_master #(
+	parameter C_AXI_ID_WIDTH	= 3, // The AXI id width used for R&W
+                                             // This is an int between 1-16
+	parameter C_AXI_DATA_WIDTH	= 128,// Width of the AXI R&W data
+	parameter C_AXI_ADDR_WIDTH	= 28,	// AXI Address width (log wordsize)
+	parameter [7:0] OPT_MAXBURST	= 8'hff,// Maximum burst length, minus 1
+	parameter [0:0] OPT_EXCLUSIVE	= 1,// Exclusive access allowed
+	parameter [0:0] OPT_NARROW_BURST = 1,// Narrow bursts allowed by default
+	// F_OPT_ASSUME_RESET, if set, will cause the design to *assume* the
+	// existence of a correct reset, rather than asserting it.  It is
+	// appropriate anytime the reset logic is outside of the circuit being
+	// examined
+	parameter [0:0]			F_OPT_ASSUME_RESET = 1'b1,
+	parameter [0:0]			F_OPT_NO_RESET = 1'b1,
+	// F_LGDEPTH is the number of bits necessary to count the maximum
+	// number of items in flight.
+	parameter				F_LGDEPTH      = 10,
+	parameter	[(F_LGDEPTH-1):0]	F_AXI_MAXSTALL = 3,
+	parameter	[(F_LGDEPTH-1):0]	F_AXI_MAXRSTALL= 3,
+	parameter	[(F_LGDEPTH-1):0]	F_AXI_MAXDELAY = 3,
+	localparam			F_OPT_BURSTS    = (OPT_MAXBURST != 0),
+	//
+	localparam IW			= C_AXI_ID_WIDTH,
+	localparam DW			= C_AXI_DATA_WIDTH,
+	localparam AW			= C_AXI_ADDR_WIDTH
+	) (
+	input	wire			i_clk,	// System clock
+	input	wire			i_axi_reset_n,
+
+// AXI write address channel signals
+	input	wire			i_axi_awready,//Slave is ready to accept
+	input	wire	[C_AXI_ID_WIDTH-1:0]	i_axi_awid,	// Write ID
+	input	wire	[AW-1:0]	i_axi_awaddr,	// Write address
+	input	wire	[7:0]		i_axi_awlen,	// Write Burst Length
+	input	wire	[2:0]		i_axi_awsize,	// Write Burst size
+	input	wire	[1:0]		i_axi_awburst,	// Write Burst type
+	input	wire	[0:0]		i_axi_awlock,	// Write lock type
+	input	wire	[3:0]		i_axi_awcache,	// Write Cache type
+	input	wire	[2:0]		i_axi_awprot,	// Write Protection type
+	input	wire	[3:0]		i_axi_awqos,	// Write Quality of Svc
+	input	wire			i_axi_awvalid,	// Write address valid
+
+// AXI write data channel signals
+	input	wire			i_axi_wready,  // Write data ready
+	input	wire	[DW-1:0]	i_axi_wdata,	// Write data
+	input	wire	[DW/8-1:0]	i_axi_wstrb,	// Write strobes
+	input	wire			i_axi_wlast,	// Last write transaction
+	input	wire			i_axi_wvalid,	// Write valid
+
+// AXI write response channel signals
+	input	wire [C_AXI_ID_WIDTH-1:0] i_axi_bid,	// Response ID
+	input	wire	[1:0]		i_axi_bresp,	// Write response
+	input	wire			i_axi_bvalid,  // Write reponse valid
+	input	wire			i_axi_bready,  // Response ready
+
+// AXI read address channel signals
+	input	wire			i_axi_arready,	// Read address ready
+	input	wire	[C_AXI_ID_WIDTH-1:0]	i_axi_arid,	// Read ID
+	input	wire	[AW-1:0]	i_axi_araddr,	// Read address
+	input	wire	[7:0]		i_axi_arlen,	// Read Burst Length
+	input	wire	[2:0]		i_axi_arsize,	// Read Burst size
+	input	wire	[1:0]		i_axi_arburst,	// Read Burst type
+	input	wire	[0:0]		i_axi_arlock,	// Read lock type
+	input	wire	[3:0]		i_axi_arcache,	// Read Cache type
+	input	wire	[2:0]		i_axi_arprot,	// Read Protection type
+	input	wire	[3:0]		i_axi_arqos,	// Read Protection type
+	input	wire			i_axi_arvalid,	// Read address valid
+
+// AXI read data channel signals
+	input wire [C_AXI_ID_WIDTH-1:0] i_axi_rid,     // Response ID
+	input	wire	[1:0]		i_axi_rresp,   // Read response
+	input	wire			i_axi_rvalid,  // Read reponse valid
+	input	wire	[DW-1:0]	i_axi_rdata,    // Read data
+	input	wire			i_axi_rlast,    // Read last
+	input	wire			i_axi_rready,  // Read Response ready
+	//
+	output	reg	[F_LGDEPTH-1:0]		f_axi_awr_nbursts,
+	output	reg	[9-1:0]			f_axi_wr_pending,
+	output	reg	[F_LGDEPTH-1:0]		f_axi_rd_nbursts,
+	output	reg	[F_LGDEPTH-1:0]		f_axi_rd_outstanding,
+	// ...
+);
+
+//*****************************************************************************
+// Parameter declarations
+//*****************************************************************************
+
+	localparam	F_AXI_MAXWAIT = F_AXI_MAXSTALL;
+
+	// Because of the nature and size of bursts, which can be up to
+	// 256 in length (AxLEN), the F_LGDEPTH parameter necessary to capture
+	// this *must* be at least 8 bits wide
+	always @(*)
+		assert(F_LGDEPTH > 8);
+
+	// Only power of two data sizes are supported from 8-bits on up to
+	// 1024
+	always @(*)
+		assert((DW == 8)
+			||(DW ==  16)
+			||(DW ==  32)
+			||(DW ==  64)
+			||(DW == 128)
+			||(DW == 256)
+			||(DW == 512)
+			||(DW == 1024));
+
+//*****************************************************************************
+// Internal register and wire declarations
+//*****************************************************************************
+
+
+	wire	axi_rd_ack, axi_wr_ack, axi_ard_req, axi_awr_req, axi_wr_req,
+		axi_rd_err, axi_wr_err;
+	//
+	assign	axi_ard_req = (i_axi_arvalid)&&(i_axi_arready);
+	assign	axi_awr_req = (i_axi_awvalid)&&(i_axi_awready);
+	assign	axi_wr_req  = (i_axi_wvalid )&&(i_axi_wready);
+	//
+	assign	axi_rd_ack = (i_axi_rvalid)&&(i_axi_rready);
+	assign	axi_wr_ack = (i_axi_bvalid)&&(i_axi_bready);
+	assign	axi_rd_err = (axi_rd_ack)&&(i_axi_rresp[1]);
+	assign	axi_wr_err = (axi_wr_ack)&&(i_axi_bresp[1]);
+	//
+	// ...
+	//
+
+	// Within the slave core, we will *assume* properties from the master,
+	// and *assert* properties of signals coming from the slave and
+	// returning to the master.  This order will be reversed within the
+	// master, and the following two definitions help us do that.
+	//
+	// Similarly, we will always *assert* local values of our own necessary
+	// for checks below.  Those will use the assert() keyword, rather than
+	// either of these two macros.
+`define	SLAVE_ASSUME	assert
+`define	SLAVE_ASSERT	assume
+
+	//
+	// Setup
+	//
+	integer	k;
+
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+
+	always @(*)
+	if (!f_past_valid)
+		assert(!i_axi_reset_n);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Reset properties
+	//
+	// Insist that the reset signal start out asserted (negative), and
+	// remain so for 16 clocks.
+	//
+	////////////////////////////////////////////////////////////////////////
+	generate if (F_OPT_ASSUME_RESET)
+	begin : ASSUME_INITIAL_RESET
+		always @(*)
+		if (!f_past_valid)
+			assume(!i_axi_reset_n);
+	end else begin : ASSERT_INITIAL_RESET
+		always @(*)
+		if (!f_past_valid)
+			assert(!i_axi_reset_n);
+	end endgenerate
+	//
+	//
+	// If asserted, the reset must be asserted for a minimum of 16 clocks
+	initial	f_reset_length = 0;
+	always @(posedge i_clk)
+	if (F_OPT_NO_RESET || i_axi_reset_n)
+		f_reset_length <= 0;
+	else if (!(&f_reset_length))
+		f_reset_length <= f_reset_length + 1'b1;
+
+	always @(posedge i_clk)
+	if ((f_past_valid)&& !F_OPT_NO_RESET
+			&& (!$past(i_axi_reset_n))&&(!$past(&f_reset_length)))
+		`SLAVE_ASSUME(!i_axi_reset_n);
+
+	//
+	// If the reset is not generated within this particular core, then it
+	// can be assumed if F_OPT_ASSUME_RESET is set
+	generate if (F_OPT_ASSUME_RESET && !F_OPT_NO_RESET)
+	begin : ASSUME_RESET
+		always @(posedge i_clk)
+		if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length)))
+			assume(!i_axi_reset_n);
+
+		always @(*)
+		if ((f_reset_length > 0)&&(f_reset_length < 4'hf))
+			assume(!i_axi_reset_n);
+
+	end else if (!F_OPT_NO_RESET)
+	begin : ASSERT_RESET
+
+		always @(posedge i_clk)
+		if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length)))
+			assert(!i_axi_reset_n);
+
+		always @(*)
+		if ((f_reset_length > 0)&&(f_reset_length < 4'hf))
+			assert(!i_axi_reset_n);
+
+	end endgenerate
+
+	//
+	// All of the xVALID signals *MUST* be set low on the clock following
+	// a reset.  Not in the spec, but also checked here is that they must
+	// also be set low initially.
+	always @(posedge i_clk)
+	if ((!f_past_valid)||(!$past(i_axi_reset_n)))
+	begin
+		`SLAVE_ASSUME(!i_axi_arvalid);
+		`SLAVE_ASSUME(!i_axi_awvalid);
+		`SLAVE_ASSUME(!i_axi_wvalid);
+		//
+		`SLAVE_ASSERT(!i_axi_bvalid);
+		`SLAVE_ASSERT(!i_axi_rvalid);
+	end
+
+	generate if (OPT_ASYNC_RESET)
+	begin
+		always @(*)
+		if (!i_axi_reset_n)
+		begin
+			`SLAVE_ASSUME(!i_axi_arvalid);
+			`SLAVE_ASSUME(!i_axi_awvalid);
+			`SLAVE_ASSUME(!i_axi_wvalid);
+			//
+			`SLAVE_ASSERT(!i_axi_bvalid);
+			`SLAVE_ASSERT(!i_axi_rvalid);
+		end
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Stability properties--what happens if valid and not ready
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	// Assume any response from the bus will not change prior to that
+	// response being accepted
+	always @(posedge i_clk)
+	if ((f_past_valid)&& $past(i_axi_reset_n)
+		&& (!OPT_ASYNC_RESET || i_axi_reset_n))
+	begin
+		// Write address channel
+		if ((f_past_valid)&&($past(i_axi_awvalid && !i_axi_awready)))
+		begin
+			`SLAVE_ASSUME(i_axi_awvalid);
+			`SLAVE_ASSUME($stable(i_axi_awaddr));
+			`SLAVE_ASSUME($stable(i_axi_awid));
+			`SLAVE_ASSUME($stable(i_axi_awlen));
+			`SLAVE_ASSUME($stable(i_axi_awsize));
+			`SLAVE_ASSUME($stable(i_axi_awburst));
+			`SLAVE_ASSUME($stable(i_axi_awlock));
+			`SLAVE_ASSUME($stable(i_axi_awcache));
+			`SLAVE_ASSUME($stable(i_axi_awprot));
+			`SLAVE_ASSUME($stable(i_axi_awqos));
+		end
+
+		// Write data channel
+		if ((f_past_valid)&&($past(i_axi_wvalid && !i_axi_wready)))
+		begin
+			`SLAVE_ASSUME(i_axi_wvalid);
+			`SLAVE_ASSUME($stable(i_axi_wstrb));
+			`SLAVE_ASSUME($stable(i_axi_wdata));
+			`SLAVE_ASSUME($stable(i_axi_wlast));
+		end
+
+		// Incoming Read address channel
+		if ((f_past_valid)&&($past(i_axi_arvalid && !i_axi_arready)))
+		begin
+			`SLAVE_ASSUME(i_axi_arvalid);
+			`SLAVE_ASSUME($stable(i_axi_arid));
+			`SLAVE_ASSUME($stable(i_axi_araddr));
+			`SLAVE_ASSUME($stable(i_axi_arlen));
+			`SLAVE_ASSUME($stable(i_axi_arsize));
+			`SLAVE_ASSUME($stable(i_axi_arburst));
+			`SLAVE_ASSUME($stable(i_axi_arlock));
+			`SLAVE_ASSUME($stable(i_axi_arcache));
+			`SLAVE_ASSUME($stable(i_axi_arprot));
+			`SLAVE_ASSUME($stable(i_axi_arqos));
+		end
+
+		// Assume any response from the bus will not change prior to
+		// that response being accepted
+		if ((f_past_valid)&&($past(i_axi_rvalid && !i_axi_rready)))
+		begin
+			`SLAVE_ASSERT(i_axi_rvalid);
+			`SLAVE_ASSERT($stable(i_axi_rid));
+			`SLAVE_ASSERT($stable(i_axi_rresp));
+			`SLAVE_ASSERT($stable(i_axi_rdata));
+			`SLAVE_ASSERT($stable(i_axi_rlast));
+		end
+
+		if ((f_past_valid)&&($past(i_axi_bvalid && !i_axi_bready)))
+		begin
+			`SLAVE_ASSERT(i_axi_bvalid);
+			`SLAVE_ASSERT($stable(i_axi_bid));
+			`SLAVE_ASSERT($stable(i_axi_bresp));
+		end
+	end
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Insist upon a maximum delay before a request is accepted
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	generate if (F_AXI_MAXWAIT > 0)
+	begin : CHECK_STALL_COUNT
+		reg	[(F_LGDEPTH-1):0]	f_axi_awstall,
+						f_axi_wstall,
+						f_axi_arstall;
+
+		//
+		// AXI write address channel
+		//
+		// Count the number of times AWVALID is true while AWREADY
+		// is false.  These are stalls, and we want to insist on a
+		// minimum number of them.  However, if BVALID && !BREADY,
+		// then there's a reason for not accepting anything more.
+		// Similarly, many cores will only ever accept one request
+		// at a time, hence we won't count things as stalls if
+		// WR-PENDING > 0.
+		initial	f_axi_awstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_awvalid)||(i_axi_awready)
+				||(f_axi_wr_pending > 0))
+			f_axi_awstall <= 0;
+		else if ((!i_axi_bvalid)||(i_axi_bready))
+			f_axi_awstall <= f_axi_awstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_awstall < F_AXI_MAXWAIT);
+
+		//
+		// AXI write data channel
+		//
+		// Count the number of clock cycles that the write data
+		// channel is stalled, that is while WVALID && !WREADY.
+		// Since things can back up if BVALID & !BREADY, we avoid
+		// counting clock cycles in that circumstance
+		initial	f_axi_wstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_wvalid)||(i_axi_wready)
+				||(f_axi_wr_pending == 0 && i_axi_wvalid))
+			f_axi_wstall <= 0;
+		else if ((!i_axi_bvalid)||(i_axi_bready))
+			f_axi_wstall <= f_axi_wstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_wstall < F_AXI_MAXWAIT);
+
+		//
+		// AXI read address channel
+		//
+		// Similar to the first two above, once the master raises
+		// ARVALID, insist that the slave respond within a minimum
+		// number of clock cycles.  Exceptions include any time
+		// RVALID is true, since that can back up the whole system,
+		// and any time the number of bursts is greater than zero,
+		// since many slaves can only accept one request at a time.
+		initial	f_axi_arstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_arvalid)||(i_axi_arready)
+				||(i_axi_rvalid)||(f_axi_rd_nbursts > 0))
+			f_axi_arstall <= 0;
+		else
+			f_axi_arstall <= f_axi_arstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_arstall < F_AXI_MAXWAIT);
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Insist upon a maximum delay before any response is accepted
+	//
+	// These are separate from the earlier ones, in case you wish to
+	// control them separately.  For example, an interconnect might be
+	// forced to let a channel wait indefinitely for access, but it might
+	// not be appropriate to require the response to be able to wait
+	// indefinitely as well
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	generate if (F_AXI_MAXRSTALL > 0)
+	begin : CHECK_RESPONSE_STALLS
+		//
+		// AXI write address channel
+		//
+		//
+		reg	[(F_LGDEPTH-1):0]	f_axi_wvstall,
+						f_axi_bstall,
+						f_axi_rstall;
+
+		// AXI write channel valid
+		//
+		// The first master stall check: guarantee that the master
+		// provides the required write data in fairly short order,
+		// and without much delay.  That is, once AWVALID && AWREADY
+		// are true, the slave needs to provide the W* values
+		initial	f_axi_wvstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(i_axi_wvalid)
+				||(i_axi_bvalid && !i_axi_bready)
+				||(f_axi_wr_pending == 0))
+			f_axi_wvstall <= 0;
+		else
+			f_axi_wvstall <= f_axi_wvstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSUME(f_axi_wvstall < F_AXI_MAXRSTALL);
+
+		// AXI write response channel
+		//
+		// Insist on a maximum number of clocks that BVALID can be
+		// high while BREADY is low
+		initial	f_axi_bstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_bvalid)||(i_axi_bready))
+			f_axi_bstall <= 0;
+		else
+			f_axi_bstall <= f_axi_bstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSUME(f_axi_bstall < F_AXI_MAXRSTALL);
+
+		// AXI read response channel
+		//
+		// Insist on a maximum number of clocks that RVALID can be
+		// high while RREADY is low
+		initial	f_axi_rstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_rvalid)||(i_axi_rready))
+			f_axi_rstall <= 0;
+		else
+			f_axi_rstall <= f_axi_rstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSUME(f_axi_rstall < F_AXI_MAXRSTALL);
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Count outstanding transactions.  With these measures, we count
+	// once per any burst.
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// ...
+
+	initial	f_axi_wr_pending = 0;
+	// ...
+	always @(posedge i_clk)
+	if (!i_axi_reset_n)
+	begin
+		f_axi_wr_pending <= 0;
+		// ...
+	end else case({ axi_awr_req, axi_wr_req })
+	2'b10: begin
+		f_axi_wr_pending <= i_axi_awlen+1;
+		// ...
+		end
+	2'b01: begin
+		`SLAVE_ASSUME(f_axi_wr_pending > 0);
+		f_axi_wr_pending <= f_axi_wr_pending - 1'b1;
+		`SLAVE_ASSUME(!i_axi_wlast || (f_axi_wr_pending == 1));
+		// ...
+		end
+	2'b11: begin
+		// ...
+		if (f_axi_wr_pending > 0)
+			f_axi_wr_pending <= i_axi_awlen+1;
+		else begin
+			f_axi_wr_pending <= i_axi_awlen;
+			// ...
+		end end
+	default: begin end
+	endcase
+
+	// ...
+	//
+	// Insist that no WVALID value show up prior to a AWVALID value.  The
+	// address *MUST* come first.  Further, while waiting for the write
+	// data, NO OTHER WRITE ADDRESS may be permitted.  This is not strictly
+	// required by the specification, but it is required in order to make
+	// these properties work (currently--I might revisit this later)
+	//
+	// ...
+
+	//
+	// Count the number of outstanding BVALID's to expect
+	//
+	initial	f_axi_awr_nbursts = 0;
+	always @(posedge i_clk)
+	if (!i_axi_reset_n)
+		f_axi_awr_nbursts <= 0;
+	else case({ (axi_awr_req), (axi_wr_ack) })
+	2'b10: f_axi_awr_nbursts <= f_axi_awr_nbursts + 1'b1;
+	2'b01: f_axi_awr_nbursts <= f_axi_awr_nbursts - 1'b1;
+	default: begin end
+	endcase
+
+	//
+	// Count the number of reads bursts outstanding.  This defines the
+	// number of RDVALID && RLAST's we expect to see before becoming idle
+	//
+	initial	f_axi_rd_nbursts = 0;
+	always @(posedge i_clk)
+	if (!i_axi_reset_n)
+		f_axi_rd_nbursts <= 0;
+	else case({ (axi_ard_req), (axi_rd_ack)&&(i_axi_rlast) })
+	2'b01: f_axi_rd_nbursts <= f_axi_rd_nbursts - 1'b1;
+	2'b10: f_axi_rd_nbursts <= f_axi_rd_nbursts + 1'b1;
+	endcase
+
+	//
+	// f_axi_rd_outstanding counts the number of RDVALID's we expect to
+	// see before becoming idle.  This must always be greater than or
+	// equal to the number of RVALID & RLAST's counted above
+	//
+	initial	f_axi_rd_outstanding = 0;
+	always @(posedge i_clk)
+	if (!i_axi_reset_n)
+		f_axi_rd_outstanding <= 0;
+	else case({ (axi_ard_req), (axi_rd_ack) })
+	2'b01: f_axi_rd_outstanding <= f_axi_rd_outstanding - 1'b1;
+	2'b10: f_axi_rd_outstanding <= f_axi_rd_outstanding + i_axi_arlen+1;
+	2'b11: f_axi_rd_outstanding <= f_axi_rd_outstanding + i_axi_arlen;
+	endcase
+
+	//
+	// Do not let the number of outstanding requests overflow.  This is
+	// a responsibility of the master to never allow 2^F_LGDEPTH-1
+	// requests to be outstanding.
+	//
+	always @(*)
+		`SLAVE_ASSERT(f_axi_rd_outstanding  < {(F_LGDEPTH){1'b1}});
+	always @(*)
+		`SLAVE_ASSERT(f_axi_awr_nbursts < {(F_LGDEPTH){1'b1}});
+	always @(*)
+		`SLAVE_ASSERT(f_axi_wr_pending <= 256);
+	always @(*)
+		`SLAVE_ASSERT(f_axi_rd_nbursts  < {(F_LGDEPTH){1'b1}});
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read Burst counting
+	//
+	always @(*)
+		assert(f_axi_rd_nbursts <= f_axi_rd_outstanding);
+	always @(*)
+		assert((f_axi_rd_nbursts == 0)==(f_axi_rd_outstanding==0));
+	//
+	//
+	// ...
+	//
+	// AXI read data channel signals
+	//
+	always @(*)
+	if (i_axi_rvalid)
+	begin
+		`SLAVE_ASSERT(f_axi_rd_outstanding > 0);
+		`SLAVE_ASSERT(f_axi_rd_nbursts > 0);
+		// ...
+	end
+	always @(*)
+		next_rd_nbursts = f_axi_rd_nbursts
+				- (i_axi_rvalid && i_axi_rlast ? 1:0);
+
+	always @(*)
+		next_rd_outstanding = f_axi_rd_outstanding
+				- (i_axi_rvalid ? 1:00);
+	// ...
+	always @(*)
+		`SLAVE_ASSERT(next_rd_nbursts   <= next_rd_outstanding);
+	// ...
+	always @(*)
+		`SLAVE_ASSERT({ 8'h00, next_rd_outstanding }
+				<= { next_rd_nbursts, 8'h00 });
+	//
+	// ...
+	//
+	always @(*)
+		assert({ 8'h00, f_axi_rd_outstanding } <= { f_axi_rd_nbursts, 8'h0 });
+
+	//
+	// ...
+	//
+
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Insist that all responses are returned in less than a maximum delay
+	// In this case, we count responses within a burst, rather than entire
+	// bursts.
+	//
+	//
+	// A unique feature to the backpressure mechanism within AXI is that
+	// we have to reset our delay counters in the case of any push back,
+	// since the response can't move forward if the master isn't (yet)
+	// ready for it.
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	generate if (F_AXI_MAXDELAY > 0)
+	begin : CHECK_MAX_DELAY
+
+		reg	[(F_LGDEPTH-1):0]	f_axi_awr_ack_delay,
+						f_axi_rd_ack_delay;
+
+		initial	f_axi_awr_ack_delay = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(i_axi_bvalid)||(i_axi_wvalid)
+					||((f_axi_awr_nbursts == 1)
+						&&(f_axi_wr_pending>0))
+					||(f_axi_awr_nbursts == 0))
+			f_axi_awr_ack_delay <= 0;
+		else
+			f_axi_awr_ack_delay <= f_axi_awr_ack_delay + 1'b1;
+
+		initial	f_axi_rd_ack_delay = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(i_axi_rvalid)||(f_axi_rd_outstanding==0))
+			f_axi_rd_ack_delay <= 0;
+		else
+			f_axi_rd_ack_delay <= f_axi_rd_ack_delay + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_awr_ack_delay < F_AXI_MAXDELAY);
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_rd_ack_delay < F_AXI_MAXDELAY);
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Assume acknowledgements must follow requests
+	//
+	// The outstanding count is a count of bursts, but the acknowledgements
+	// we are looking for are individual.  Hence, there should be no
+	// individual acknowledgements coming back if there's no outstanding
+	// burst.
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	//
+	// AXI write response channel
+	//
+	//
+	// ...
+	//
+	//
+	// Cannot have outstanding values if there aren't any outstanding
+	// bursts
+	//
+	// ...
+	//
+	always @(posedge i_clk)
+	if (f_axi_awr_nbursts == 0)
+		`SLAVE_ASSERT(f_axi_wr_pending == 0);
+	//
+	// ...
+	//
+
+	//
+	// Because we can't accept multiple AW* requests prior to the
+	// last WVALID && WLAST, the AWREADY signal *MUST* be high while
+	// waiting
+	//
+	always @(*)
+	if (f_axi_wr_pending > 1)
+		`SLAVE_ASSERT(!i_axi_awready);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write address checking
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(posedge i_clk)
+	begin
+		//
+		// ...
+		//
+		if (!OPT_NARROW_BURST)
+		begin
+			// In this case, all size parameters are fixed.
+			// Let's remove them from the solvers logic choices
+			// for optimization purposes
+			//
+			if (DW == 8)
+				f_axi_wr_size <= 0;
+			else if (DW == 16)
+				f_axi_wr_size <= 1;
+			else if (DW == 32)
+				f_axi_wr_size <= 2;
+			else if (DW == 64)
+				f_axi_wr_size <= 3;
+			else if (DW == 128)
+				f_axi_wr_size <= 4;
+			else if (DW == 256)
+				f_axi_wr_size <= 5;
+			else if (DW == 512)
+				f_axi_wr_size <= 6;
+			else // if (DW == 1024)
+				f_axi_wr_size <= 7;
+		end
+	end
+
+	//
+	// ...
+	//
+	always @(*)
+		wstb_addr = f_axi_wr_addr;
+
+
+	// Insist the only the appropriate bits be valid
+	// For example, if the lower address bit is one, then the
+	// strobe LSB cannot be 1, but must be zero.  This is just
+	// enforcing the rules of the sub-address which must match
+	// the write strobe.  An STRB of 0 is always allowed.
+	//
+	always @(*)
+	if (i_axi_wvalid)
+		`SLAVE_ASSUME(wstb_valid);
+
+	//
+	// Write induction properties
+	//
+	// These are actual assert()s and not `SLAVE_ASSERT or `SLAVE_ASSUMEs
+	// because they are testing the functionality of this core and its local
+	// logical registers, not so much the functionality of the core we are
+	// testing
+	//
+	reg	[7:0]	val_wr_len;
+	always @(*)
+		val_wr_len = f_axi_wr_pending[7:0]-1;
+
+	always @(*)
+	if (f_axi_wr_pending > 0)
+		assert(f_axi_wr_pending <= f_axi_wr_len + 1);
+	always @(*)
+		assert(f_axi_wr_pending <= 9'h100);
+
+	always @(*)
+	if ((f_axi_wr_pending > 0)&&(f_axi_wr_burst == 2'b10))
+		assert((f_axi_wr_len == 1)
+			||(f_axi_wr_len == 3)
+			||(f_axi_wr_len == 7)
+			||(f_axi_wr_len == 15));
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read address checking
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(posedge i_clk)
+	begin
+		//
+		// ...
+		//
+		if (!OPT_NARROW_BURST)
+		begin
+			// In this case, all size parameters are fixed.
+			// Let's remove them from the solvers logic choices
+			// for optimization purposes
+			//
+			if (DW == 8)
+				f_axi_rd_cksize <= 0;
+			else if (DW == 16)
+				f_axi_rd_cksize <= 1;
+			else if (DW == 32)
+				f_axi_rd_cksize <= 2;
+			else if (DW == 64)
+				f_axi_rd_cksize <= 3;
+			else if (DW == 128)
+				f_axi_rd_cksize <= 4;
+			else if (DW == 256)
+				f_axi_rd_cksize <= 5;
+			else if (DW == 512)
+				f_axi_rd_cksize <= 6;
+			else // if (DW == 1024)
+				f_axi_rd_cksize <= 7;
+		end
+	end
+
+	//
+	// Read induction properties
+	//
+	// These are actual assert()s and not `SLAVE_ASSERT or `SLAVE_ASSUMEs
+	// because they are testing the functionality of this core and its local
+	// logical registers, not so much the functionality of the core we are
+	// testing
+	//
+	// ...
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Exclusive properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	generate if (!OPT_EXCLUSIVE)
+	begin : EXCLUSIVE_DISALLOWED
+		localparam [1:0]	EXOKAY = 2'b01;
+
+		//
+		// Without exclusive access support, the master shall not issue
+		// exclusive access requests
+		always @(*)
+		begin
+		`SLAVE_ASSUME(!i_axi_awvalid || !i_axi_awlock);
+		`SLAVE_ASSUME(!i_axi_arvalid || !i_axi_arlock);
+		end
+
+		// Similarly, without exclusive access support, the slave
+		// shall not respond with an okay indicating that exclusive
+		// access was supported.
+		always @(*)
+		begin
+		`SLAVE_ASSERT(!i_axi_bvalid || i_axi_bresp != EXOKAY);
+		`SLAVE_ASSERT(!i_axi_rvalid || i_axi_rresp != EXOKAY);
+		end
+
+	end else begin : EXCLUSIVE_ACCESS_CHECKER
+
+		//
+		// 1. Exclusive access burst lengths max out at 16
+		// 2. Exclusive access bursts must be aligned
+		// 3. Write must take place when the read channel is idle (on
+		//	this ID)
+		// (4. Further read accesses on this ID are not allowed)
+		//
+		always @(*)
+		if (i_axi_awvalid && i_axi_awlock)
+		begin
+			// ...
+		end
+
+		always @(*)
+		if (i_axi_arvalid && i_axi_arlock)
+		begin
+			// ...
+		end
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// ...
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Option for no bursts, only single transactions
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	generate if (!F_OPT_BURSTS)
+	begin
+
+		always @(*)
+		if (i_axi_awvalid)
+			`SLAVE_ASSUME(i_axi_awlen == 0);
+
+		always @(*)
+		if (i_axi_wvalid)
+			`SLAVE_ASSUME(i_axi_wlast);
+
+		always @(*)
+			assert(f_axi_wr_pending <= 1);
+
+		always @(*)
+			assert(f_axi_wr_len == 0);
+
+		always @(*)
+		if (i_axi_arvalid)
+			`SLAVE_ASSUME(i_axi_arlen == 0);
+
+		always @(*)
+		if (i_axi_rvalid)
+			`SLAVE_ASSERT(i_axi_rlast);
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_rd_nbursts == f_axi_rd_outstanding);
+		//
+		// ...
+		//
+	end endgenerate
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Packet read checking
+	//
+	// Pick a read address request, and then track that one transaction
+	// through the system
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	//
+	// ...
+	//
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxi_slave.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxi_slave.v
new file mode 100644
index 0000000..49f7c60
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxi_slave.v
@@ -0,0 +1,972 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	faxi_slave.v (Formal properties of an AXI4 (full) slave)
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	This file contains a subset of the formal properties which I've
+//		used to formally verify that a core truly follows the full
+//	AXI4 specification.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2017-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module faxi_slave #(
+	parameter C_AXI_ID_WIDTH	= 3, // The AXI id width used for R&W
+                                             // This is an int between 1-16
+	parameter C_AXI_DATA_WIDTH	= 128,// Width of the AXI R&W data
+	parameter C_AXI_ADDR_WIDTH	= 28,	// AXI Address width (log wordsize)
+	parameter [7:0] OPT_MAXBURST	= 8'hff,// Maximum burst length, minus 1
+	parameter [0:0] OPT_EXCLUSIVE	= 1,// Exclusive access allowed
+	parameter [0:0] OPT_NARROW_BURST = 1,// Narrow bursts allowed by default
+	parameter [0:0]	OPT_ASYNC_RESET  = 0,
+	// F_OPT_ASSUME_RESET, if set, will cause the design to *assume* the
+	// existence of a correct reset, rather than asserting it.  It is
+	// appropriate anytime the reset logic is outside of the circuit being
+	// examined
+	parameter [0:0]			F_OPT_ASSUME_RESET = 1'b1,
+	parameter [0:0]			F_OPT_NO_RESET = 1'b1,
+	// F_LGDEPTH is the number of bits necessary to count the maximum
+	// number of items in flight.
+	parameter				F_LGDEPTH      = 10,
+	parameter	[(F_LGDEPTH-1):0]	F_AXI_MAXSTALL = 3,
+	parameter	[(F_LGDEPTH-1):0]	F_AXI_MAXRSTALL= 3,
+	parameter	[(F_LGDEPTH-1):0]	F_AXI_MAXDELAY = 3,
+	localparam			F_OPT_BURSTS    = (OPT_MAXBURST != 0),
+	//
+	localparam IW			= C_AXI_ID_WIDTH,
+	localparam DW			= C_AXI_DATA_WIDTH,
+	localparam AW			= C_AXI_ADDR_WIDTH
+	) (
+	input	wire			i_clk,	// System clock
+	input	wire			i_axi_reset_n,
+
+// AXI write address channel signals
+	input	wire			i_axi_awready,//Slave is ready to accept
+	input	wire	[C_AXI_ID_WIDTH-1:0]	i_axi_awid,	// Write ID
+	input	wire	[AW-1:0]	i_axi_awaddr,	// Write address
+	input	wire	[7:0]		i_axi_awlen,	// Write Burst Length
+	input	wire	[2:0]		i_axi_awsize,	// Write Burst size
+	input	wire	[1:0]		i_axi_awburst,	// Write Burst type
+	input	wire	[0:0]		i_axi_awlock,	// Write lock type
+	input	wire	[3:0]		i_axi_awcache,	// Write Cache type
+	input	wire	[2:0]		i_axi_awprot,	// Write Protection type
+	input	wire	[3:0]		i_axi_awqos,	// Write Quality of Svc
+	input	wire			i_axi_awvalid,	// Write address valid
+
+// AXI write data channel signals
+	input	wire			i_axi_wready,  // Write data ready
+	input	wire	[DW-1:0]	i_axi_wdata,	// Write data
+	input	wire	[DW/8-1:0]	i_axi_wstrb,	// Write strobes
+	input	wire			i_axi_wlast,	// Last write transaction
+	input	wire			i_axi_wvalid,	// Write valid
+
+// AXI write response channel signals
+	input	wire [C_AXI_ID_WIDTH-1:0] i_axi_bid,	// Response ID
+	input	wire	[1:0]		i_axi_bresp,	// Write response
+	input	wire			i_axi_bvalid,  // Write reponse valid
+	input	wire			i_axi_bready,  // Response ready
+
+// AXI read address channel signals
+	input	wire			i_axi_arready,	// Read address ready
+	input	wire	[C_AXI_ID_WIDTH-1:0]	i_axi_arid,	// Read ID
+	input	wire	[AW-1:0]	i_axi_araddr,	// Read address
+	input	wire	[7:0]		i_axi_arlen,	// Read Burst Length
+	input	wire	[2:0]		i_axi_arsize,	// Read Burst size
+	input	wire	[1:0]		i_axi_arburst,	// Read Burst type
+	input	wire	[0:0]		i_axi_arlock,	// Read lock type
+	input	wire	[3:0]		i_axi_arcache,	// Read Cache type
+	input	wire	[2:0]		i_axi_arprot,	// Read Protection type
+	input	wire	[3:0]		i_axi_arqos,	// Read Protection type
+	input	wire			i_axi_arvalid,	// Read address valid
+
+// AXI read data channel signals
+	input wire [C_AXI_ID_WIDTH-1:0] i_axi_rid,     // Response ID
+	input	wire	[1:0]		i_axi_rresp,   // Read response
+	input	wire			i_axi_rvalid,  // Read reponse valid
+	input	wire	[DW-1:0]	i_axi_rdata,    // Read data
+	input	wire			i_axi_rlast,    // Read last
+	input	wire			i_axi_rready,  // Read Response ready
+	//
+	output	reg	[F_LGDEPTH-1:0]		f_axi_awr_nbursts,
+	output	reg	[9-1:0]			f_axi_wr_pending,
+	output	reg	[F_LGDEPTH-1:0]		f_axi_rd_nbursts,
+	output	reg	[F_LGDEPTH-1:0]		f_axi_rd_outstanding,
+	// ...
+);
+
+//*****************************************************************************
+// Parameter declarations
+//*****************************************************************************
+
+	localparam	F_AXI_MAXWAIT = F_AXI_MAXSTALL;
+
+	// Because of the nature and size of bursts, which can be up to
+	// 256 in length (AxLEN), the F_LGDEPTH parameter necessary to capture
+	// this *must* be at least 8 bits wide
+	always @(*)
+		assert(F_LGDEPTH > 8);
+
+	// Only power of two data sizes are supported from 8-bits on up to
+	// 1024
+	always @(*)
+		assert((DW == 8)
+			||(DW ==  16)
+			||(DW ==  32)
+			||(DW ==  64)
+			||(DW == 128)
+			||(DW == 256)
+			||(DW == 512)
+			||(DW == 1024));
+
+//*****************************************************************************
+// Internal register and wire declarations
+//*****************************************************************************
+
+
+	wire	axi_rd_ack, axi_wr_ack, axi_ard_req, axi_awr_req, axi_wr_req,
+		axi_rd_err, axi_wr_err;
+	//
+	assign	axi_ard_req = (i_axi_arvalid)&&(i_axi_arready);
+	assign	axi_awr_req = (i_axi_awvalid)&&(i_axi_awready);
+	assign	axi_wr_req  = (i_axi_wvalid )&&(i_axi_wready);
+	//
+	assign	axi_rd_ack = (i_axi_rvalid)&&(i_axi_rready);
+	assign	axi_wr_ack = (i_axi_bvalid)&&(i_axi_bready);
+	assign	axi_rd_err = (axi_rd_ack)&&(i_axi_rresp[1]);
+	assign	axi_wr_err = (axi_wr_ack)&&(i_axi_bresp[1]);
+	//
+	// ...
+	//
+
+	// Within the slave core, we will *assume* properties from the master,
+	// and *assert* properties of signals coming from the slave and
+	// returning to the master.  This order will be reversed within the
+	// master, and the following two definitions help us do that.
+	//
+	// Similarly, we will always *assert* local values of our own necessary
+	// for checks below.  Those will use the assert() keyword, rather than
+	// either of these two macros.
+`define	SLAVE_ASSUME	assume
+`define	SLAVE_ASSERT	assert
+
+	//
+	// Setup
+	//
+	integer	k;
+
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+
+	always @(*)
+	if (!f_past_valid)
+		assume(!i_axi_reset_n);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Reset properties
+	//
+	// Insist that the reset signal start out asserted (negative), and
+	// remain so for 16 clocks.
+	//
+	////////////////////////////////////////////////////////////////////////
+	generate if (F_OPT_ASSUME_RESET)
+	begin : ASSUME_INITIAL_RESET
+		always @(*)
+		if (!f_past_valid)
+			assume(!i_axi_reset_n);
+	end else begin : ASSERT_INITIAL_RESET
+		always @(*)
+		if (!f_past_valid)
+			assert(!i_axi_reset_n);
+	end endgenerate
+	//
+	//
+	// If asserted, the reset must be asserted for a minimum of 16 clocks
+	initial	f_reset_length = 0;
+	always @(posedge i_clk)
+	if (F_OPT_NO_RESET || i_axi_reset_n)
+		f_reset_length <= 0;
+	else if (!(&f_reset_length))
+		f_reset_length <= f_reset_length + 1'b1;
+
+	always @(posedge i_clk)
+	if ((f_past_valid)&& !F_OPT_NO_RESET
+			&& (!$past(i_axi_reset_n))&&(!$past(&f_reset_length)))
+		`SLAVE_ASSUME(!i_axi_reset_n);
+
+	//
+	// If the reset is not generated within this particular core, then it
+	// can be assumed if F_OPT_ASSUME_RESET is set
+	generate if (F_OPT_ASSUME_RESET && !F_OPT_NO_RESET)
+	begin : ASSUME_RESET
+		always @(posedge i_clk)
+		if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length)))
+			assume(!i_axi_reset_n);
+
+		always @(*)
+		if ((f_reset_length > 0)&&(f_reset_length < 4'hf))
+			assume(!i_axi_reset_n);
+
+	end else if (!F_OPT_NO_RESET)
+	begin : ASSERT_RESET
+
+		always @(posedge i_clk)
+		if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length)))
+			assert(!i_axi_reset_n);
+
+		always @(*)
+		if ((f_reset_length > 0)&&(f_reset_length < 4'hf))
+			assert(!i_axi_reset_n);
+
+	end endgenerate
+
+	//
+	// All of the xVALID signals *MUST* be set low on the clock following
+	// a reset.  Not in the spec, but also checked here is that they must
+	// also be set low initially.
+	always @(posedge i_clk)
+	if ((!f_past_valid)||(!$past(i_axi_reset_n)))
+	begin
+		`SLAVE_ASSUME(!i_axi_arvalid);
+		`SLAVE_ASSUME(!i_axi_awvalid);
+		`SLAVE_ASSUME(!i_axi_wvalid);
+		//
+		`SLAVE_ASSERT(!i_axi_bvalid);
+		`SLAVE_ASSERT(!i_axi_rvalid);
+	end
+
+	generate if (OPT_ASYNC_RESET)
+	begin
+		always @(*)
+		if (!i_axi_reset_n)
+		begin
+			`SLAVE_ASSUME(!i_axi_arvalid);
+			`SLAVE_ASSUME(!i_axi_awvalid);
+			`SLAVE_ASSUME(!i_axi_wvalid);
+			//
+			`SLAVE_ASSERT(!i_axi_bvalid);
+			`SLAVE_ASSERT(!i_axi_rvalid);
+		end
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Stability properties--what happens if valid and not ready
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	// Assume any response from the bus will not change prior to that
+	// response being accepted
+	always @(posedge i_clk)
+	if ((f_past_valid)&& $past(i_axi_reset_n)
+		&& (!OPT_ASYNC_RESET || i_axi_reset_n))
+	begin
+		// Write address channel
+		if ((f_past_valid)&&($past(i_axi_awvalid && !i_axi_awready)))
+		begin
+			`SLAVE_ASSUME(i_axi_awvalid);
+			`SLAVE_ASSUME($stable(i_axi_awaddr));
+			`SLAVE_ASSUME($stable(i_axi_awid));
+			`SLAVE_ASSUME($stable(i_axi_awlen));
+			`SLAVE_ASSUME($stable(i_axi_awsize));
+			`SLAVE_ASSUME($stable(i_axi_awburst));
+			`SLAVE_ASSUME($stable(i_axi_awlock));
+			`SLAVE_ASSUME($stable(i_axi_awcache));
+			`SLAVE_ASSUME($stable(i_axi_awprot));
+			`SLAVE_ASSUME($stable(i_axi_awqos));
+		end
+
+		// Write data channel
+		if ((f_past_valid)&&($past(i_axi_wvalid && !i_axi_wready)))
+		begin
+			`SLAVE_ASSUME(i_axi_wvalid);
+			`SLAVE_ASSUME($stable(i_axi_wstrb));
+			`SLAVE_ASSUME($stable(i_axi_wdata));
+			`SLAVE_ASSUME($stable(i_axi_wlast));
+		end
+
+		// Incoming Read address channel
+		if ((f_past_valid)&&($past(i_axi_arvalid && !i_axi_arready)))
+		begin
+			`SLAVE_ASSUME(i_axi_arvalid);
+			`SLAVE_ASSUME($stable(i_axi_arid));
+			`SLAVE_ASSUME($stable(i_axi_araddr));
+			`SLAVE_ASSUME($stable(i_axi_arlen));
+			`SLAVE_ASSUME($stable(i_axi_arsize));
+			`SLAVE_ASSUME($stable(i_axi_arburst));
+			`SLAVE_ASSUME($stable(i_axi_arlock));
+			`SLAVE_ASSUME($stable(i_axi_arcache));
+			`SLAVE_ASSUME($stable(i_axi_arprot));
+			`SLAVE_ASSUME($stable(i_axi_arqos));
+		end
+
+		// Assume any response from the bus will not change prior to
+		// that response being accepted
+		if ((f_past_valid)&&($past(i_axi_rvalid && !i_axi_rready)))
+		begin
+			`SLAVE_ASSERT(i_axi_rvalid);
+			`SLAVE_ASSERT($stable(i_axi_rid));
+			`SLAVE_ASSERT($stable(i_axi_rresp));
+			`SLAVE_ASSERT($stable(i_axi_rdata));
+			`SLAVE_ASSERT($stable(i_axi_rlast));
+		end
+
+		if ((f_past_valid)&&($past(i_axi_bvalid && !i_axi_bready)))
+		begin
+			`SLAVE_ASSERT(i_axi_bvalid);
+			`SLAVE_ASSERT($stable(i_axi_bid));
+			`SLAVE_ASSERT($stable(i_axi_bresp));
+		end
+	end
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Insist upon a maximum delay before a request is accepted
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	generate if (F_AXI_MAXWAIT > 0)
+	begin : CHECK_STALL_COUNT
+		reg	[(F_LGDEPTH-1):0]	f_axi_awstall,
+						f_axi_wstall,
+						f_axi_arstall;
+
+		//
+		// AXI write address channel
+		//
+		// Count the number of times AWVALID is true while AWREADY
+		// is false.  These are stalls, and we want to insist on a
+		// minimum number of them.  However, if BVALID && !BREADY,
+		// then there's a reason for not accepting anything more.
+		// Similarly, many cores will only ever accept one request
+		// at a time, hence we won't count things as stalls if
+		// WR-PENDING > 0.
+		initial	f_axi_awstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_awvalid)||(i_axi_awready)
+				||(f_axi_wr_pending > 0))
+			f_axi_awstall <= 0;
+		else if ((!i_axi_bvalid)||(i_axi_bready))
+			f_axi_awstall <= f_axi_awstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_awstall < F_AXI_MAXWAIT);
+
+		//
+		// AXI write data channel
+		//
+		// Count the number of clock cycles that the write data
+		// channel is stalled, that is while WVALID && !WREADY.
+		// Since things can back up if BVALID & !BREADY, we avoid
+		// counting clock cycles in that circumstance
+		initial	f_axi_wstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_wvalid)||(i_axi_wready)
+				||(f_axi_wr_pending == 0 && i_axi_wvalid))
+			f_axi_wstall <= 0;
+		else if ((!i_axi_bvalid)||(i_axi_bready))
+			f_axi_wstall <= f_axi_wstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_wstall < F_AXI_MAXWAIT);
+
+		//
+		// AXI read address channel
+		//
+		// Similar to the first two above, once the master raises
+		// ARVALID, insist that the slave respond within a minimum
+		// number of clock cycles.  Exceptions include any time
+		// RVALID is true, since that can back up the whole system,
+		// and any time the number of bursts is greater than zero,
+		// since many slaves can only accept one request at a time.
+		initial	f_axi_arstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_arvalid)||(i_axi_arready)
+				||(i_axi_rvalid)||(f_axi_rd_nbursts > 0))
+			f_axi_arstall <= 0;
+		else
+			f_axi_arstall <= f_axi_arstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_arstall < F_AXI_MAXWAIT);
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Insist upon a maximum delay before any response is accepted
+	//
+	// These are separate from the earlier ones, in case you wish to
+	// control them separately.  For example, an interconnect might be
+	// forced to let a channel wait indefinitely for access, but it might
+	// not be appropriate to require the response to be able to wait
+	// indefinitely as well
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	generate if (F_AXI_MAXRSTALL > 0)
+	begin : CHECK_RESPONSE_STALLS
+		//
+		// AXI write address channel
+		//
+		//
+		reg	[(F_LGDEPTH-1):0]	f_axi_wvstall,
+						f_axi_bstall,
+						f_axi_rstall;
+
+		// AXI write channel valid
+		//
+		// The first master stall check: guarantee that the master
+		// provides the required write data in fairly short order,
+		// and without much delay.  That is, once AWVALID && AWREADY
+		// are true, the slave needs to provide the W* values
+		initial	f_axi_wvstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(i_axi_wvalid)
+				||(i_axi_bvalid && !i_axi_bready)
+				||(f_axi_wr_pending == 0))
+			f_axi_wvstall <= 0;
+		else
+			f_axi_wvstall <= f_axi_wvstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSUME(f_axi_wvstall < F_AXI_MAXRSTALL);
+
+		// AXI write response channel
+		//
+		// Insist on a maximum number of clocks that BVALID can be
+		// high while BREADY is low
+		initial	f_axi_bstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_bvalid)||(i_axi_bready))
+			f_axi_bstall <= 0;
+		else
+			f_axi_bstall <= f_axi_bstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSUME(f_axi_bstall < F_AXI_MAXRSTALL);
+
+		// AXI read response channel
+		//
+		// Insist on a maximum number of clocks that RVALID can be
+		// high while RREADY is low
+		initial	f_axi_rstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_rvalid)||(i_axi_rready))
+			f_axi_rstall <= 0;
+		else
+			f_axi_rstall <= f_axi_rstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSUME(f_axi_rstall < F_AXI_MAXRSTALL);
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Count outstanding transactions.  With these measures, we count
+	// once per any burst.
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// ...
+
+	initial	f_axi_wr_pending = 0;
+	// ...
+	always @(posedge i_clk)
+	if (!i_axi_reset_n)
+	begin
+		f_axi_wr_pending <= 0;
+		// ...
+	end else case({ axi_awr_req, axi_wr_req })
+	2'b10: begin
+		f_axi_wr_pending <= i_axi_awlen+1;
+		// ...
+		end
+	2'b01: begin
+		`SLAVE_ASSUME(f_axi_wr_pending > 0);
+		f_axi_wr_pending <= f_axi_wr_pending - 1'b1;
+		`SLAVE_ASSUME(!i_axi_wlast || (f_axi_wr_pending == 1));
+		// ...
+		end
+	2'b11: begin
+		// ...
+		if (f_axi_wr_pending > 0)
+			f_axi_wr_pending <= i_axi_awlen+1;
+		else begin
+			f_axi_wr_pending <= i_axi_awlen;
+			// ...
+		end end
+	default: begin end
+	endcase
+
+	// ...
+	//
+	// Insist that no WVALID value show up prior to a AWVALID value.  The
+	// address *MUST* come first.  Further, while waiting for the write
+	// data, NO OTHER WRITE ADDRESS may be permitted.  This is not strictly
+	// required by the specification, but it is required in order to make
+	// these properties work (currently--I might revisit this later)
+	//
+	// ...
+
+	//
+	// Count the number of outstanding BVALID's to expect
+	//
+	initial	f_axi_awr_nbursts = 0;
+	always @(posedge i_clk)
+	if (!i_axi_reset_n)
+		f_axi_awr_nbursts <= 0;
+	else case({ (axi_awr_req), (axi_wr_ack) })
+	2'b10: f_axi_awr_nbursts <= f_axi_awr_nbursts + 1'b1;
+	2'b01: f_axi_awr_nbursts <= f_axi_awr_nbursts - 1'b1;
+	default: begin end
+	endcase
+
+	//
+	// Count the number of reads bursts outstanding.  This defines the
+	// number of RDVALID && RLAST's we expect to see before becoming idle
+	//
+	initial	f_axi_rd_nbursts = 0;
+	always @(posedge i_clk)
+	if (!i_axi_reset_n)
+		f_axi_rd_nbursts <= 0;
+	else case({ (axi_ard_req), (axi_rd_ack)&&(i_axi_rlast) })
+	2'b01: f_axi_rd_nbursts <= f_axi_rd_nbursts - 1'b1;
+	2'b10: f_axi_rd_nbursts <= f_axi_rd_nbursts + 1'b1;
+	endcase
+
+	//
+	// f_axi_rd_outstanding counts the number of RDVALID's we expect to
+	// see before becoming idle.  This must always be greater than or
+	// equal to the number of RVALID & RLAST's counted above
+	//
+	initial	f_axi_rd_outstanding = 0;
+	always @(posedge i_clk)
+	if (!i_axi_reset_n)
+		f_axi_rd_outstanding <= 0;
+	else case({ (axi_ard_req), (axi_rd_ack) })
+	2'b01: f_axi_rd_outstanding <= f_axi_rd_outstanding - 1'b1;
+	2'b10: f_axi_rd_outstanding <= f_axi_rd_outstanding + i_axi_arlen+1;
+	2'b11: f_axi_rd_outstanding <= f_axi_rd_outstanding + i_axi_arlen;
+	endcase
+
+	//
+	// Do not let the number of outstanding requests overflow.  This is
+	// a responsibility of the master to never allow 2^F_LGDEPTH-1
+	// requests to be outstanding.
+	//
+	always @(*)
+		`SLAVE_ASSERT(f_axi_rd_outstanding  < {(F_LGDEPTH){1'b1}});
+	always @(*)
+		`SLAVE_ASSERT(f_axi_awr_nbursts < {(F_LGDEPTH){1'b1}});
+	always @(*)
+		`SLAVE_ASSERT(f_axi_wr_pending <= 256);
+	always @(*)
+		`SLAVE_ASSERT(f_axi_rd_nbursts  < {(F_LGDEPTH){1'b1}});
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read Burst counting
+	//
+	always @(*)
+		assert(f_axi_rd_nbursts <= f_axi_rd_outstanding);
+	always @(*)
+		assert((f_axi_rd_nbursts == 0)==(f_axi_rd_outstanding==0));
+	//
+	//
+	// ...
+	//
+	// AXI read data channel signals
+	//
+	always @(*)
+	if (i_axi_rvalid)
+	begin
+		`SLAVE_ASSERT(f_axi_rd_outstanding > 0);
+		`SLAVE_ASSERT(f_axi_rd_nbursts > 0);
+		// ...
+	end
+	always @(*)
+		next_rd_nbursts = f_axi_rd_nbursts
+				- (i_axi_rvalid && i_axi_rlast ? 1:0);
+
+	always @(*)
+		next_rd_outstanding = f_axi_rd_outstanding
+				- (i_axi_rvalid ? 1:00);
+	// ...
+	always @(*)
+		`SLAVE_ASSERT(next_rd_nbursts   <= next_rd_outstanding);
+	// ...
+	always @(*)
+		`SLAVE_ASSERT({ 8'h00, next_rd_outstanding }
+				<= { next_rd_nbursts, 8'h00 });
+	//
+	// ...
+	//
+	always @(*)
+		assert({ 8'h00, f_axi_rd_outstanding } <= { f_axi_rd_nbursts, 8'h0 });
+
+	//
+	// ...
+	//
+
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Insist that all responses are returned in less than a maximum delay
+	// In this case, we count responses within a burst, rather than entire
+	// bursts.
+	//
+	//
+	// A unique feature to the backpressure mechanism within AXI is that
+	// we have to reset our delay counters in the case of any push back,
+	// since the response can't move forward if the master isn't (yet)
+	// ready for it.
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	generate if (F_AXI_MAXDELAY > 0)
+	begin : CHECK_MAX_DELAY
+
+		reg	[(F_LGDEPTH-1):0]	f_axi_awr_ack_delay,
+						f_axi_rd_ack_delay;
+
+		initial	f_axi_awr_ack_delay = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(i_axi_bvalid)||(i_axi_wvalid)
+					||((f_axi_awr_nbursts == 1)
+						&&(f_axi_wr_pending>0))
+					||(f_axi_awr_nbursts == 0))
+			f_axi_awr_ack_delay <= 0;
+		else
+			f_axi_awr_ack_delay <= f_axi_awr_ack_delay + 1'b1;
+
+		initial	f_axi_rd_ack_delay = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(i_axi_rvalid)||(f_axi_rd_outstanding==0))
+			f_axi_rd_ack_delay <= 0;
+		else
+			f_axi_rd_ack_delay <= f_axi_rd_ack_delay + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_awr_ack_delay < F_AXI_MAXDELAY);
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_rd_ack_delay < F_AXI_MAXDELAY);
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Assume acknowledgements must follow requests
+	//
+	// The outstanding count is a count of bursts, but the acknowledgements
+	// we are looking for are individual.  Hence, there should be no
+	// individual acknowledgements coming back if there's no outstanding
+	// burst.
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	//
+	// AXI write response channel
+	//
+	//
+	// ...
+	//
+	//
+	// Cannot have outstanding values if there aren't any outstanding
+	// bursts
+	//
+	// ...
+	//
+	always @(posedge i_clk)
+	if (f_axi_awr_nbursts == 0)
+		`SLAVE_ASSERT(f_axi_wr_pending == 0);
+	//
+	// ...
+	//
+
+	//
+	// Because we can't accept multiple AW* requests prior to the
+	// last WVALID && WLAST, the AWREADY signal *MUST* be high while
+	// waiting
+	//
+	always @(*)
+	if (f_axi_wr_pending > 1)
+		`SLAVE_ASSERT(!i_axi_awready);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write address checking
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(posedge i_clk)
+	begin
+		//
+		// ...
+		//
+		if (!OPT_NARROW_BURST)
+		begin
+			// In this case, all size parameters are fixed.
+			// Let's remove them from the solvers logic choices
+			// for optimization purposes
+			//
+			if (DW == 8)
+				f_axi_wr_size <= 0;
+			else if (DW == 16)
+				f_axi_wr_size <= 1;
+			else if (DW == 32)
+				f_axi_wr_size <= 2;
+			else if (DW == 64)
+				f_axi_wr_size <= 3;
+			else if (DW == 128)
+				f_axi_wr_size <= 4;
+			else if (DW == 256)
+				f_axi_wr_size <= 5;
+			else if (DW == 512)
+				f_axi_wr_size <= 6;
+			else // if (DW == 1024)
+				f_axi_wr_size <= 7;
+		end
+	end
+
+	//
+	// ...
+	//
+	always @(*)
+		wstb_addr = f_axi_wr_addr;
+
+
+	// Insist the only the appropriate bits be valid
+	// For example, if the lower address bit is one, then the
+	// strobe LSB cannot be 1, but must be zero.  This is just
+	// enforcing the rules of the sub-address which must match
+	// the write strobe.  An STRB of 0 is always allowed.
+	//
+	always @(*)
+	if (i_axi_wvalid)
+		`SLAVE_ASSUME(wstb_valid);
+
+	//
+	// Write induction properties
+	//
+	// These are actual assert()s and not `SLAVE_ASSERT or `SLAVE_ASSUMEs
+	// because they are testing the functionality of this core and its local
+	// logical registers, not so much the functionality of the core we are
+	// testing
+	//
+	reg	[7:0]	val_wr_len;
+	always @(*)
+		val_wr_len = f_axi_wr_pending[7:0]-1;
+
+	always @(*)
+	if (f_axi_wr_pending > 0)
+		assert(f_axi_wr_pending <= f_axi_wr_len + 1);
+	always @(*)
+		assert(f_axi_wr_pending <= 9'h100);
+
+	always @(*)
+	if ((f_axi_wr_pending > 0)&&(f_axi_wr_burst == 2'b10))
+		assert((f_axi_wr_len == 1)
+			||(f_axi_wr_len == 3)
+			||(f_axi_wr_len == 7)
+			||(f_axi_wr_len == 15));
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read address checking
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(posedge i_clk)
+	begin
+		//
+		// ...
+		//
+		if (!OPT_NARROW_BURST)
+		begin
+			// In this case, all size parameters are fixed.
+			// Let's remove them from the solvers logic choices
+			// for optimization purposes
+			//
+			if (DW == 8)
+				f_axi_rd_cksize <= 0;
+			else if (DW == 16)
+				f_axi_rd_cksize <= 1;
+			else if (DW == 32)
+				f_axi_rd_cksize <= 2;
+			else if (DW == 64)
+				f_axi_rd_cksize <= 3;
+			else if (DW == 128)
+				f_axi_rd_cksize <= 4;
+			else if (DW == 256)
+				f_axi_rd_cksize <= 5;
+			else if (DW == 512)
+				f_axi_rd_cksize <= 6;
+			else // if (DW == 1024)
+				f_axi_rd_cksize <= 7;
+		end
+	end
+
+	//
+	// Read induction properties
+	//
+	// These are actual assert()s and not `SLAVE_ASSERT or `SLAVE_ASSUMEs
+	// because they are testing the functionality of this core and its local
+	// logical registers, not so much the functionality of the core we are
+	// testing
+	//
+	// ...
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Exclusive properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	generate if (!OPT_EXCLUSIVE)
+	begin : EXCLUSIVE_DISALLOWED
+		localparam [1:0]	EXOKAY = 2'b01;
+
+		//
+		// Without exclusive access support, the master shall not issue
+		// exclusive access requests
+		always @(*)
+		begin
+		`SLAVE_ASSUME(!i_axi_awvalid || !i_axi_awlock);
+		`SLAVE_ASSUME(!i_axi_arvalid || !i_axi_arlock);
+		end
+
+		// Similarly, without exclusive access support, the slave
+		// shall not respond with an okay indicating that exclusive
+		// access was supported.
+		always @(*)
+		begin
+		`SLAVE_ASSERT(!i_axi_bvalid || i_axi_bresp != EXOKAY);
+		`SLAVE_ASSERT(!i_axi_rvalid || i_axi_rresp != EXOKAY);
+		end
+
+	end else begin : EXCLUSIVE_ACCESS_CHECKER
+
+		//
+		// 1. Exclusive access burst lengths max out at 16
+		// 2. Exclusive access bursts must be aligned
+		// 3. Write must take place when the read channel is idle (on
+		//	this ID)
+		// (4. Further read accesses on this ID are not allowed)
+		//
+		always @(*)
+		if (i_axi_awvalid && i_axi_awlock)
+		begin
+			// ...
+		end
+
+		always @(*)
+		if (i_axi_arvalid && i_axi_arlock)
+		begin
+			// ...
+		end
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// ...
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Option for no bursts, only single transactions
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	generate if (!F_OPT_BURSTS)
+	begin
+
+		always @(*)
+		if (i_axi_awvalid)
+			`SLAVE_ASSUME(i_axi_awlen == 0);
+
+		always @(*)
+		if (i_axi_wvalid)
+			`SLAVE_ASSUME(i_axi_wlast);
+
+		always @(*)
+			assert(f_axi_wr_pending <= 1);
+
+		always @(*)
+			assert(f_axi_wr_len == 0);
+
+		always @(*)
+		if (i_axi_arvalid)
+			`SLAVE_ASSUME(i_axi_arlen == 0);
+
+		always @(*)
+		if (i_axi_rvalid)
+			`SLAVE_ASSERT(i_axi_rlast);
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_rd_nbursts == f_axi_rd_outstanding);
+		//
+		// ...
+		//
+	end endgenerate
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Packet read checking
+	//
+	// Pick a read address request, and then track that one transaction
+	// through the system
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	//
+	// ...
+	//
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxil_master.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxil_master.v
new file mode 100644
index 0000000..23e7c0f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxil_master.v
@@ -0,0 +1,814 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	faxil_master.v (Formal properties of an AXI lite master)
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2018-2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// }}}
+module faxil_master #(
+	// {{{
+	parameter  C_AXI_DATA_WIDTH	= 32,// Fixed, width of the AXI R&W data
+	parameter  C_AXI_ADDR_WIDTH	= 28,// AXI Address width (log wordsize)
+	// F_OPT_XILINX, Certain Xilinx cores impose additional rules upon AXI
+	// write transactions, limiting how far the write and write address
+	// can be apart.  If F_OPT_XILINX is set, these rules will be applied
+	// here as well.  See in-line for more details.
+	parameter [0:0]	F_OPT_XILINX = 1'b0,
+	parameter [0:0]	F_OPT_HAS_CACHE = 1'b0,
+	// F_OPT_WRITE_ONLY, if set, will assume the master is always idle on
+	// te read channel, allowing you to test/focus on the write interface
+	parameter [0:0]	F_OPT_WRITE_ONLY  = 1'b0,
+	// F_OPT_READ_ONLY, if set, will assume the master is always idle on
+	// the write channel, while asserting that all of the associated returns
+	// and counters are zero
+	parameter [0:0]	F_OPT_READ_ONLY = 1'b0,
+	// F_OPT_BRESP: Allow any type of write response.  If set clear, then
+	// error responses are disallowed.
+	parameter [0:0]	F_OPT_BRESP = 1'b1,
+	// F_OPT_RRESP, if cleared, will disallow error responses
+	parameter [0:0]	F_OPT_RRESP = 1'b1,
+	// F_OPT_ASSUME_RESET, if set, will cause the design to *assume* the
+	// existence of a correct reset, rather than asserting it.  It is
+	// appropriate anytime the reset logic is outside of the circuit being
+	// examined
+	parameter [0:0]			F_OPT_ASSUME_RESET = 1'b0,
+	parameter [0:0]			F_OPT_NO_RESET = F_OPT_ASSUME_RESET,
+	//
+	// F_OPT_ASYNC_RESET is for those designs that will reset the channels
+	// using an asynchronous reset.  In these cases, the stability
+	// properties only apply when the async reset is not asserted.
+	// Likewise, when F_OPT_ASYNC_RESET is set, the reset assertions are
+	// applied *on the same clock cycle*, in addition to one cycle later.
+	parameter [0:0]			F_OPT_ASYNC_RESET = 1'b0,
+	parameter 			F_OPT_COVER_BURST = 0,
+	// F_LGDEPTH is the number of bits necessary to count the maximum
+	// number of items in flight.
+	parameter			F_LGDEPTH	= 4,
+	// F_AXI_MAXWAIT is the maximum number of clock cycles the
+	// master should have to wait for a slave to raise its ready flag to
+	// accept a request.  Set to zero for no limit.
+	parameter			F_AXI_MAXWAIT  = 12,
+	// F_AXI_MAXRSTALL is the maximum number of clock cycles the
+	// slave should have to wait with a return valid signal high, but
+	// while the master's return ready signal is low.  Set to zero for no
+	// limit.
+	parameter			F_AXI_MAXRSTALL= 12,
+	// F_AXI_MAXDELAY is the maximum number of clock cycles between request
+	// and response within the slave.  Set this to zero for no limit.
+	parameter			F_AXI_MAXDELAY = 12,
+
+	//
+	localparam DW			= C_AXI_DATA_WIDTH,
+	localparam AW			= C_AXI_ADDR_WIDTH
+	// }}}
+	) (
+	input	wire			i_clk,	// System clock
+	input	wire			i_axi_reset_n,
+
+// AXI write address channel signals
+	input	wire			i_axi_awready,//Slave is ready to accept
+	input	wire	[AW-1:0]	i_axi_awaddr,	// Write address
+	input	wire	[3:0]		i_axi_awcache,	// Write Cache type
+	input	wire	[2:0]		i_axi_awprot,	// Write Protection type
+	input	wire			i_axi_awvalid,	// Write address valid
+
+// AXI write data channel signals
+	input	wire			i_axi_wready,  // Write data ready
+	input	wire	[DW-1:0]	i_axi_wdata,	// Write data
+	input	wire	[DW/8-1:0]	i_axi_wstrb,	// Write strobes
+	input	wire			i_axi_wvalid,	// Write valid
+
+// AXI write response channel signals
+	input	wire	[1:0]		i_axi_bresp,	// Write response
+	input	wire			i_axi_bvalid,  // Write reponse valid
+	input	wire			i_axi_bready,  // Response ready
+
+// AXI read address channel signals
+	input	wire			i_axi_arready,	// Read address ready
+	input	wire	[AW-1:0]	i_axi_araddr,	// Read address
+	input	wire	[3:0]		i_axi_arcache,	// Read Cache type
+	input	wire	[2:0]		i_axi_arprot,	// Read Protection type
+	input	wire			i_axi_arvalid,	// Read address valid
+
+// AXI read data channel signals
+	input	wire	[1:0]		i_axi_rresp,   // Read response
+	input	wire			i_axi_rvalid,  // Read reponse valid
+	input	wire	[DW-1:0]	i_axi_rdata,   // Read data
+	input	wire			i_axi_rready,  // Read Response ready
+	//
+	output	reg	[(F_LGDEPTH-1):0]	f_axi_rd_outstanding,
+	output	reg	[(F_LGDEPTH-1):0]	f_axi_wr_outstanding,
+	output	reg	[(F_LGDEPTH-1):0]	f_axi_awr_outstanding
+);
+
+	localparam	MAX_SLAVE_TIMEOUT = (F_AXI_MAXWAIT > F_AXI_MAXDELAY)
+				? (F_AXI_MAXWAIT) : F_AXI_MAXDELAY;
+	localparam	MAX_TIMEOUT = (F_AXI_MAXRSTALL>MAX_SLAVE_TIMEOUT)
+				? (F_AXI_MAXRSTALL) : MAX_SLAVE_TIMEOUT;
+	localparam	LGTIMEOUT = $clog2(MAX_TIMEOUT+1);
+
+//*****************************************************************************
+// Parameter declarations
+//*****************************************************************************
+
+//*****************************************************************************
+// Internal register and wire declarations
+//*****************************************************************************
+
+	// wire	w_fifo_full;
+	wire	axi_rd_ack, axi_wr_ack, axi_ard_req, axi_awr_req, axi_wr_req,
+		axi_rd_err, axi_wr_err;
+	//
+	assign	axi_ard_req = (i_axi_arvalid)&&(i_axi_arready);
+	assign	axi_awr_req = (i_axi_awvalid)&&(i_axi_awready);
+	assign	axi_wr_req  = (i_axi_wvalid )&&(i_axi_wready);
+	//
+	assign	axi_rd_ack = (i_axi_rvalid)&&(i_axi_rready);
+	assign	axi_wr_ack = (i_axi_bvalid)&&(i_axi_bready);
+	assign	axi_rd_err = (axi_rd_ack)&&(i_axi_rresp[1]);
+	assign	axi_wr_err = (axi_wr_ack)&&(i_axi_bresp[1]);
+
+`define	SLAVE_ASSUME	assert
+`define	SLAVE_ASSERT	assume
+
+	//
+	// Setup
+	//
+	reg	f_past_valid;
+	integer	k;
+
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Reset properties
+	//
+	// Insist that the reset signal start out asserted (negative), and
+	// remain so for 16 clocks.
+	//
+	////////////////////////////////////////////////////////////////////////
+	generate if (F_OPT_ASSUME_RESET)
+	begin : ASSUME_INITIAL_RESET
+		always @(*)
+		if (!f_past_valid)
+			assume(!i_axi_reset_n);
+	end else begin : ASSERT_INITIAL_RESET
+		always @(*)
+		if (!f_past_valid)
+			assert(!i_axi_reset_n);
+	end endgenerate
+
+
+	//
+	// If asserted, the reset must be asserted for a minimum of 16 clocks
+	reg	[3:0]	f_reset_length;
+	initial	f_reset_length = 0;
+	always @(posedge i_clk)
+	if (F_OPT_NO_RESET || i_axi_reset_n)
+		f_reset_length <= 0;
+	else if (!(&f_reset_length))
+		f_reset_length <= f_reset_length + 1'b1;
+
+
+	//
+	// If the reset is not generated within this particular core, then it
+	// can be assumed if F_OPT_ASSUME_RESET is set
+	generate if (F_OPT_ASSUME_RESET && !F_OPT_NO_RESET)
+	begin : ASSUME_RESET
+		always @(posedge i_clk)
+		if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length)))
+			assume(!i_axi_reset_n);
+
+		always @(*)
+		if ((f_reset_length > 0)&&(f_reset_length < 4'hf))
+			assume(!i_axi_reset_n);
+
+	end else if (!F_OPT_NO_RESET)
+	begin : ASSERT_RESET
+
+		always @(posedge i_clk)
+		if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length)))
+			assert(!i_axi_reset_n);
+
+		always @(*)
+		if ((f_reset_length > 0)&&(f_reset_length < 4'hf))
+			assert(!i_axi_reset_n);
+
+	end endgenerate
+
+	//
+	// All of the xVALID signals *MUST* be set low on the clock following
+	// a reset.  Not in the spec, but also checked here is that they must
+	// also be set low initially.
+	always @(posedge i_clk)
+	if ((!f_past_valid)||(!$past(i_axi_reset_n)))
+	begin
+		`SLAVE_ASSUME(!i_axi_arvalid);
+		`SLAVE_ASSUME(!i_axi_awvalid);
+		`SLAVE_ASSUME(!i_axi_wvalid);
+		//
+		`SLAVE_ASSERT(!i_axi_bvalid);
+		`SLAVE_ASSERT(!i_axi_rvalid);
+	end
+
+	generate if (F_OPT_ASYNC_RESET)
+	begin
+		always @(*)
+		if (!i_axi_reset_n)
+		begin
+			`SLAVE_ASSUME(!i_axi_arvalid);
+			`SLAVE_ASSUME(!i_axi_awvalid);
+			`SLAVE_ASSUME(!i_axi_wvalid);
+			//
+			`SLAVE_ASSERT(!i_axi_bvalid);
+			`SLAVE_ASSERT(!i_axi_rvalid);
+		end
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Constant input assumptions (AxCACHE and AxPROT)
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	always @(*)
+	if (i_axi_awvalid)
+	begin
+		`SLAVE_ASSUME(i_axi_awprot  == 3'h0);
+		if (F_OPT_HAS_CACHE)
+			// Normal non-cachable, but bufferable
+			`SLAVE_ASSUME(i_axi_awcache == 4'h3);
+		else
+			// No caching capability
+			`SLAVE_ASSUME(i_axi_awcache == 4'h0);
+	end
+
+	always @(*)
+	if (i_axi_arvalid)
+	begin
+		`SLAVE_ASSUME(i_axi_arprot  == 3'h0);
+		if (F_OPT_HAS_CACHE)
+			// Normal non-cachable, but bufferable
+			`SLAVE_ASSUME(i_axi_arcache == 4'h3);
+		else
+			// No caching capability
+			`SLAVE_ASSUME(i_axi_arcache == 4'h0);
+	end
+
+	always @(*)
+	if ((i_axi_bvalid)&&(!F_OPT_BRESP))
+		`SLAVE_ASSERT(i_axi_bresp == 0);
+	always @(*)
+	if ((i_axi_rvalid)&&(!F_OPT_RRESP))
+		`SLAVE_ASSERT(i_axi_rresp == 0);
+	always @(*)
+	if (i_axi_bvalid)
+		`SLAVE_ASSERT(i_axi_bresp != 2'b01); // Exclusive access not allowed
+	always @(*)
+	if (i_axi_rvalid)
+		`SLAVE_ASSERT(i_axi_rresp != 2'b01); // Exclusive access not allowed
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Stability properties--what happens if valid and not ready
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	// Assume any response from the bus will not change prior to that
+	// response being accepted
+	always @(posedge i_clk)
+	if ((f_past_valid)&&($past(i_axi_reset_n))
+			&&(!F_OPT_ASYNC_RESET || i_axi_reset_n))
+	begin
+		// Write address channel
+		if ((f_past_valid)&&($past(i_axi_awvalid && !i_axi_awready)))
+		begin
+			`SLAVE_ASSUME(i_axi_awvalid);
+			`SLAVE_ASSUME($stable(i_axi_awaddr));
+		end
+
+		// Write data channel
+		if ((f_past_valid && (!F_OPT_ASYNC_RESET || i_axi_reset_n))
+				&&($past(i_axi_wvalid && !i_axi_wready)))
+		begin
+			`SLAVE_ASSUME(i_axi_wvalid);
+			`SLAVE_ASSUME($stable(i_axi_wstrb));
+			`SLAVE_ASSUME($stable(i_axi_wdata));
+		end
+
+		// Incoming Read address channel
+		if ((f_past_valid && (!F_OPT_ASYNC_RESET || i_axi_reset_n))
+			&&($past(i_axi_arvalid && !i_axi_arready)))
+		begin
+			`SLAVE_ASSUME(i_axi_arvalid);
+			`SLAVE_ASSUME($stable(i_axi_araddr));
+		end
+
+		if ((f_past_valid && (!F_OPT_ASYNC_RESET || i_axi_reset_n))
+			&&($past(i_axi_rvalid && !i_axi_rready)))
+		begin
+			`SLAVE_ASSERT(i_axi_rvalid);
+			`SLAVE_ASSERT($stable(i_axi_rresp));
+			`SLAVE_ASSERT($stable(i_axi_rdata));
+		end
+
+		if ((f_past_valid && (!F_OPT_ASYNC_RESET || i_axi_reset_n))
+			&&($past(i_axi_bvalid && !i_axi_bready)))
+		begin
+			`SLAVE_ASSERT(i_axi_bvalid);
+			`SLAVE_ASSERT($stable(i_axi_bresp));
+		end
+	end
+
+	// Nothing should be returned or requested on the first clock
+	initial	`SLAVE_ASSUME(!i_axi_arvalid);
+	initial	`SLAVE_ASSUME(!i_axi_awvalid);
+	initial	`SLAVE_ASSUME(!i_axi_wvalid);
+	//
+	initial	`SLAVE_ASSERT(!i_axi_bvalid);
+	initial	`SLAVE_ASSERT(!i_axi_rvalid);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Insist upon a maximum delay before a request is accepted
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	generate if (F_AXI_MAXWAIT > 0)
+	begin : CHECK_STALL_COUNT
+		reg	[LGTIMEOUT-1:0]		f_axi_awstall,
+						f_axi_wstall,
+						f_axi_arstall;
+
+		//
+		// AXI write address channel
+		//
+		// Count the number of times AWVALID is true while AWREADY
+		// is false.  These are stalls, and we want to insist on a
+		// minimum number of them.  However, if BVALID && !BREADY,
+		// then there's a reason for not accepting anything more.
+		// Similarly, many cores will only ever accept one request
+		// at a time, hence we won't count things as stalls if
+		// WR-PENDING > 0.
+		initial	f_axi_awstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_awvalid)||(i_axi_awready)
+				||(i_axi_bvalid))
+			f_axi_awstall <= 0;
+		else if ((f_axi_awr_outstanding >= f_axi_wr_outstanding)
+			&&(i_axi_awvalid && !i_axi_wvalid))
+			// If we are waiting for the write channel to be valid
+			// then don't count stalls
+			f_axi_awstall <= 0;
+		else
+			f_axi_awstall <= f_axi_awstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_awstall < F_AXI_MAXWAIT);
+
+		//
+		// AXI write data channel
+		//
+		// Count the number of clock cycles that the write data
+		// channel is stalled, that is while WVALID && !WREADY.
+		// Since things can back up if BVALID & !BREADY, we avoid
+		// counting clock cycles in that circumstance
+		initial	f_axi_wstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_wvalid)||(i_axi_wready)
+				||(i_axi_bvalid))
+			f_axi_wstall <= 0;
+		else if ((f_axi_wr_outstanding >= f_axi_awr_outstanding)
+			&&(!i_axi_awvalid && i_axi_wvalid))
+			// If we are waiting for the write address channel
+			// to be valid, then don't count stalls
+			f_axi_wstall <= 0;
+		else
+			f_axi_wstall <= f_axi_wstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_wstall < F_AXI_MAXWAIT);
+
+		//
+		// AXI read address channel
+		//
+		// Similar to the first two above, once the master raises
+		// ARVALID, insist that the slave respond within a minimum
+		// number of clock cycles.  Exceptions include any time
+		// RVALID is true, since that can back up the whole system,
+		// and any time the number of bursts is greater than zero,
+		// since many slaves can only accept one request at a time.
+		initial	f_axi_arstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_arvalid)||(i_axi_arready)
+				||(i_axi_rvalid))
+			f_axi_arstall <= 0;
+		else
+			f_axi_arstall <= f_axi_arstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_arstall < F_AXI_MAXWAIT);
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Insist upon a maximum delay before any response is accepted
+	//
+	// These are separate from the earlier ones, in case you wish to
+	// control them separately.  For example, an interconnect might be
+	// forced to let a channel wait indefinitely for access, but it might
+	// not be appropriate to require the response to be able to wait
+	// indefinitely as well
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	generate if (F_AXI_MAXRSTALL > 0)
+	begin : CHECK_RESPONSE_STALLS
+		reg	[LGTIMEOUT-1:0]		f_axi_bstall,
+						f_axi_rstall;
+
+		// AXI write response channel
+		//
+		// Insist on a maximum number of clocks that BVALID can be
+		// high while BREADY is low
+		initial	f_axi_bstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_bvalid)||(i_axi_bready))
+			f_axi_bstall <= 0;
+		else
+			f_axi_bstall <= f_axi_bstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSUME(f_axi_bstall < F_AXI_MAXRSTALL);
+
+		// AXI read response channel
+		//
+		// Insist on a maximum number of clocks that RVALID can be
+		// high while RREADY is low
+		initial	f_axi_rstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_rvalid)||(i_axi_rready))
+			f_axi_rstall <= 0;
+		else
+			f_axi_rstall <= f_axi_rstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSUME(f_axi_rstall < F_AXI_MAXRSTALL);
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Xilinx extensions/guarantees to the AXI protocol
+	//
+	//	1. The address line will never be more than two clocks ahead of
+	//		the write data channel, and
+	//	2. The write data channel will never be more than one clock
+	//		ahead of the address channel.
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate if (F_OPT_XILINX)
+	begin
+		// Rule number one:
+		always @(posedge i_clk)
+		if ((i_axi_reset_n)&&($past(i_axi_reset_n))
+			&&($past(i_axi_awvalid && !i_axi_wvalid,2))
+				&&($past(f_axi_awr_outstanding>=f_axi_wr_outstanding,2))
+				&&(!$past(i_axi_wvalid)))
+			`SLAVE_ASSUME(i_axi_wvalid);
+
+		always @(posedge i_clk)
+		if ((i_axi_reset_n)
+				&&(f_axi_awr_outstanding > 1)
+				&&(f_axi_awr_outstanding-1 > f_axi_wr_outstanding))
+			`SLAVE_ASSUME(i_axi_wvalid);
+
+		always @(posedge i_clk)
+		if ((i_axi_reset_n)
+				&&($past(f_axi_awr_outstanding > f_axi_wr_outstanding))
+				&&(!$past(axi_wr_req)))
+			`SLAVE_ASSUME(i_axi_wvalid);
+
+
+		// Rule number two:
+		always @(posedge i_clk)
+		if ((i_axi_reset_n)&&(f_axi_awr_outstanding < f_axi_wr_outstanding))
+			`SLAVE_ASSUME(i_axi_awvalid);
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Count outstanding transactions.  With these measures, we count
+	// once per any burst.
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// Count outstanding write address channel requests
+	initial	f_axi_awr_outstanding = 0;
+	always @(posedge i_clk)
+	if (!i_axi_reset_n)
+		f_axi_awr_outstanding <= 0;
+	else case({ (axi_awr_req), (axi_wr_ack) })
+		2'b10: f_axi_awr_outstanding <= f_axi_awr_outstanding + 1'b1;
+		2'b01: f_axi_awr_outstanding <= f_axi_awr_outstanding - 1'b1;
+		default: begin end
+	endcase
+
+	//
+	// Count outstanding write data channel requests
+	initial	f_axi_wr_outstanding = 0;
+	always @(posedge i_clk)
+	if (!i_axi_reset_n)
+		f_axi_wr_outstanding <= 0;
+	else case({ (axi_wr_req), (axi_wr_ack) })
+	2'b01: f_axi_wr_outstanding <= f_axi_wr_outstanding - 1'b1;
+	2'b10: f_axi_wr_outstanding <= f_axi_wr_outstanding + 1'b1;
+	endcase
+
+	//
+	// Count outstanding read requests
+	initial	f_axi_rd_outstanding = 0;
+	always @(posedge i_clk)
+	if (!i_axi_reset_n)
+		f_axi_rd_outstanding <= 0;
+	else case({ (axi_ard_req), (axi_rd_ack) })
+	2'b01: f_axi_rd_outstanding <= f_axi_rd_outstanding - 1'b1;
+	2'b10: f_axi_rd_outstanding <= f_axi_rd_outstanding + 1'b1;
+	endcase
+
+	//
+	// Do not let the number of outstanding requests overflow
+	always @(posedge i_clk)
+		`SLAVE_ASSERT(f_axi_wr_outstanding  < {(F_LGDEPTH){1'b1}});
+	always @(posedge i_clk)
+		`SLAVE_ASSERT(f_axi_awr_outstanding < {(F_LGDEPTH){1'b1}});
+	always @(posedge i_clk)
+		`SLAVE_ASSERT(f_axi_rd_outstanding  < {(F_LGDEPTH){1'b1}});
+
+	//
+	// That means that requests need to stop when we're almost full
+	always @(posedge i_clk)
+	if (f_axi_awr_outstanding == { {(F_LGDEPTH-1){1'b1}}, 1'b0} )
+		assert(!i_axi_awvalid);
+	always @(posedge i_clk)
+	if (f_axi_wr_outstanding == { {(F_LGDEPTH-1){1'b1}}, 1'b0} )
+		assert(!i_axi_wvalid);
+	always @(posedge i_clk)
+	if (f_axi_rd_outstanding == { {(F_LGDEPTH-1){1'b1}}, 1'b0} )
+		assert(!i_axi_arvalid);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Insist that all responses are returned in less than a maximum delay
+	// In this case, we count responses within a burst, rather than entire
+	// bursts.
+	//
+	//
+	// A unique feature to the backpressure mechanism within AXI is that
+	// we have to reset our delay counters in the case of any push back,
+	// since the response can't move forward if the master isn't (yet)
+	// ready for it.
+	//
+	////////////////////////////////////////////////////////////////////////
+	generate if (F_AXI_MAXDELAY > 0)
+	begin : CHECK_MAX_DELAY
+
+		reg	[LGTIMEOUT-1:0]		f_axi_wr_ack_delay,
+						f_axi_rd_ack_delay;
+
+		//
+		// Count the clock cycles a write request (address + data) has
+		// been outstanding and without any response
+		initial	f_axi_wr_ack_delay = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(i_axi_bvalid)
+				||(f_axi_awr_outstanding==0)
+				||(f_axi_wr_outstanding==0))
+			f_axi_wr_ack_delay <= 0;
+		else if (f_axi_wr_outstanding > 0)
+			f_axi_wr_ack_delay <= f_axi_wr_ack_delay + 1'b1;
+
+		//
+		// Count the clock cycles that any read request has been
+		// outstanding, but without any response.
+		initial	f_axi_rd_ack_delay = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(i_axi_rvalid)||(f_axi_rd_outstanding==0))
+			f_axi_rd_ack_delay <= 0;
+		else
+			f_axi_rd_ack_delay <= f_axi_rd_ack_delay + 1'b1;
+
+
+		//
+		// Assert that write responses will be returned in a timely
+		// fashion
+		always @(*)
+			`SLAVE_ASSERT(f_axi_wr_ack_delay < F_AXI_MAXDELAY);
+
+		//
+		// Assert that read responses will be returned in a timely
+		// fashion
+		always @(*)
+			`SLAVE_ASSERT(f_axi_rd_ack_delay < F_AXI_MAXDELAY);
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Assume acknowledgements must follow requests
+	//
+	// The f_axi*outstanding counters count the number of requests.  No
+	// acknowledgment should issue without a pending request
+	// burst.  Further, the spec is clear: you can't acknowledge something
+	// on the same clock you get the request.  There must be at least one
+	// clock delay.
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	//
+	// AXI write response channel
+	//
+	always @(posedge i_clk)
+	if (i_axi_bvalid)
+	begin
+		// No BVALID w/o an outstanding request
+		`SLAVE_ASSERT(f_axi_awr_outstanding > 0);
+		`SLAVE_ASSERT(f_axi_wr_outstanding  > 0);
+	end
+
+	//
+	// AXI read data channel signals
+	//
+	always @(posedge i_clk)
+	if (i_axi_rvalid)
+		// No RVALID w/o an outstanding request
+		`SLAVE_ASSERT(f_axi_rd_outstanding > 0);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// F_OPT_WRITE_ONLY or F_OPT_READ_ONLY
+	//
+	// Optionally disable either read or write channels (or both??)
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	initial	assert((!F_OPT_WRITE_ONLY)||(!F_OPT_READ_ONLY));
+
+	generate if (F_OPT_WRITE_ONLY)
+	begin : NO_READS
+
+		// If there are no read requests (assumed), there should be
+		// no read responses
+		always @(*)
+			`SLAVE_ASSUME(i_axi_arvalid == 0);
+		always @(*)
+			assert(f_axi_rd_outstanding == 0);
+		always @(*)
+			`SLAVE_ASSERT(i_axi_rvalid == 0);
+
+	end endgenerate
+
+	generate if (F_OPT_READ_ONLY)
+	begin : NO_WRITES
+
+		// If there are no write requests (assumed, address or data),
+		// there should be no read responses
+		always @(*)
+			`SLAVE_ASSUME(i_axi_awvalid == 0);
+		always @(*)
+			`SLAVE_ASSUME(i_axi_wvalid == 0);
+		always @(*)
+			assert(f_axi_wr_outstanding == 0);
+		always @(*)
+			assert(f_axi_awr_outstanding == 0);
+		always @(*)
+			`SLAVE_ASSERT(i_axi_bvalid == 0);
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Cover properties
+	//
+	// We'll use this to prove that transactions are even possible, and
+	// hence that we haven't so constrained the bus that nothing can take
+	// place.
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	//
+	// AXI write response channel
+	//
+	generate if (!F_OPT_READ_ONLY)
+	begin
+		always @(posedge i_clk)
+			// Make sure we can get a write acknowledgment
+			cover((i_axi_bvalid)&&(i_axi_bready));
+	end endgenerate
+
+	//
+	// AXI read response channel
+	//
+	generate if (!F_OPT_WRITE_ONLY)
+	begin
+		always @(posedge i_clk)
+			// Make sure we can get a response from the read channel
+			cover((i_axi_rvalid)&&(i_axi_rready));
+	end endgenerate
+
+	generate if (!F_OPT_READ_ONLY && F_OPT_COVER_BURST > 0)
+	begin : COVER_WRITE_BURSTS
+
+		reg	[31:0]	cvr_writes;
+
+		initial	cvr_writes = 0;
+		always @(posedge i_clk)
+		if (!i_axi_reset_n)
+			cvr_writes <= 0;
+		else if (i_axi_bvalid && i_axi_bready && i_axi_bresp == 2'b00
+				&& !(&cvr_writes))
+			cvr_writes <= cvr_writes + 1;
+
+		always @(*)
+			cover(cvr_writes == F_OPT_COVER_BURST);
+
+	end endgenerate
+
+	generate if (!F_OPT_WRITE_ONLY && F_OPT_COVER_BURST > 0)
+	begin : COVER_READ_BURSTS
+
+		reg	[31:0]	cvr_reads;
+
+		initial	cvr_reads = 0;
+		always @(posedge i_clk)
+		if (!i_axi_reset_n)
+			cvr_reads <= 0;
+		else if (i_axi_rvalid && i_axi_rready && i_axi_rresp == 2'b00
+				&& !(&cvr_reads))
+			cvr_reads <= cvr_reads + 1;
+
+		always @(*)
+			cover(cvr_reads == F_OPT_COVER_BURST);
+
+	end endgenerate
+
+`undef	SLAVE_ASSUME
+`undef	SLAVE_ASSERT
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxil_slave.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxil_slave.v
new file mode 100644
index 0000000..f53cc59
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxil_slave.v
@@ -0,0 +1,814 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	faxil_slave.v (Formal properties of an AXI lite slave)
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2018-2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// }}}
+module faxil_slave #(
+	// {{{
+	parameter  C_AXI_DATA_WIDTH	= 32,// Fixed, width of the AXI R&W data
+	parameter  C_AXI_ADDR_WIDTH	= 28,// AXI Address width (log wordsize)
+	// F_OPT_XILINX, Certain Xilinx cores impose additional rules upon AXI
+	// write transactions, limiting how far the write and write address
+	// can be apart.  If F_OPT_XILINX is set, these rules will be applied
+	// here as well.  See in-line for more details.
+	parameter [0:0]	F_OPT_XILINX = 1'b0,
+	parameter [0:0]	F_OPT_HAS_CACHE = 1'b0,
+	// F_OPT_WRITE_ONLY, if set, will assume the master is always idle on
+	// te read channel, allowing you to test/focus on the write interface
+	parameter [0:0]	F_OPT_WRITE_ONLY  = 1'b0,
+	// F_OPT_READ_ONLY, if set, will assume the master is always idle on
+	// the write channel, while asserting that all of the associated returns
+	// and counters are zero
+	parameter [0:0]	F_OPT_READ_ONLY = 1'b0,
+	// F_OPT_BRESP: Allow any type of write response.  If set clear, then
+	// error responses are disallowed.
+	parameter [0:0]	F_OPT_BRESP = 1'b1,
+	// F_OPT_RRESP, if cleared, will disallow error responses
+	parameter [0:0]	F_OPT_RRESP = 1'b1,
+	// F_OPT_ASSUME_RESET, if set, will cause the design to *assume* the
+	// existence of a correct reset, rather than asserting it.  It is
+	// appropriate anytime the reset logic is outside of the circuit being
+	// examined
+	parameter [0:0]			F_OPT_ASSUME_RESET = 1'b1,
+	parameter [0:0]			F_OPT_NO_RESET = 1'b1,
+	//
+	// F_OPT_ASYNC_RESET is for those designs that will reset the channels
+	// using an asynchronous reset.  In these cases, the stability
+	// properties only apply when the async reset is not asserted.
+	// Likewise, when F_OPT_ASYNC_RESET is set, the reset assertions are
+	// applied *on the same clock cycle*, in addition to one cycle later.
+	parameter [0:0]			F_OPT_ASYNC_RESET = 1'b0,
+	parameter 			F_OPT_COVER_BURST = 0,
+	// F_LGDEPTH is the number of bits necessary to count the maximum
+	// number of items in flight.
+	parameter			F_LGDEPTH	= 4,
+	// F_AXI_MAXWAIT is the maximum number of clock cycles the
+	// master should have to wait for a slave to raise its ready flag to
+	// accept a request.  Set to zero for no limit.
+	parameter			F_AXI_MAXWAIT  = 12,
+	// F_AXI_MAXRSTALL is the maximum number of clock cycles the
+	// slave should have to wait with a return valid signal high, but
+	// while the master's return ready signal is low.  Set to zero for no
+	// limit.
+	parameter			F_AXI_MAXRSTALL= 12,
+	// F_AXI_MAXDELAY is the maximum number of clock cycles between request
+	// and response within the slave.  Set this to zero for no limit.
+	parameter			F_AXI_MAXDELAY = 12,
+
+	//
+	localparam DW			= C_AXI_DATA_WIDTH,
+	localparam AW			= C_AXI_ADDR_WIDTH
+	// }}}
+	) (
+	input	wire			i_clk,	// System clock
+	input	wire			i_axi_reset_n,
+
+// AXI write address channel signals
+	input	wire			i_axi_awready,//Slave is ready to accept
+	input	wire	[AW-1:0]	i_axi_awaddr,	// Write address
+	input	wire	[3:0]		i_axi_awcache,	// Write Cache type
+	input	wire	[2:0]		i_axi_awprot,	// Write Protection type
+	input	wire			i_axi_awvalid,	// Write address valid
+
+// AXI write data channel signals
+	input	wire			i_axi_wready,  // Write data ready
+	input	wire	[DW-1:0]	i_axi_wdata,	// Write data
+	input	wire	[DW/8-1:0]	i_axi_wstrb,	// Write strobes
+	input	wire			i_axi_wvalid,	// Write valid
+
+// AXI write response channel signals
+	input	wire	[1:0]		i_axi_bresp,	// Write response
+	input	wire			i_axi_bvalid,  // Write reponse valid
+	input	wire			i_axi_bready,  // Response ready
+
+// AXI read address channel signals
+	input	wire			i_axi_arready,	// Read address ready
+	input	wire	[AW-1:0]	i_axi_araddr,	// Read address
+	input	wire	[3:0]		i_axi_arcache,	// Read Cache type
+	input	wire	[2:0]		i_axi_arprot,	// Read Protection type
+	input	wire			i_axi_arvalid,	// Read address valid
+
+// AXI read data channel signals
+	input	wire	[1:0]		i_axi_rresp,   // Read response
+	input	wire			i_axi_rvalid,  // Read reponse valid
+	input	wire	[DW-1:0]	i_axi_rdata,   // Read data
+	input	wire			i_axi_rready,  // Read Response ready
+	//
+	output	reg	[(F_LGDEPTH-1):0]	f_axi_rd_outstanding,
+	output	reg	[(F_LGDEPTH-1):0]	f_axi_wr_outstanding,
+	output	reg	[(F_LGDEPTH-1):0]	f_axi_awr_outstanding
+);
+
+	localparam	MAX_SLAVE_TIMEOUT = (F_AXI_MAXWAIT > F_AXI_MAXDELAY)
+				? (F_AXI_MAXWAIT) : F_AXI_MAXDELAY;
+	localparam	MAX_TIMEOUT = (F_AXI_MAXRSTALL>MAX_SLAVE_TIMEOUT)
+				? (F_AXI_MAXRSTALL) : MAX_SLAVE_TIMEOUT;
+	localparam	LGTIMEOUT = $clog2(MAX_TIMEOUT+1);
+
+//*****************************************************************************
+// Parameter declarations
+//*****************************************************************************
+
+//*****************************************************************************
+// Internal register and wire declarations
+//*****************************************************************************
+
+	// wire	w_fifo_full;
+	wire	axi_rd_ack, axi_wr_ack, axi_ard_req, axi_awr_req, axi_wr_req,
+		axi_rd_err, axi_wr_err;
+	//
+	assign	axi_ard_req = (i_axi_arvalid)&&(i_axi_arready);
+	assign	axi_awr_req = (i_axi_awvalid)&&(i_axi_awready);
+	assign	axi_wr_req  = (i_axi_wvalid )&&(i_axi_wready);
+	//
+	assign	axi_rd_ack = (i_axi_rvalid)&&(i_axi_rready);
+	assign	axi_wr_ack = (i_axi_bvalid)&&(i_axi_bready);
+	assign	axi_rd_err = (axi_rd_ack)&&(i_axi_rresp[1]);
+	assign	axi_wr_err = (axi_wr_ack)&&(i_axi_bresp[1]);
+
+`define	SLAVE_ASSUME	assume
+`define	SLAVE_ASSERT	assert
+
+	//
+	// Setup
+	//
+	reg	f_past_valid;
+	integer	k;
+
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Reset properties
+	//
+	// Insist that the reset signal start out asserted (negative), and
+	// remain so for 16 clocks.
+	//
+	////////////////////////////////////////////////////////////////////////
+	generate if (F_OPT_ASSUME_RESET)
+	begin : ASSUME_INITIAL_RESET
+		always @(*)
+		if (!f_past_valid)
+			assume(!i_axi_reset_n);
+	end else begin : ASSERT_INITIAL_RESET
+		always @(*)
+		if (!f_past_valid)
+			assert(!i_axi_reset_n);
+	end endgenerate
+
+
+	//
+	// If asserted, the reset must be asserted for a minimum of 16 clocks
+	reg	[3:0]	f_reset_length;
+	initial	f_reset_length = 0;
+	always @(posedge i_clk)
+	if (F_OPT_NO_RESET || i_axi_reset_n)
+		f_reset_length <= 0;
+	else if (!(&f_reset_length))
+		f_reset_length <= f_reset_length + 1'b1;
+
+
+	//
+	// If the reset is not generated within this particular core, then it
+	// can be assumed if F_OPT_ASSUME_RESET is set
+	generate if (F_OPT_ASSUME_RESET && !F_OPT_NO_RESET)
+	begin : ASSUME_RESET
+		always @(posedge i_clk)
+		if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length)))
+			assume(!i_axi_reset_n);
+
+		always @(*)
+		if ((f_reset_length > 0)&&(f_reset_length < 4'hf))
+			assume(!i_axi_reset_n);
+
+	end else if (!F_OPT_NO_RESET)
+	begin : ASSERT_RESET
+
+		always @(posedge i_clk)
+		if ((f_past_valid)&&(!$past(i_axi_reset_n))&&(!$past(&f_reset_length)))
+			assert(!i_axi_reset_n);
+
+		always @(*)
+		if ((f_reset_length > 0)&&(f_reset_length < 4'hf))
+			assert(!i_axi_reset_n);
+
+	end endgenerate
+
+	//
+	// All of the xVALID signals *MUST* be set low on the clock following
+	// a reset.  Not in the spec, but also checked here is that they must
+	// also be set low initially.
+	always @(posedge i_clk)
+	if ((!f_past_valid)||(!$past(i_axi_reset_n)))
+	begin
+		`SLAVE_ASSUME(!i_axi_arvalid);
+		`SLAVE_ASSUME(!i_axi_awvalid);
+		`SLAVE_ASSUME(!i_axi_wvalid);
+		//
+		`SLAVE_ASSERT(!i_axi_bvalid);
+		`SLAVE_ASSERT(!i_axi_rvalid);
+	end
+
+	generate if (F_OPT_ASYNC_RESET)
+	begin
+		always @(*)
+		if (!i_axi_reset_n)
+		begin
+			`SLAVE_ASSUME(!i_axi_arvalid);
+			`SLAVE_ASSUME(!i_axi_awvalid);
+			`SLAVE_ASSUME(!i_axi_wvalid);
+			//
+			`SLAVE_ASSERT(!i_axi_bvalid);
+			`SLAVE_ASSERT(!i_axi_rvalid);
+		end
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Constant input assumptions (AxCACHE and AxPROT)
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	always @(*)
+	if (i_axi_awvalid)
+	begin
+		`SLAVE_ASSUME(i_axi_awprot  == 3'h0);
+		if (F_OPT_HAS_CACHE)
+			// Normal non-cachable, but bufferable
+			`SLAVE_ASSUME(i_axi_awcache == 4'h3);
+		else
+			// No caching capability
+			`SLAVE_ASSUME(i_axi_awcache == 4'h0);
+	end
+
+	always @(*)
+	if (i_axi_arvalid)
+	begin
+		`SLAVE_ASSUME(i_axi_arprot  == 3'h0);
+		if (F_OPT_HAS_CACHE)
+			// Normal non-cachable, but bufferable
+			`SLAVE_ASSUME(i_axi_arcache == 4'h3);
+		else
+			// No caching capability
+			`SLAVE_ASSUME(i_axi_arcache == 4'h0);
+	end
+
+	always @(*)
+	if ((i_axi_bvalid)&&(!F_OPT_BRESP))
+		`SLAVE_ASSERT(i_axi_bresp == 0);
+	always @(*)
+	if ((i_axi_rvalid)&&(!F_OPT_RRESP))
+		`SLAVE_ASSERT(i_axi_rresp == 0);
+	always @(*)
+	if (i_axi_bvalid)
+		`SLAVE_ASSERT(i_axi_bresp != 2'b01); // Exclusive access not allowed
+	always @(*)
+	if (i_axi_rvalid)
+		`SLAVE_ASSERT(i_axi_rresp != 2'b01); // Exclusive access not allowed
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Stability properties--what happens if valid and not ready
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	// Assume any response from the bus will not change prior to that
+	// response being accepted
+	always @(posedge i_clk)
+	if ((f_past_valid)&&($past(i_axi_reset_n))
+			&&(!F_OPT_ASYNC_RESET || i_axi_reset_n))
+	begin
+		// Write address channel
+		if ((f_past_valid)&&($past(i_axi_awvalid && !i_axi_awready)))
+		begin
+			`SLAVE_ASSUME(i_axi_awvalid);
+			`SLAVE_ASSUME($stable(i_axi_awaddr));
+		end
+
+		// Write data channel
+		if ((f_past_valid && (!F_OPT_ASYNC_RESET || i_axi_reset_n))
+				&&($past(i_axi_wvalid && !i_axi_wready)))
+		begin
+			`SLAVE_ASSUME(i_axi_wvalid);
+			`SLAVE_ASSUME($stable(i_axi_wstrb));
+			`SLAVE_ASSUME($stable(i_axi_wdata));
+		end
+
+		// Incoming Read address channel
+		if ((f_past_valid && (!F_OPT_ASYNC_RESET || i_axi_reset_n))
+			&&($past(i_axi_arvalid && !i_axi_arready)))
+		begin
+			`SLAVE_ASSUME(i_axi_arvalid);
+			`SLAVE_ASSUME($stable(i_axi_araddr));
+		end
+
+		if ((f_past_valid && (!F_OPT_ASYNC_RESET || i_axi_reset_n))
+			&&($past(i_axi_rvalid && !i_axi_rready)))
+		begin
+			`SLAVE_ASSERT(i_axi_rvalid);
+			`SLAVE_ASSERT($stable(i_axi_rresp));
+			`SLAVE_ASSERT($stable(i_axi_rdata));
+		end
+
+		if ((f_past_valid && (!F_OPT_ASYNC_RESET || i_axi_reset_n))
+			&&($past(i_axi_bvalid && !i_axi_bready)))
+		begin
+			`SLAVE_ASSERT(i_axi_bvalid);
+			`SLAVE_ASSERT($stable(i_axi_bresp));
+		end
+	end
+
+	// Nothing should be returned or requested on the first clock
+	initial	`SLAVE_ASSUME(!i_axi_arvalid);
+	initial	`SLAVE_ASSUME(!i_axi_awvalid);
+	initial	`SLAVE_ASSUME(!i_axi_wvalid);
+	//
+	initial	`SLAVE_ASSERT(!i_axi_bvalid);
+	initial	`SLAVE_ASSERT(!i_axi_rvalid);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Insist upon a maximum delay before a request is accepted
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	generate if (F_AXI_MAXWAIT > 0)
+	begin : CHECK_STALL_COUNT
+		reg	[LGTIMEOUT-1:0]		f_axi_awstall,
+						f_axi_wstall,
+						f_axi_arstall;
+
+		//
+		// AXI write address channel
+		//
+		// Count the number of times AWVALID is true while AWREADY
+		// is false.  These are stalls, and we want to insist on a
+		// minimum number of them.  However, if BVALID && !BREADY,
+		// then there's a reason for not accepting anything more.
+		// Similarly, many cores will only ever accept one request
+		// at a time, hence we won't count things as stalls if
+		// WR-PENDING > 0.
+		initial	f_axi_awstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_awvalid)||(i_axi_awready)
+				||(i_axi_bvalid))
+			f_axi_awstall <= 0;
+		else if ((f_axi_awr_outstanding >= f_axi_wr_outstanding)
+			&&(i_axi_awvalid && !i_axi_wvalid))
+			// If we are waiting for the write channel to be valid
+			// then don't count stalls
+			f_axi_awstall <= 0;
+		else
+			f_axi_awstall <= f_axi_awstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_awstall < F_AXI_MAXWAIT);
+
+		//
+		// AXI write data channel
+		//
+		// Count the number of clock cycles that the write data
+		// channel is stalled, that is while WVALID && !WREADY.
+		// Since things can back up if BVALID & !BREADY, we avoid
+		// counting clock cycles in that circumstance
+		initial	f_axi_wstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_wvalid)||(i_axi_wready)
+				||(i_axi_bvalid))
+			f_axi_wstall <= 0;
+		else if ((f_axi_wr_outstanding >= f_axi_awr_outstanding)
+			&&(!i_axi_awvalid && i_axi_wvalid))
+			// If we are waiting for the write address channel
+			// to be valid, then don't count stalls
+			f_axi_wstall <= 0;
+		else
+			f_axi_wstall <= f_axi_wstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_wstall < F_AXI_MAXWAIT);
+
+		//
+		// AXI read address channel
+		//
+		// Similar to the first two above, once the master raises
+		// ARVALID, insist that the slave respond within a minimum
+		// number of clock cycles.  Exceptions include any time
+		// RVALID is true, since that can back up the whole system,
+		// and any time the number of bursts is greater than zero,
+		// since many slaves can only accept one request at a time.
+		initial	f_axi_arstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_arvalid)||(i_axi_arready)
+				||(i_axi_rvalid))
+			f_axi_arstall <= 0;
+		else
+			f_axi_arstall <= f_axi_arstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSERT(f_axi_arstall < F_AXI_MAXWAIT);
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Insist upon a maximum delay before any response is accepted
+	//
+	// These are separate from the earlier ones, in case you wish to
+	// control them separately.  For example, an interconnect might be
+	// forced to let a channel wait indefinitely for access, but it might
+	// not be appropriate to require the response to be able to wait
+	// indefinitely as well
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	generate if (F_AXI_MAXRSTALL > 0)
+	begin : CHECK_RESPONSE_STALLS
+		reg	[LGTIMEOUT-1:0]		f_axi_bstall,
+						f_axi_rstall;
+
+		// AXI write response channel
+		//
+		// Insist on a maximum number of clocks that BVALID can be
+		// high while BREADY is low
+		initial	f_axi_bstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_bvalid)||(i_axi_bready))
+			f_axi_bstall <= 0;
+		else
+			f_axi_bstall <= f_axi_bstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSUME(f_axi_bstall < F_AXI_MAXRSTALL);
+
+		// AXI read response channel
+		//
+		// Insist on a maximum number of clocks that RVALID can be
+		// high while RREADY is low
+		initial	f_axi_rstall = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(!i_axi_rvalid)||(i_axi_rready))
+			f_axi_rstall <= 0;
+		else
+			f_axi_rstall <= f_axi_rstall + 1'b1;
+
+		always @(*)
+			`SLAVE_ASSUME(f_axi_rstall < F_AXI_MAXRSTALL);
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Xilinx extensions/guarantees to the AXI protocol
+	//
+	//	1. The address line will never be more than two clocks ahead of
+	//		the write data channel, and
+	//	2. The write data channel will never be more than one clock
+	//		ahead of the address channel.
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate if (F_OPT_XILINX)
+	begin
+		// Rule number one:
+		always @(posedge i_clk)
+		if ((i_axi_reset_n)&&($past(i_axi_reset_n))
+			&&($past(i_axi_awvalid && !i_axi_wvalid,2))
+				&&($past(f_axi_awr_outstanding>=f_axi_wr_outstanding,2))
+				&&(!$past(i_axi_wvalid)))
+			`SLAVE_ASSUME(i_axi_wvalid);
+
+		always @(posedge i_clk)
+		if ((i_axi_reset_n)
+				&&(f_axi_awr_outstanding > 1)
+				&&(f_axi_awr_outstanding-1 > f_axi_wr_outstanding))
+			`SLAVE_ASSUME(i_axi_wvalid);
+
+		always @(posedge i_clk)
+		if ((i_axi_reset_n)
+				&&($past(f_axi_awr_outstanding > f_axi_wr_outstanding))
+				&&(!$past(axi_wr_req)))
+			`SLAVE_ASSUME(i_axi_wvalid);
+
+
+		// Rule number two:
+		always @(posedge i_clk)
+		if ((i_axi_reset_n)&&(f_axi_awr_outstanding < f_axi_wr_outstanding))
+			`SLAVE_ASSUME(i_axi_awvalid);
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Count outstanding transactions.  With these measures, we count
+	// once per any burst.
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// Count outstanding write address channel requests
+	initial	f_axi_awr_outstanding = 0;
+	always @(posedge i_clk)
+	if (!i_axi_reset_n)
+		f_axi_awr_outstanding <= 0;
+	else case({ (axi_awr_req), (axi_wr_ack) })
+		2'b10: f_axi_awr_outstanding <= f_axi_awr_outstanding + 1'b1;
+		2'b01: f_axi_awr_outstanding <= f_axi_awr_outstanding - 1'b1;
+		default: begin end
+	endcase
+
+	//
+	// Count outstanding write data channel requests
+	initial	f_axi_wr_outstanding = 0;
+	always @(posedge i_clk)
+	if (!i_axi_reset_n)
+		f_axi_wr_outstanding <= 0;
+	else case({ (axi_wr_req), (axi_wr_ack) })
+	2'b01: f_axi_wr_outstanding <= f_axi_wr_outstanding - 1'b1;
+	2'b10: f_axi_wr_outstanding <= f_axi_wr_outstanding + 1'b1;
+	endcase
+
+	//
+	// Count outstanding read requests
+	initial	f_axi_rd_outstanding = 0;
+	always @(posedge i_clk)
+	if (!i_axi_reset_n)
+		f_axi_rd_outstanding <= 0;
+	else case({ (axi_ard_req), (axi_rd_ack) })
+	2'b01: f_axi_rd_outstanding <= f_axi_rd_outstanding - 1'b1;
+	2'b10: f_axi_rd_outstanding <= f_axi_rd_outstanding + 1'b1;
+	endcase
+
+	//
+	// Do not let the number of outstanding requests overflow
+	always @(posedge i_clk)
+		`SLAVE_ASSERT(f_axi_wr_outstanding  < {(F_LGDEPTH){1'b1}});
+	always @(posedge i_clk)
+		`SLAVE_ASSERT(f_axi_awr_outstanding < {(F_LGDEPTH){1'b1}});
+	always @(posedge i_clk)
+		`SLAVE_ASSERT(f_axi_rd_outstanding  < {(F_LGDEPTH){1'b1}});
+
+	//
+	// That means that requests need to stop when we're almost full
+	always @(posedge i_clk)
+	if (f_axi_awr_outstanding == { {(F_LGDEPTH-1){1'b1}}, 1'b0} )
+		assert(!i_axi_awready);
+	always @(posedge i_clk)
+	if (f_axi_wr_outstanding == { {(F_LGDEPTH-1){1'b1}}, 1'b0} )
+		assert(!i_axi_wready);
+	always @(posedge i_clk)
+	if (f_axi_rd_outstanding == { {(F_LGDEPTH-1){1'b1}}, 1'b0} )
+		assert(!i_axi_arready);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Insist that all responses are returned in less than a maximum delay
+	// In this case, we count responses within a burst, rather than entire
+	// bursts.
+	//
+	//
+	// A unique feature to the backpressure mechanism within AXI is that
+	// we have to reset our delay counters in the case of any push back,
+	// since the response can't move forward if the master isn't (yet)
+	// ready for it.
+	//
+	////////////////////////////////////////////////////////////////////////
+	generate if (F_AXI_MAXDELAY > 0)
+	begin : CHECK_MAX_DELAY
+
+		reg	[LGTIMEOUT-1:0]		f_axi_wr_ack_delay,
+						f_axi_rd_ack_delay;
+
+		//
+		// Count the clock cycles a write request (address + data) has
+		// been outstanding and without any response
+		initial	f_axi_wr_ack_delay = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(i_axi_bvalid)
+				||(f_axi_awr_outstanding==0)
+				||(f_axi_wr_outstanding==0))
+			f_axi_wr_ack_delay <= 0;
+		else if (f_axi_wr_outstanding > 0)
+			f_axi_wr_ack_delay <= f_axi_wr_ack_delay + 1'b1;
+
+		//
+		// Count the clock cycles that any read request has been
+		// outstanding, but without any response.
+		initial	f_axi_rd_ack_delay = 0;
+		always @(posedge i_clk)
+		if ((!i_axi_reset_n)||(i_axi_rvalid)||(f_axi_rd_outstanding==0))
+			f_axi_rd_ack_delay <= 0;
+		else
+			f_axi_rd_ack_delay <= f_axi_rd_ack_delay + 1'b1;
+
+
+		//
+		// Assert that write responses will be returned in a timely
+		// fashion
+		always @(*)
+			`SLAVE_ASSERT(f_axi_wr_ack_delay < F_AXI_MAXDELAY);
+
+		//
+		// Assert that read responses will be returned in a timely
+		// fashion
+		always @(*)
+			`SLAVE_ASSERT(f_axi_rd_ack_delay < F_AXI_MAXDELAY);
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Assume acknowledgements must follow requests
+	//
+	// The f_axi*outstanding counters count the number of requests.  No
+	// acknowledgment should issue without a pending request
+	// burst.  Further, the spec is clear: you can't acknowledge something
+	// on the same clock you get the request.  There must be at least one
+	// clock delay.
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	//
+	// AXI write response channel
+	//
+	always @(posedge i_clk)
+	if (i_axi_bvalid)
+	begin
+		// No BVALID w/o an outstanding request
+		`SLAVE_ASSERT(f_axi_awr_outstanding > 0);
+		`SLAVE_ASSERT(f_axi_wr_outstanding  > 0);
+	end
+
+	//
+	// AXI read data channel signals
+	//
+	always @(posedge i_clk)
+	if (i_axi_rvalid)
+		// No RVALID w/o an outstanding request
+		`SLAVE_ASSERT(f_axi_rd_outstanding > 0);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// F_OPT_WRITE_ONLY or F_OPT_READ_ONLY
+	//
+	// Optionally disable either read or write channels (or both??)
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	initial	assert((!F_OPT_WRITE_ONLY)||(!F_OPT_READ_ONLY));
+
+	generate if (F_OPT_WRITE_ONLY)
+	begin : NO_READS
+
+		// If there are no read requests (assumed), there should be
+		// no read responses
+		always @(*)
+			`SLAVE_ASSUME(i_axi_arvalid == 0);
+		always @(*)
+			assert(f_axi_rd_outstanding == 0);
+		always @(*)
+			`SLAVE_ASSERT(i_axi_rvalid == 0);
+
+	end endgenerate
+
+	generate if (F_OPT_READ_ONLY)
+	begin : NO_WRITES
+
+		// If there are no write requests (assumed, address or data),
+		// there should be no read responses
+		always @(*)
+			`SLAVE_ASSUME(i_axi_awvalid == 0);
+		always @(*)
+			`SLAVE_ASSUME(i_axi_wvalid == 0);
+		always @(*)
+			assert(f_axi_wr_outstanding == 0);
+		always @(*)
+			assert(f_axi_awr_outstanding == 0);
+		always @(*)
+			`SLAVE_ASSERT(i_axi_bvalid == 0);
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Cover properties
+	//
+	// We'll use this to prove that transactions are even possible, and
+	// hence that we haven't so constrained the bus that nothing can take
+	// place.
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+
+	//
+	// AXI write response channel
+	//
+	generate if (!F_OPT_READ_ONLY)
+	begin
+		always @(posedge i_clk)
+			// Make sure we can get a write acknowledgment
+			cover((i_axi_bvalid)&&(i_axi_bready));
+	end endgenerate
+
+	//
+	// AXI read response channel
+	//
+	generate if (!F_OPT_WRITE_ONLY)
+	begin
+		always @(posedge i_clk)
+			// Make sure we can get a response from the read channel
+			cover((i_axi_rvalid)&&(i_axi_rready));
+	end endgenerate
+
+	generate if (!F_OPT_READ_ONLY && F_OPT_COVER_BURST > 0)
+	begin : COVER_WRITE_BURSTS
+
+		reg	[31:0]	cvr_writes;
+
+		initial	cvr_writes = 0;
+		always @(posedge i_clk)
+		if (!i_axi_reset_n)
+			cvr_writes <= 0;
+		else if (i_axi_bvalid && i_axi_bready && i_axi_bresp == 2'b00
+				&& !(&cvr_writes))
+			cvr_writes <= cvr_writes + 1;
+
+		always @(*)
+			cover(cvr_writes == F_OPT_COVER_BURST);
+
+	end endgenerate
+
+	generate if (!F_OPT_WRITE_ONLY && F_OPT_COVER_BURST > 0)
+	begin : COVER_READ_BURSTS
+
+		reg	[31:0]	cvr_reads;
+
+		initial	cvr_reads = 0;
+		always @(posedge i_clk)
+		if (!i_axi_reset_n)
+			cvr_reads <= 0;
+		else if (i_axi_rvalid && i_axi_rready && i_axi_rresp == 2'b00
+				&& !(&cvr_reads))
+			cvr_reads <= cvr_reads + 1;
+
+		always @(*)
+			cover(cvr_reads == F_OPT_COVER_BURST);
+
+	end endgenerate
+
+`undef	SLAVE_ASSUME
+`undef	SLAVE_ASSERT
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxis_master.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxis_master.v
new file mode 100644
index 0000000..cba9380
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxis_master.v
@@ -0,0 +1,229 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	faxis_master.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Formal properties for verifying the proper functionality of an
+//		AXI Stream master.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+module	faxis_master #(
+	parameter	F_MAX_PACKET = 0,
+	parameter	F_MIN_PACKET = 0,
+	parameter	F_MAX_STALL  = 0,
+	parameter	C_S_AXI_DATA_WIDTH  = 32,
+	parameter	C_S_AXI_ID_WIDTH = 1,
+	parameter	C_S_AXI_ADDR_WIDTH = 1,
+	parameter	C_S_AXI_USER_WIDTH = 1,
+	parameter [0:0]	OPT_ASYNC_RESET = 1'b0,
+	//
+	// F_LGDEPTH is the number of bits necessary to represent a packets
+	// length
+	parameter	F_LGDEPTH = 32,
+	//
+	localparam	AW  = C_S_AXI_ADDR_WIDTH,
+	localparam	DW  = C_S_AXI_DATA_WIDTH,
+	localparam	IDW  = C_S_AXI_ID_WIDTH,
+	localparam	UW  = C_S_AXI_USER_WIDTH
+	//
+	) (
+	//
+	input	wire			i_aclk, i_aresetn,
+	input	wire			i_tvalid,
+	input	wire			i_tready = 1,
+	input	wire	[DW-1:0]	i_tdata,
+	input	wire	[DW/8-1:0]	i_tstrb = {(DW/8){1'b1}},
+	input	wire	[DW/8-1:0]	i_tkeep = {(DW/8){1'b1}},
+	input	wire			i_tlast,
+	input	wire	[(IDW>0?IDW:1)-1:0]	i_tid = {(IDW){1'b0}},
+	input	wire	[(AW>0?AW:1)-1:0]	i_tdest = {(AW){1'b0}},
+	input	wire	[(UW>0?UW:1)-1:0]	i_tuser = {(UW){1'b0}},
+	//
+	output	reg	[F_LGDEPTH-1:0]	f_bytecount,
+	(* anyconst *) output	reg	[AW+IDW-1:0]	f_routecheck
+	);
+
+`define	SLAVE_ASSUME	assert
+`define	SLAVE_ASSERT	assume
+
+	localparam	F_STALLBITS	= (F_MAX_STALL <= 1)
+						? 1 : $clog2(F_MAX_STALL+2);
+	reg				f_past_valid;
+	reg	[F_LGDEPTH-1:0]		f_vbytes;
+	reg	[F_STALLBITS-1:0]	f_stall_count;
+	integer	iB;
+	genvar	k;
+
+	//
+	// f_past_valid is used to make certain that temporal assertions
+	// depending upon past values depend upon *valid* past values.
+	// It is true for all clocks other than the first clock.
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_aclk)
+		f_past_valid <= 1'b1;
+
+	//
+	// Reset should always be active (low) initially
+	always @(posedge i_aclk)
+	if (!f_past_valid)
+		`SLAVE_ASSUME(!i_aresetn);
+
+	//
+	// During and following a reset, TVALID should be deasserted
+	always @(posedge i_aclk)
+	if ((!f_past_valid)||(!i_aresetn && OPT_ASYNC_RESET)||($past(!i_aresetn)))
+		`SLAVE_ASSUME(!i_tvalid);
+
+	//
+	// If TVALID but not TREADY, then the master isn't allowed to change
+	// anything until the slave asserts TREADY.
+	always @(posedge i_aclk)
+	if ((f_past_valid)&&($past(i_aresetn))&&(!OPT_ASYNC_RESET || i_aresetn)
+		&&($past(i_tvalid))&&(!$past(i_tready)))
+	begin
+		`SLAVE_ASSUME(i_tvalid);
+		`SLAVE_ASSUME($stable(i_tstrb));
+		`SLAVE_ASSUME($stable(i_tkeep));
+		`SLAVE_ASSUME($stable(i_tlast));
+		`SLAVE_ASSUME($stable(i_tid));
+		`SLAVE_ASSUME($stable(i_tdest));
+		`SLAVE_ASSUME($stable(i_tuser));
+	end
+
+	generate for(k=0; k<DW/8; k=k+1)
+	begin : CHECK_PARTIAL_DATA
+
+		// If TVALID && !TREADY, only those TDATA values with TKEEP
+		// high are required to maintain their values until TREADY
+		// becomes true.
+		always @(posedge i_aclk)
+		if ((f_past_valid)&&($past(i_aresetn))
+			&&(!OPT_ASYNC_RESET || i_aresetn)
+			&&($past(i_tvalid))&&(!$past(i_tready)))
+		begin
+			if (i_tkeep[k])
+				`SLAVE_ASSUME($stable(i_tdata[k*8 +: 8]));
+			// else this is a null (don't care) byte, with
+			// no data within it
+			//
+		end
+
+	end endgenerate
+
+	//
+	// TKEEP == LOW and TSTRB == HIGH is reserved per the spec, and
+	// must not be used
+	always @(posedge i_aclk)
+	if (i_tvalid)
+		`SLAVE_ASSUME((~i_tkeep & i_tstrb)==0);
+
+	//
+	// f_vbytes is the number of valid bytes contained in the current beat
+	// It is used for counting packet lengths below.
+	always @(*)
+	if (!i_tvalid)
+		f_vbytes = 0;
+	else begin
+		f_vbytes = 0;
+		for(iB=0; iB < DW/8; iB=iB+1)
+		if (i_tkeep[iB] && i_tstrb[iB])
+			f_vbytes = f_vbytes + 1;
+	end
+
+	//
+	// f_bytecount is the number of bytes that have taken place so far in
+	// the current packet transmission.  Note that we are *only* counting
+	// our location within the stream if the TUSER and TDEST fields match
+	// our (solver chosen) ROUTECHECK.  That way we don't have to check
+	// *EVERY POSSIBLE* TUSER and TDEST combination.
+	initial	f_bytecount = 0;
+	always @(posedge i_aclk)
+	if (!i_aresetn)
+		f_bytecount <= 0;
+	else if (i_tready && i_tvalid && ({ i_tuser, i_tdest } == f_routecheck))
+	begin
+		if (i_tlast)
+			f_bytecount <= 0;
+		else
+			f_bytecount <= f_bytecount + f_vbytes;
+	end
+
+	//
+	// Count the number of clock cycles between ready's.  We'll use this in
+	// a bit to insist on an (optional) minimum transfer speed.
+	initial	f_stall_count = 0;
+	always @(posedge i_aclk)
+	if (!i_aresetn || !i_tvalid || i_tready)
+		f_stall_count <= 0;
+	else if (!(&f_stall_count))
+		f_stall_count <= f_stall_count + 1;
+
+	//
+	// F_MAX_PACKET
+	//
+	// An optional check, to make certain packets don't exceed some maximum
+	// length
+	generate if (F_MAX_PACKET > 0)
+	begin : MAX_PACKET
+
+		always @(*)
+			`SLAVE_ASSUME(f_bytecount + f_vbytes <= F_MAX_PACKET);
+
+	end endgenerate
+
+	//
+	// F_MIN_PACKET
+	//
+	// An optoinal check, forcing a minimum packet length
+	generate if (F_MIN_PACKET > 0)
+	begin : MIN_PACKET
+
+		always @(*)
+		if (i_tvalid && i_tlast)
+			`SLAVE_ASSUME(f_bytecount + f_vbytes >= F_MIN_PACKET);
+
+	end endgenerate
+
+	//
+	// F_MAX_STALL
+	//
+	// Another optional check, this time insisting that the READY flag can
+	// only be low for up to F_MAX_STALL clocks.
+	//
+	generate if (F_MAX_STALL > 0)
+	begin : MAX_STALL_CHECK
+
+		always @(*)
+			`SLAVE_ASSERT(f_stall_count < F_MAX_STALL);
+
+	end endgenerate
+endmodule
+`undef	SLAVE_ASSUME
+`undef	SLAVE_ASSERT
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxis_slave.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxis_slave.v
new file mode 100644
index 0000000..d528b0d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/faxis_slave.v
@@ -0,0 +1,229 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	faxis_slave.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Formal properties for verifying the proper functionality of an
+//		AXI Stream slave.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+module	faxis_slave #(
+	parameter	F_MAX_PACKET = 0,
+	parameter	F_MIN_PACKET = 0,
+	parameter	F_MAX_STALL  = 0,
+	parameter	C_S_AXI_DATA_WIDTH  = 32,
+	parameter	C_S_AXI_ID_WIDTH = 1,
+	parameter	C_S_AXI_ADDR_WIDTH = 1,
+	parameter	C_S_AXI_USER_WIDTH = 1,
+	parameter [0:0]	OPT_ASYNC_RESET = 1'b0,
+	//
+	// F_LGDEPTH is the number of bits necessary to represent a packets
+	// length
+	parameter	F_LGDEPTH = 32,
+	//
+	localparam	AW  = C_S_AXI_ADDR_WIDTH,
+	localparam	DW  = C_S_AXI_DATA_WIDTH,
+	localparam	IDW  = C_S_AXI_ID_WIDTH,
+	localparam	UW  = C_S_AXI_USER_WIDTH
+	//
+	) (
+	//
+	input	wire			i_aclk, i_aresetn,
+	input	wire			i_tvalid,
+	input	wire			i_tready = 1,
+	input	wire	[DW-1:0]	i_tdata,
+	input	wire	[DW/8-1:0]	i_tstrb = {(DW/8){1'b1}},
+	input	wire	[DW/8-1:0]	i_tkeep = {(DW/8){1'b1}},
+	input	wire			i_tlast,
+	input	wire	[(IDW>0?IDW:1)-1:0]	i_tid = {(IDW){1'b0}},
+	input	wire	[(AW>0?AW:1)-1:0]	i_tdest = {(AW){1'b0}},
+	input	wire	[(UW>0?UW:1)-1:0]	i_tuser = {(UW){1'b0}},
+	//
+	output	reg	[F_LGDEPTH-1:0]	f_bytecount,
+	(* anyconst *) output	reg	[AW+IDW-1:0]	f_routecheck
+	);
+
+`define	SLAVE_ASSUME	assume
+`define	SLAVE_ASSERT	assert
+
+	localparam	F_STALLBITS	= (F_MAX_STALL <= 1)
+						? 1 : $clog2(F_MAX_STALL+2);
+	reg				f_past_valid;
+	reg	[F_LGDEPTH-1:0]		f_vbytes;
+	reg	[F_STALLBITS-1:0]	f_stall_count;
+	integer	iB;
+	genvar	k;
+
+	//
+	// f_past_valid is used to make certain that temporal assertions
+	// depending upon past values depend upon *valid* past values.
+	// It is true for all clocks other than the first clock.
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_aclk)
+		f_past_valid <= 1'b1;
+
+	//
+	// Reset should always be active (low) initially
+	always @(posedge i_aclk)
+	if (!f_past_valid)
+		`SLAVE_ASSUME(!i_aresetn);
+
+	//
+	// During and following a reset, TVALID should be deasserted
+	always @(posedge i_aclk)
+	if ((!f_past_valid)||(!i_aresetn && OPT_ASYNC_RESET)||($past(!i_aresetn)))
+		`SLAVE_ASSUME(!i_tvalid);
+
+	//
+	// If TVALID but not TREADY, then the master isn't allowed to change
+	// anything until the slave asserts TREADY.
+	always @(posedge i_aclk)
+	if ((f_past_valid)&&($past(i_aresetn))&&(!OPT_ASYNC_RESET || i_aresetn)
+		&&($past(i_tvalid))&&(!$past(i_tready)))
+	begin
+		`SLAVE_ASSUME(i_tvalid);
+		`SLAVE_ASSUME($stable(i_tstrb));
+		`SLAVE_ASSUME($stable(i_tkeep));
+		`SLAVE_ASSUME($stable(i_tlast));
+		`SLAVE_ASSUME($stable(i_tid));
+		`SLAVE_ASSUME($stable(i_tdest));
+		`SLAVE_ASSUME($stable(i_tuser));
+	end
+
+	generate for(k=0; k<DW/8; k=k+1)
+	begin : CHECK_PARTIAL_DATA
+
+		// If TVALID && !TREADY, only those TDATA values with TKEEP
+		// high are required to maintain their values until TREADY
+		// becomes true.
+		always @(posedge i_aclk)
+		if ((f_past_valid)&&($past(i_aresetn))
+			&&(!OPT_ASYNC_RESET || i_aresetn)
+			&&($past(i_tvalid))&&(!$past(i_tready)))
+		begin
+			if (i_tkeep[k])
+				`SLAVE_ASSUME($stable(i_tdata[k*8 +: 8]));
+			// else this is a null (don't care) byte, with
+			// no data within it
+			//
+		end
+
+	end endgenerate
+
+	//
+	// TKEEP == LOW and TSTRB == HIGH is reserved per the spec, and
+	// must not be used
+	always @(posedge i_aclk)
+	if (i_tvalid)
+		`SLAVE_ASSUME((~i_tkeep & i_tstrb)==0);
+
+	//
+	// f_vbytes is the number of valid bytes contained in the current beat
+	// It is used for counting packet lengths below.
+	always @(*)
+	if (!i_tvalid)
+		f_vbytes = 0;
+	else begin
+		f_vbytes = 0;
+		for(iB=0; iB < DW/8; iB=iB+1)
+		if (i_tkeep[iB] && i_tstrb[iB])
+			f_vbytes = f_vbytes + 1;
+	end
+
+	//
+	// f_bytecount is the number of bytes that have taken place so far in
+	// the current packet transmission.  Note that we are *only* counting
+	// our location within the stream if the TUSER and TDEST fields match
+	// our (solver chosen) ROUTECHECK.  That way we don't have to check
+	// *EVERY POSSIBLE* TUSER and TDEST combination.
+	initial	f_bytecount = 0;
+	always @(posedge i_aclk)
+	if (!i_aresetn)
+		f_bytecount <= 0;
+	else if (i_tready && i_tvalid && ({ i_tuser, i_tdest } == f_routecheck))
+	begin
+		if (i_tlast)
+			f_bytecount <= 0;
+		else
+			f_bytecount <= f_bytecount + f_vbytes;
+	end
+
+	//
+	// Count the number of clock cycles between ready's.  We'll use this in
+	// a bit to insist on an (optional) minimum transfer speed.
+	initial	f_stall_count = 0;
+	always @(posedge i_aclk)
+	if (!i_aresetn || !i_tvalid || i_tready)
+		f_stall_count <= 0;
+	else if (!(&f_stall_count))
+		f_stall_count <= f_stall_count + 1;
+
+	//
+	// F_MAX_PACKET
+	//
+	// An optional check, to make certain packets don't exceed some maximum
+	// length
+	generate if (F_MAX_PACKET > 0)
+	begin : MAX_PACKET
+
+		always @(*)
+			`SLAVE_ASSUME(f_bytecount + f_vbytes <= F_MAX_PACKET);
+
+	end endgenerate
+
+	//
+	// F_MIN_PACKET
+	//
+	// An optoinal check, forcing a minimum packet length
+	generate if (F_MIN_PACKET > 0)
+	begin : MIN_PACKET
+
+		always @(*)
+		if (i_tvalid && i_tlast)
+			`SLAVE_ASSUME(f_bytecount + f_vbytes >= F_MIN_PACKET);
+
+	end endgenerate
+
+	//
+	// F_MAX_STALL
+	//
+	// Another optional check, this time insisting that the READY flag can
+	// only be low for up to F_MAX_STALL clocks.
+	//
+	generate if (F_MAX_STALL > 0)
+	begin : MAX_STALL_CHECK
+
+		always @(*)
+			`SLAVE_ASSERT(f_stall_count < F_MAX_STALL);
+
+	end endgenerate
+endmodule
+`undef	SLAVE_ASSUME
+`undef	SLAVE_ASSERT
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fwb_master.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fwb_master.v
new file mode 100644
index 0000000..757bf30
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fwb_master.v
@@ -0,0 +1,476 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename:	fwb_master.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	This file describes the rules of a wishbone interaction from the
+//		perspective of a wishbone master.  These formal rules may be used
+//	with yosys-smtbmc to *prove* that the master properly handles outgoing
+//	transactions and incoming responses.
+//
+//	This module contains no functional logic.  It is intended for formal
+//	verification only.  The outputs returned, the number of requests that
+//	have been made, the number of acknowledgements received, and the number
+//	of outstanding requests, are designed for further formal verification
+//	purposes *only*.
+//
+//	This file is different from a companion formal_slave.v file in that the
+//	assertions are made on the outputs of the wishbone master: o_wb_cyc,
+//	o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, and o_wb_sel, while only
+//	assumptions are made about the inputs: i_wb_stall, i_wb_ack, i_wb_data,
+//	i_wb_err.  In the formal_slave.v, assumptions are made about the
+//	slave inputs (the master outputs), and assertions are made about the
+//	slave outputs (the master inputs).
+//
+//	In order to make it easier to compare the slave against the master,
+//	assumptions with respect to the slave have been marked with the
+//	`SLAVE_ASSUME macro.  Similarly, assertions the slave would make have
+//	been marked with `SLAVE_ASSERT.  This allows the master to redefine
+//	these two macros to be from his perspective, and therefore the
+//	diffs between the two files actually show true differences, rather
+//	than just these differences in perspective.
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2017-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+module	fwb_master(i_clk, i_reset,
+		// The Wishbone bus
+		i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel,
+			i_wb_ack, i_wb_stall, i_wb_idata, i_wb_err,
+		// Some convenience output parameters
+		f_nreqs, f_nacks, f_outstanding);
+	parameter		AW=32, DW=32;
+	parameter		F_MAX_STALL = 0,
+				F_MAX_ACK_DELAY = 0;
+	parameter		F_LGDEPTH = 4;
+	parameter [(F_LGDEPTH-1):0] F_MAX_REQUESTS = 0;
+	//
+	// If true, allow the bus to be kept open when there are no outstanding
+	// requests.  This is useful for any master that might execute a
+	// read modify write cycle, such as an atomic add.
+	parameter [0:0]		F_OPT_RMW_BUS_OPTION = 1;
+	//
+	// 
+	parameter [0:0]		F_OPT_SHORT_CIRCUIT_PROOF = 0;
+	//
+	// If this is the source of a request, then we can assume STB and CYC
+	// will initially start out high.  Master interfaces following the
+	// source on the way to the slave may not have this property
+	parameter [0:0]		F_OPT_SOURCE = 0;
+	//
+	// If true, allow the bus to issue multiple discontinuous requests.
+	// Unlike F_OPT_RMW_BUS_OPTION, these requests may be issued while other
+	// requests are outstanding
+	parameter	[0:0]	F_OPT_DISCONTINUOUS = 0;
+	//
+	//
+	// If true, insist that there be a minimum of a single clock delay
+	// between request and response.  This defaults to off since the
+	// wishbone specification specifically doesn't require this.  However,
+	// some interfaces do, so we allow it as an option here.
+	parameter	[0:0]	F_OPT_MINCLOCK_DELAY = 0;
+	//
+	//
+	localparam [(F_LGDEPTH-1):0] MAX_OUTSTANDING = {(F_LGDEPTH){1'b1}};
+	localparam	MAX_DELAY = (F_MAX_STALL > F_MAX_ACK_DELAY)
+				? F_MAX_STALL : F_MAX_ACK_DELAY;
+	localparam	DLYBITS= (MAX_DELAY < 4) ? 2
+				: ((MAX_DELAY <    16) ? 4
+				: ((MAX_DELAY <    64) ? 6
+				: ((MAX_DELAY <   256) ? 8
+				: ((MAX_DELAY <  1024) ? 10
+				: ((MAX_DELAY <  4096) ? 12
+				: ((MAX_DELAY < 16384) ? 14
+				: ((MAX_DELAY < 65536) ? 16
+				: 32)))))));
+	//
+	input	wire			i_clk, i_reset;
+	// Input/master bus
+	input	wire			i_wb_cyc, i_wb_stb, i_wb_we;
+	input	wire	[(AW-1):0]	i_wb_addr;
+	input	wire	[(DW-1):0]	i_wb_data;
+	input	wire	[(DW/8-1):0]	i_wb_sel;
+	//
+	input	wire			i_wb_ack;
+	input	wire			i_wb_stall;
+	input	wire	[(DW-1):0]	i_wb_idata;
+	input	wire			i_wb_err;
+	//
+	output	reg	[(F_LGDEPTH-1):0]	f_nreqs, f_nacks;
+	output	wire	[(F_LGDEPTH-1):0]	f_outstanding;
+
+`define	SLAVE_ASSUME	assert
+`define	SLAVE_ASSERT	assume
+	//
+	// Let's just make sure our parameters are set up right
+	//
+	initial	assert(F_MAX_REQUESTS < {(F_LGDEPTH){1'b1}});
+
+	//
+	// Wrap the request line in a bundle.  The top bit, named STB_BIT,
+	// is the bit indicating whether the request described by this vector
+	// is a valid request or not.
+	//
+	localparam	STB_BIT = 2+AW+DW+DW/8-1;
+	wire	[STB_BIT:0]	f_request;
+	assign	f_request = { i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel };
+
+	//
+	// A quick register to be used later to know if the $past() operator
+	// will yield valid result
+	reg	f_past_valid;
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+	always @(*)
+	if (!f_past_valid)
+		`SLAVE_ASSUME(i_reset);
+	//
+	//
+	// Assertions regarding the initial (and reset) state
+	//
+	//
+
+	//
+	// Assume we start from a reset condition
+	initial assert(i_reset);
+	initial `SLAVE_ASSUME(!i_wb_cyc);
+	initial `SLAVE_ASSUME(!i_wb_stb);
+	//
+	initial	`SLAVE_ASSERT(!i_wb_ack);
+	initial	`SLAVE_ASSERT(!i_wb_err);
+
+`ifdef	VERIFIC
+	always @(*)
+	if (!f_past_valid)
+	begin
+		`SLAVE_ASSUME(!i_wb_cyc);
+		`SLAVE_ASSUME(!i_wb_stb);
+		//
+		`SLAVE_ASSERT(!i_wb_ack);
+		`SLAVE_ASSERT(!i_wb_err);
+	end
+`endif
+	always @(posedge i_clk)
+	if ((!f_past_valid)||($past(i_reset)))
+	begin
+		`SLAVE_ASSUME(!i_wb_cyc);
+		`SLAVE_ASSUME(!i_wb_stb);
+		//
+		`SLAVE_ASSERT(!i_wb_ack);
+		`SLAVE_ASSERT(!i_wb_err);
+	end
+
+	always @(*)
+	if (!f_past_valid)
+		`SLAVE_ASSUME(!i_wb_cyc);
+
+	//
+	//
+	// Bus requests
+	//
+	//
+
+	// Following any bus error, the CYC line should be dropped to abort
+	// the transaction
+	always @(posedge i_clk)
+	if ((f_past_valid)&&($past(i_wb_err))&&($past(i_wb_cyc)))
+		`SLAVE_ASSUME(!i_wb_cyc);
+
+	// STB can only be true if CYC is also true
+	always @(*)
+	if (i_wb_stb)
+		`SLAVE_ASSUME(i_wb_cyc);
+
+	// If a request was both outstanding and stalled on the last clock,
+	// then nothing should change on this clock regarding it.
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_reset))&&($past(i_wb_stb))
+			&&($past(i_wb_stall))&&(i_wb_cyc))
+	begin
+		`SLAVE_ASSUME(i_wb_stb);
+		`SLAVE_ASSUME(i_wb_we   == $past(i_wb_we));
+		`SLAVE_ASSUME(i_wb_addr == $past(i_wb_addr));
+		`SLAVE_ASSUME(i_wb_sel  == $past(i_wb_sel));
+		if (i_wb_we)
+			`SLAVE_ASSUME(i_wb_data == $past(i_wb_data));
+	end
+
+	// Within any series of STB/requests, the direction of the request
+	// may not change.
+	always @(posedge i_clk)
+	if ((f_past_valid)&&($past(i_wb_stb))&&(i_wb_stb))
+		`SLAVE_ASSUME(i_wb_we == $past(i_wb_we));
+
+
+	// Within any given bus cycle, the direction may *only* change when
+	// there are no further outstanding requests.
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(f_outstanding > 0))
+		`SLAVE_ASSUME(i_wb_we == $past(i_wb_we));
+
+	// Write requests must also set one (or more) of i_wb_sel
+	//
+	// This test has been removed since down-sizers (taking bus from width
+	// DW to width dw < DW) might actually create empty requests that this
+	// would prevent.  Re-enabling it would also complicate AXI to WB
+	// transfers, since AXI explicitly allows WSTRB == 0.  Finally, this
+	// criteria isn't found in the WB spec--so while it might be a good
+	// idea to check, in hind sight there are too many exceptions to be
+	// dogmatic about it.
+	//
+	// always @(*)
+	// if ((i_wb_stb)&&(i_wb_we))
+	//	`SLAVE_ASSUME(|i_wb_sel);
+
+
+	//
+	//
+	// Bus responses
+	//
+	//
+
+	// If CYC was low on the last clock, then both ACK and ERR should be
+	// low on this clock.
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_wb_cyc))&&(!i_wb_cyc))
+	begin
+		`SLAVE_ASSERT(!i_wb_ack);
+		`SLAVE_ASSERT(!i_wb_err);
+		// Stall may still be true--such as when we are not
+		// selected at some arbiter between us and the slave
+	end
+
+	//
+	// Any time the CYC line drops, it is possible that there may be a
+	// remaining (registered) ACK or ERR that hasn't yet been returned.
+	// Restrict such out of band returns so that they are *only* returned
+	// if there is an outstanding operation.
+	//
+	// Update: As per spec, WB-classic to WB-pipeline conversions require
+	// that the ACK|ERR might come back on the same cycle that STB
+	// is low, yet also be registered.  Hence, if STB & STALL are true on
+	// one cycle, then CYC is dropped, ACK|ERR might still be true on the
+	// cycle when CYC is dropped
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_reset))&&($past(i_wb_cyc))&&(!i_wb_cyc))
+	begin
+		// Note that, unlike f_outstanding, f_nreqs and f_nacks are both
+		// registered.  Hence, we can check here if a response is still
+		// pending.  If not, no response should be returned.
+		if (f_nreqs == f_nacks)
+		begin
+			`SLAVE_ASSERT(!i_wb_ack);
+			`SLAVE_ASSERT(!i_wb_err);
+		end
+	end
+
+	// ACK and ERR may never both be true at the same time
+	always @(*)
+		`SLAVE_ASSERT((!i_wb_ack)||(!i_wb_err));
+
+	generate if (F_MAX_STALL > 0)
+	begin : MXSTALL
+		//
+		// Assume the slave cannnot stall for more than F_MAX_STALL
+		// counts.  We'll count this forward any time STB and STALL
+		// are both true.
+		//
+		reg	[(DLYBITS-1):0]		f_stall_count;
+
+		initial	f_stall_count = 0;
+		always @(posedge i_clk)
+		if ((!i_reset)&&(i_wb_stb)&&(i_wb_stall))
+			f_stall_count <= f_stall_count + 1'b1;
+		else
+			f_stall_count <= 0;
+
+		always @(*)
+		if (i_wb_cyc)
+			`SLAVE_ASSERT(f_stall_count < F_MAX_STALL);
+	end endgenerate
+
+	generate if (F_MAX_ACK_DELAY > 0)
+	begin : MXWAIT
+		//
+		// Assume the slave will respond within F_MAX_ACK_DELAY cycles,
+		// counted either from the end of the last request, or from the
+		// last ACK received
+		//
+		reg	[(DLYBITS-1):0]		f_ackwait_count;
+
+		initial	f_ackwait_count = 0;
+		always @(posedge i_clk)
+		if ((!i_reset)&&(i_wb_cyc)&&(!i_wb_stb)
+				&&(!i_wb_ack)&&(!i_wb_err)
+				&&(f_outstanding > 0))
+			f_ackwait_count <= f_ackwait_count + 1'b1;
+		else
+			f_ackwait_count <= 0;
+
+		always @(*)
+		if ((!i_reset)&&(i_wb_cyc)&&(!i_wb_stb)
+					&&(!i_wb_ack)&&(!i_wb_err)
+					&&(f_outstanding > 0))
+			`SLAVE_ASSERT(f_ackwait_count < F_MAX_ACK_DELAY);
+	end endgenerate
+
+	//
+	// Count the number of requests that have been made
+	//
+	initial	f_nreqs = 0;
+	always @(posedge i_clk)
+	if ((i_reset)||(!i_wb_cyc))
+		f_nreqs <= 0;
+	else if ((i_wb_stb)&&(!i_wb_stall))
+		f_nreqs <= f_nreqs + 1'b1;
+
+
+	//
+	// Count the number of acknowledgements that have been received
+	//
+	initial	f_nacks = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		f_nacks <= 0;
+	else if (!i_wb_cyc)
+		f_nacks <= 0;
+	else if ((i_wb_ack)||(i_wb_err))
+		f_nacks <= f_nacks + 1'b1;
+
+	//
+	// The number of outstanding requests is the difference between
+	// the number of requests and the number of acknowledgements
+	//
+	assign	f_outstanding = (i_wb_cyc) ? (f_nreqs - f_nacks):0;
+
+	always @(*)
+	if ((i_wb_cyc)&&(F_MAX_REQUESTS > 0))
+	begin
+		if (i_wb_stb)
+			`SLAVE_ASSUME(f_nreqs < F_MAX_REQUESTS);
+		else
+			`SLAVE_ASSUME(f_nreqs <= F_MAX_REQUESTS);
+		`SLAVE_ASSERT(f_nacks <= f_nreqs);
+		assert(f_outstanding < (1<<F_LGDEPTH)-1);
+	end else
+		assume(f_outstanding < (1<<F_LGDEPTH)-1);
+
+	always @(*)
+	if ((i_wb_cyc)&&(f_outstanding == 0))
+	begin
+		// If nothing is outstanding, then there should be
+		// no acknowledgements ... however, an acknowledgement
+		// *can* come back on the same clock as the stb is
+		// going out.
+		if (F_OPT_MINCLOCK_DELAY)
+		begin
+			`SLAVE_ASSERT(!i_wb_ack);
+			`SLAVE_ASSERT(!i_wb_err);
+		end else begin
+			`SLAVE_ASSERT((!i_wb_ack)||((i_wb_stb)&&(!i_wb_stall)));
+			// The same is true of errors.  They may not be
+			// created before the request gets through
+			`SLAVE_ASSERT((!i_wb_err)||((i_wb_stb)&&(!i_wb_stall)));
+		end
+	end else if (!i_wb_cyc && f_nacks == f_nreqs)
+	begin
+		`SLAVE_ASSERT(!i_wb_ack);
+		`SLAVE_ASSERT(!i_wb_err);
+	end
+
+	generate if (F_OPT_SOURCE)
+	begin : SRC
+		// Any opening bus request starts with both CYC and STB high
+		// This is true for the master only, and more specifically
+		// only for those masters that are the initial source of any
+		// transaction.  By the time an interaction gets to the slave,
+		// the CYC line may go high or low without actually affecting
+		// the STB line of the slave.
+		always @(posedge i_clk)
+		if ((f_past_valid)&&(!$past(i_wb_cyc))&&(i_wb_cyc))
+			`SLAVE_ASSUME(i_wb_stb);
+	end endgenerate
+
+
+	generate if (!F_OPT_RMW_BUS_OPTION)
+	begin
+		// If we aren't waiting for anything, and we aren't issuing
+		// any requests, then then our transaction is over and we
+		// should be dropping the CYC line.
+		always @(*)
+		if (f_outstanding == 0)
+			`SLAVE_ASSUME((i_wb_stb)||(!i_wb_cyc));
+		// Not all masters will abide by this restriction.  Some
+		// masters may wish to implement read-modify-write bus
+		// interactions.  These masters need to keep CYC high between
+		// transactions, even though nothing is outstanding.  For
+		// these busses, turn F_OPT_RMW_BUS_OPTION on.
+	end endgenerate
+
+	generate if (F_OPT_SHORT_CIRCUIT_PROOF)
+	begin
+		// In many ways, we don't care what happens on the bus return
+		// lines if the cycle line is low, so restricting them to a
+		// known value makes a lot of sense.
+		//
+		// On the other hand, if something above *does* depend upon
+		// these values (when it shouldn't), then we might want to know
+		// about it.
+		//
+		//
+		always @(posedge i_clk)
+		begin
+			if (!i_wb_cyc)
+			begin
+				assume(!i_wb_stall);
+				assume($stable(i_wb_idata));
+			end else if ((!$past(i_wb_ack))&&(!i_wb_ack))
+				assume($stable(i_wb_idata));
+		end
+	end endgenerate
+
+	generate if ((!F_OPT_DISCONTINUOUS)&&(!F_OPT_RMW_BUS_OPTION))
+	begin : INSIST_ON_NO_DISCONTINUOUS_STBS
+		// Within my own code, once a request begins it goes to
+		// completion and the CYC line is dropped.  The master
+		// is not allowed to raise STB again after dropping it.
+		// Doing so would be a *discontinuous* request.
+		//
+		// However, in any RMW scheme, discontinuous requests are
+		// necessary, and the spec doesn't disallow them.  Hence we
+		// make this check optional.
+		always @(posedge i_clk)
+		if ((f_past_valid)&&($past(i_wb_cyc))&&(!$past(i_wb_stb)))
+			`SLAVE_ASSUME(!i_wb_stb);
+	end endgenerate
+
+endmodule
+`undef	SLAVE_ASSUME
+`undef	SLAVE_ASSERT
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fwb_slave.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fwb_slave.v
new file mode 100644
index 0000000..5a705ac
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fwb_slave.v
@@ -0,0 +1,434 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename:	fwb_slave.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	This file describes the rules of a wishbone interaction from the
+//		perspective of a wishbone slave.  These formal rules may be used
+//	with yosys-smtbmc to *prove* that the slave properly handles outgoing
+//	responses to (assumed correct) incoming requests.
+//
+//	This module contains no functional logic.  It is intended for formal
+//	verification only.  The outputs returned, the number of requests that
+//	have been made, the number of acknowledgements received, and the number
+//	of outstanding requests, are designed for further formal verification
+//	purposes *only*.
+//
+//	This file is different from a companion formal_master.v file in that
+//	assumptions are made about the inputs to the slave: i_wb_cyc,
+//	i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, and i_wb_sel, while full
+//	assertions are made about the outputs: o_wb_stall, o_wb_ack, o_wb_data,
+//	o_wb_err.  In the formal_master.v, assertions are made about the
+//	master outputs (slave inputs)), and assumptions are made about the
+//	master inputs (the slave outputs).
+//
+//	In order to make it easier to compare the slave against the master,
+//	assumptions with respect to the slave have been marked with the
+//	`SLAVE_ASSUME macro.  Similarly, assertions the slave would make have
+//	been marked with `SLAVE_ASSERT.  This allows the master to redefine
+//	these two macros to be from his perspective, and therefore the
+//	diffs between the two files actually show true differences, rather
+//	than just these differences in perspective.
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2017-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+module	fwb_slave(i_clk, i_reset,
+		// The Wishbone bus
+		i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel,
+			i_wb_ack, i_wb_stall, i_wb_idata, i_wb_err,
+		// Some convenience output parameters
+		f_nreqs, f_nacks, f_outstanding);
+	parameter		AW=32, DW=32;
+	parameter		F_MAX_STALL = 0,
+				F_MAX_ACK_DELAY = 0;
+	parameter		F_LGDEPTH = 4;
+	parameter [(F_LGDEPTH-1):0] F_MAX_REQUESTS = 0;
+	//
+	// If true, allow the bus to be kept open when there are no outstanding
+	// requests.  This is useful for any master that might execute a
+	// read modify write cycle, such as an atomic add.
+	parameter [0:0]		F_OPT_RMW_BUS_OPTION = 1;
+	//
+	// 
+	// If true, allow the bus to issue multiple discontinuous requests.
+	// Unlike F_OPT_RMW_BUS_OPTION, these requests may be issued while other
+	// requests are outstanding
+	parameter	[0:0]	F_OPT_DISCONTINUOUS = 1;
+	//
+	//
+	// If true, insist that there be a minimum of a single clock delay
+	// between request and response.  This defaults to off since the
+	// wishbone specification specifically doesn't require this.  However,
+	// some interfaces do, so we allow it as an option here.
+	parameter	[0:0]	F_OPT_MINCLOCK_DELAY = 0;
+	//
+	//
+	//
+	localparam [(F_LGDEPTH-1):0] MAX_OUTSTANDING = {(F_LGDEPTH){1'b1}};
+	localparam	MAX_DELAY = (F_MAX_STALL > F_MAX_ACK_DELAY)
+				? F_MAX_STALL : F_MAX_ACK_DELAY;
+	localparam	DLYBITS= (MAX_DELAY < 4) ? 2
+				: ((MAX_DELAY <    16) ? 4
+				: ((MAX_DELAY <    64) ? 6
+				: ((MAX_DELAY <   256) ? 8
+				: ((MAX_DELAY <  1024) ? 10
+				: ((MAX_DELAY <  4096) ? 12
+				: ((MAX_DELAY < 16384) ? 14
+				: ((MAX_DELAY < 65536) ? 16
+				: 32)))))));
+	//
+	input	wire			i_clk, i_reset;
+	// Input/master bus
+	input	wire			i_wb_cyc, i_wb_stb, i_wb_we;
+	input	wire	[(AW-1):0]	i_wb_addr;
+	input	wire	[(DW-1):0]	i_wb_data;
+	input	wire	[(DW/8-1):0]	i_wb_sel;
+	//
+	input	wire			i_wb_ack;
+	input	wire			i_wb_stall;
+	input	wire	[(DW-1):0]	i_wb_idata;
+	input	wire			i_wb_err;
+	//
+	output	reg	[(F_LGDEPTH-1):0]	f_nreqs, f_nacks;
+	output	wire	[(F_LGDEPTH-1):0]	f_outstanding;
+
+`define	SLAVE_ASSUME	assume
+`define	SLAVE_ASSERT	assert
+	//
+	// Let's just make sure our parameters are set up right
+	//
+	initial	assert(F_MAX_REQUESTS < {(F_LGDEPTH){1'b1}});
+
+	//
+	// Wrap the request line in a bundle.  The top bit, named STB_BIT,
+	// is the bit indicating whether the request described by this vector
+	// is a valid request or not.
+	//
+	localparam	STB_BIT = 2+AW+DW+DW/8-1;
+	wire	[STB_BIT:0]	f_request;
+	assign	f_request = { i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel };
+
+	//
+	// A quick register to be used later to know if the $past() operator
+	// will yield valid result
+	reg	f_past_valid;
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+	always @(*)
+	if (!f_past_valid)
+		`SLAVE_ASSUME(i_reset);
+	//
+	//
+	// Assertions regarding the initial (and reset) state
+	//
+	//
+
+	//
+	// Assume we start from a reset condition
+	initial assert(i_reset);
+	initial `SLAVE_ASSUME(!i_wb_cyc);
+	initial `SLAVE_ASSUME(!i_wb_stb);
+	//
+	initial	`SLAVE_ASSERT(!i_wb_ack);
+	initial	`SLAVE_ASSERT(!i_wb_err);
+
+`ifdef	VERIFIC
+	always @(*)
+	if (!f_past_valid)
+	begin
+		`SLAVE_ASSUME(!i_wb_cyc);
+		`SLAVE_ASSUME(!i_wb_stb);
+		//
+		`SLAVE_ASSERT(!i_wb_ack);
+		`SLAVE_ASSERT(!i_wb_err);
+	end
+`endif
+	always @(posedge i_clk)
+	if ((!f_past_valid)||($past(i_reset)))
+	begin
+		`SLAVE_ASSUME(!i_wb_cyc);
+		`SLAVE_ASSUME(!i_wb_stb);
+		//
+		`SLAVE_ASSERT(!i_wb_ack);
+		`SLAVE_ASSERT(!i_wb_err);
+	end
+
+	always @(*)
+	if (!f_past_valid)
+		`SLAVE_ASSUME(!i_wb_cyc);
+
+	//
+	//
+	// Bus requests
+	//
+	//
+
+	// Following any bus error, the CYC line should be dropped to abort
+	// the transaction
+	always @(posedge i_clk)
+	if ((f_past_valid)&&($past(i_wb_err))&&($past(i_wb_cyc)))
+		`SLAVE_ASSUME(!i_wb_cyc);
+
+	// STB can only be true if CYC is also true
+	always @(*)
+	if (i_wb_stb)
+		`SLAVE_ASSUME(i_wb_cyc);
+
+	// If a request was both outstanding and stalled on the last clock,
+	// then nothing should change on this clock regarding it.
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_reset))&&($past(i_wb_stb))
+			&&($past(i_wb_stall))&&(i_wb_cyc))
+	begin
+		`SLAVE_ASSUME(i_wb_stb);
+		`SLAVE_ASSUME(i_wb_we   == $past(i_wb_we));
+		`SLAVE_ASSUME(i_wb_addr == $past(i_wb_addr));
+		`SLAVE_ASSUME(i_wb_sel  == $past(i_wb_sel));
+		if (i_wb_we)
+			`SLAVE_ASSUME(i_wb_data == $past(i_wb_data));
+	end
+
+	// Within any series of STB/requests, the direction of the request
+	// may not change.
+	always @(posedge i_clk)
+	if ((f_past_valid)&&($past(i_wb_stb))&&(i_wb_stb))
+		`SLAVE_ASSUME(i_wb_we == $past(i_wb_we));
+
+
+	// Within any given bus cycle, the direction may *only* change when
+	// there are no further outstanding requests.
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(f_outstanding > 0))
+		`SLAVE_ASSUME(i_wb_we == $past(i_wb_we));
+
+	// Write requests must also set one (or more) of i_wb_sel
+	//
+	// This test has been removed since down-sizers (taking bus from width
+	// DW to width dw < DW) might actually create empty requests that this
+	// would prevent.  Re-enabling it would also complicate AXI to WB
+	// transfers, since AXI explicitly allows WSTRB == 0.  Finally, this
+	// criteria isn't found in the WB spec--so while it might be a good
+	// idea to check, in hind sight there are too many exceptions to be
+	// dogmatic about it.
+	//
+	// always @(*)
+	// if ((i_wb_stb)&&(i_wb_we))
+	//	`SLAVE_ASSUME(|i_wb_sel);
+
+
+	//
+	//
+	// Bus responses
+	//
+	//
+
+	// If CYC was low on the last clock, then both ACK and ERR should be
+	// low on this clock.
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_wb_cyc))&&(!i_wb_cyc))
+	begin
+		`SLAVE_ASSERT(!i_wb_ack);
+		`SLAVE_ASSERT(!i_wb_err);
+		// Stall may still be true--such as when we are not
+		// selected at some arbiter between us and the slave
+	end
+
+	//
+	// Any time the CYC line drops, it is possible that there may be a
+	// remaining (registered) ACK or ERR that hasn't yet been returned.
+	// Restrict such out of band returns so that they are *only* returned
+	// if there is an outstanding operation.
+	//
+	// Update: As per spec, WB-classic to WB-pipeline conversions require
+	// that the ACK|ERR might come back on the same cycle that STB
+	// is low, yet also be registered.  Hence, if STB & STALL are true on
+	// one cycle, then CYC is dropped, ACK|ERR might still be true on the
+	// cycle when CYC is dropped
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_reset))&&($past(i_wb_cyc))&&(!i_wb_cyc))
+	begin
+		// Note that, unlike f_outstanding, f_nreqs and f_nacks are both
+		// registered.  Hence, we can check here if a response is still
+		// pending.  If not, no response should be returned.
+		if (f_nreqs == f_nacks)
+		begin
+			`SLAVE_ASSERT(!i_wb_ack);
+			`SLAVE_ASSERT(!i_wb_err);
+		end
+	end
+
+	// ACK and ERR may never both be true at the same time
+	always @(*)
+		`SLAVE_ASSERT((!i_wb_ack)||(!i_wb_err));
+
+	generate if (F_MAX_STALL > 0)
+	begin : MXSTALL
+		//
+		// Assume the slave cannnot stall for more than F_MAX_STALL
+		// counts.  We'll count this forward any time STB and STALL
+		// are both true.
+		//
+		reg	[(DLYBITS-1):0]		f_stall_count;
+
+		initial	f_stall_count = 0;
+		always @(posedge i_clk)
+		if ((!i_reset)&&(i_wb_stb)&&(i_wb_stall))
+			f_stall_count <= f_stall_count + 1'b1;
+		else
+			f_stall_count <= 0;
+
+		always @(*)
+		if (i_wb_cyc)
+			`SLAVE_ASSERT(f_stall_count < F_MAX_STALL);
+	end endgenerate
+
+	generate if (F_MAX_ACK_DELAY > 0)
+	begin : MXWAIT
+		//
+		// Assume the slave will respond within F_MAX_ACK_DELAY cycles,
+		// counted either from the end of the last request, or from the
+		// last ACK received
+		//
+		reg	[(DLYBITS-1):0]		f_ackwait_count;
+
+		initial	f_ackwait_count = 0;
+		always @(posedge i_clk)
+		if ((!i_reset)&&(i_wb_cyc)&&(!i_wb_stb)
+				&&(!i_wb_ack)&&(!i_wb_err)
+				&&(f_outstanding > 0))
+			f_ackwait_count <= f_ackwait_count + 1'b1;
+		else
+			f_ackwait_count <= 0;
+
+		always @(*)
+		if ((!i_reset)&&(i_wb_cyc)&&(!i_wb_stb)
+					&&(!i_wb_ack)&&(!i_wb_err)
+					&&(f_outstanding > 0))
+			`SLAVE_ASSERT(f_ackwait_count < F_MAX_ACK_DELAY);
+	end endgenerate
+
+	//
+	// Count the number of requests that have been received
+	//
+	initial	f_nreqs = 0;
+	always @(posedge i_clk)
+	if ((i_reset)||(!i_wb_cyc))
+		f_nreqs <= 0;
+	else if ((i_wb_stb)&&(!i_wb_stall))
+		f_nreqs <= f_nreqs + 1'b1;
+
+
+	//
+	// Count the number of acknowledgements that have been returned
+	//
+	initial	f_nacks = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		f_nacks <= 0;
+	else if (!i_wb_cyc)
+		f_nacks <= 0;
+	else if ((i_wb_ack)||(i_wb_err))
+		f_nacks <= f_nacks + 1'b1;
+
+	//
+	// The number of outstanding requests is the difference between
+	// the number of requests and the number of acknowledgements
+	//
+	assign	f_outstanding = (i_wb_cyc) ? (f_nreqs - f_nacks):0;
+
+	always @(*)
+	if ((i_wb_cyc)&&(F_MAX_REQUESTS > 0))
+	begin
+		if (i_wb_stb)
+			`SLAVE_ASSUME(f_nreqs < F_MAX_REQUESTS);
+		else
+			`SLAVE_ASSUME(f_nreqs <= F_MAX_REQUESTS);
+		`SLAVE_ASSERT(f_nacks <= f_nreqs);
+		assert(f_outstanding < (1<<F_LGDEPTH)-1);
+	end else
+		assume(f_outstanding < (1<<F_LGDEPTH)-1);
+
+	always @(*)
+	if ((i_wb_cyc)&&(f_outstanding == 0))
+	begin
+		// If nothing is outstanding, then there should be
+		// no acknowledgements ... however, an acknowledgement
+		// *can* come back on the same clock as the stb is
+		// going out.
+		if (F_OPT_MINCLOCK_DELAY)
+		begin
+			`SLAVE_ASSERT(!i_wb_ack);
+			`SLAVE_ASSERT(!i_wb_err);
+		end else begin
+			`SLAVE_ASSERT((!i_wb_ack)||((i_wb_stb)&&(!i_wb_stall)));
+			// The same is true of errors.  They may not be
+			// created before the request gets through
+			`SLAVE_ASSERT((!i_wb_err)||((i_wb_stb)&&(!i_wb_stall)));
+		end
+	end else if (!i_wb_cyc && f_nacks == f_nreqs)
+	begin
+		`SLAVE_ASSERT(!i_wb_ack);
+		`SLAVE_ASSERT(!i_wb_err);
+	end
+
+	generate if (!F_OPT_RMW_BUS_OPTION)
+	begin
+		// If we aren't waiting for anything, and we aren't issuing
+		// any requests, then then our transaction is over and we
+		// should be dropping the CYC line.
+		always @(*)
+		if (f_outstanding == 0)
+			`SLAVE_ASSUME((i_wb_stb)||(!i_wb_cyc));
+		// Not all masters will abide by this restriction.  Some
+		// masters may wish to implement read-modify-write bus
+		// interactions.  These masters need to keep CYC high between
+		// transactions, even though nothing is outstanding.  For
+		// these busses, turn F_OPT_RMW_BUS_OPTION on.
+	end endgenerate
+
+	generate if ((!F_OPT_DISCONTINUOUS)&&(!F_OPT_RMW_BUS_OPTION))
+	begin : INSIST_ON_NO_DISCONTINUOUS_STBS
+		// Within my own code, once a request begins it goes to
+		// completion and the CYC line is dropped.  The master
+		// is not allowed to raise STB again after dropping it.
+		// Doing so would be a *discontinuous* request.
+		//
+		// However, in any RMW scheme, discontinuous requests are
+		// necessary, and the spec doesn't disallow them.  Hence we
+		// make this check optional.
+		always @(posedge i_clk)
+		if ((f_past_valid)&&($past(i_wb_cyc))&&(!$past(i_wb_stb)))
+			`SLAVE_ASSUME(!i_wb_stb);
+	end endgenerate
+
+endmodule
+`undef	SLAVE_ASSUME
+`undef	SLAVE_ASSERT
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fwbc_master.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fwbc_master.v
new file mode 100644
index 0000000..732cc62
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fwbc_master.v
@@ -0,0 +1,308 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename:	fwbc_master.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	This file describes the rules of a wishbone *classic*
+//		interaction from the perspective of a wishbone classic master.
+//	These formal rules may be used with SymbiYosys to *prove* that the
+//	master properly generates outgoing responses to drive an (assumed
+//	correct) slave.
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+module	fwbc_master(i_clk, i_reset,
+		// The Wishbone bus
+		i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel,
+			i_wb_cti, i_wb_bte,
+			i_wb_ack, i_wb_idata, i_wb_err, i_wb_rty);
+	parameter		AW=32, DW=32;
+	parameter		F_MAX_DELAY = 4;
+	parameter	[0:0]	OPT_BUS_ABORT = 0;
+	localparam	DLYBITS= $clog2(F_MAX_DELAY+1);
+	//
+	input	wire			i_clk, i_reset;
+	// Input/master bus
+	input	wire			i_wb_cyc, i_wb_stb, i_wb_we;
+	input	wire	[(AW-1):0]	i_wb_addr;
+	input	wire	[(DW-1):0]	i_wb_data;
+	input	wire	[(DW/8-1):0]	i_wb_sel;
+	input	wire	[2:0]		i_wb_cti;
+	input	wire	[1:0]		i_wb_bte;
+	//
+	input	wire			i_wb_ack;
+	input	wire	[(DW-1):0]	i_wb_idata;
+	input	wire			i_wb_err;
+	input	wire			i_wb_rty;
+	//
+
+`define	SLAVE_ASSUME	assert
+`define	SLAVE_ASSERT	assume
+
+	// next_addr, for use in calculating the next address within a
+	// burst
+	reg	[AW-1:0]	next_addr;
+
+
+	//
+	// Wrap the request line in a bundle.  The top bit, named STB_BIT,
+	// is the bit indicating whether the request described by this vector
+	// is a valid request or not.
+	//
+	localparam	STB_BIT = 2+AW+DW+DW/8+3+2-1;
+	wire	[STB_BIT:0]	f_request;
+	assign	f_request = { i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel,
+				i_wb_cti, i_wb_bte };
+
+	//
+	// A quick register to be used later to know if the $past() operator
+	// will yield valid result
+	reg	f_past_valid;
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+	always @(*)
+	if (!f_past_valid)
+		`SLAVE_ASSUME(i_reset);
+	//
+	//
+	// Assertions regarding the initial (and reset) state
+	//
+	//
+
+	//
+	// Assume we start from a reset condition
+	initial assert(i_reset);
+	initial `SLAVE_ASSUME(!i_wb_cyc);
+	initial `SLAVE_ASSUME(!i_wb_stb);
+	//
+	initial	`SLAVE_ASSERT(!i_wb_ack);
+	initial	`SLAVE_ASSERT(!i_wb_err);
+	initial	`SLAVE_ASSERT(!i_wb_rty);
+
+	always @(posedge i_clk)
+	if ((!f_past_valid)||($past(i_reset)))
+	begin
+		`SLAVE_ASSUME(!i_wb_cyc);
+		`SLAVE_ASSUME(!i_wb_stb);
+		//
+		`SLAVE_ASSERT(!i_wb_ack);
+		`SLAVE_ASSERT(!i_wb_err);
+		`SLAVE_ASSERT(!i_wb_rty);
+	end
+
+	//
+	//
+	// Bus requests
+	//
+	//
+
+	// This core only supports classic CTIs.  Burst types are therefore
+	// irrelevant and ignored.
+	always @(*)
+	if (i_wb_stb)
+		`SLAVE_ASSUME(i_wb_cti == 3'b0);
+
+	// STB can only be true if CYC is also true
+	always @(*)
+	if (i_wb_stb)
+		`SLAVE_ASSUME(i_wb_cyc);
+
+	// If a request was both outstanding and stalled on the last clock,
+	// then nothing should change on this clock regarding it.
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_reset))
+			&&($past(i_wb_stb))&&(i_wb_cyc)
+			&&(!$past(i_wb_ack | i_wb_err | i_wb_rty)))
+		`SLAVE_ASSUME(i_wb_stb);
+
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_reset))
+			&&($past(i_wb_stb))&&!$past(i_wb_ack|i_wb_err|i_wb_rty))
+	begin
+		`SLAVE_ASSUME(i_wb_stb);
+		`SLAVE_ASSUME($stable(i_wb_we));
+		`SLAVE_ASSUME($stable(i_wb_addr));
+		`SLAVE_ASSUME($stable(i_wb_sel));
+		`SLAVE_ASSUME($stable(i_wb_cti));
+		`SLAVE_ASSUME($stable(i_wb_bte));
+		if (i_wb_we)
+			`SLAVE_ASSUME($stable(i_wb_data));
+	end
+
+	//
+	//
+	// Bus responses
+	//
+	//
+
+	// If STB (or CYC) was low on the last two clock cycles, then both
+	// ACK and ERR should be low on this clock cycle.
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_wb_stb))&&(!i_wb_stb))
+	begin
+		`SLAVE_ASSERT(!i_wb_ack);
+		`SLAVE_ASSERT(!i_wb_err);
+		`SLAVE_ASSERT(!i_wb_rty);
+	end else if (f_past_valid && $past(i_wb_ack|i_wb_err|i_wb_rty)
+			&& !i_wb_stb)
+	begin
+		`SLAVE_ASSERT(!i_wb_ack);
+		`SLAVE_ASSERT(!i_wb_err);
+		`SLAVE_ASSERT(!i_wb_rty);
+	end
+
+	//
+	// OPT_BUS_ABORT
+	//
+	// If CYC is dropped, this will abort the transaction in
+	// progress.  Not all busses support this option, and it's
+	// not specifically called out in the spec.  Therefore, we'll
+	// check if this is set (it will be clear by default) and
+	// prohibit a transaction from being aborted otherwise
+	always @(posedge i_clk)
+	if (f_past_valid && !$past(i_reset) && !OPT_BUS_ABORT
+		&& $past(i_wb_stb && !(i_wb_ack|i_wb_err|i_wb_rty)))
+		`SLAVE_ASSUME(i_wb_stb);
+
+	//
+	// No more than one of ACK, ERR or RTY may ever be true at a given time
+	always @(*)
+	begin
+		if (i_wb_ack)
+			`SLAVE_ASSERT(!i_wb_err && !i_wb_rty);
+		else if (i_wb_err)
+			`SLAVE_ASSERT(!i_wb_rty);
+	end
+
+	localparam [2:0]	C_CLASSIC = 3'b000;
+	localparam [2:0]	C_FIXED   = 3'b001;
+	localparam [2:0]	C_INCR    = 3'b010;
+	localparam [2:0]	C_EOB     = 3'b111;
+	localparam [1:0]	B_LINEAR = 2'b00;
+	localparam [1:0]	B_WRAP4  = 2'b01;
+	localparam [1:0]	B_WRAP8  = 2'b10;
+	localparam [1:0]	B_WRAP16 = 2'b11;
+
+	// Burst address checking
+	always @(*)
+	if (i_wb_stb)
+	begin
+		// Several designations are reserved.  Using those
+		// designations is "illegal".
+		assert(i_wb_cti != 3'b011);
+		assert(i_wb_cti != 3'b100);
+		assert(i_wb_cti != 3'b101);
+		assert(i_wb_cti != 3'b110);
+	end
+
+	always @(posedge i_clk)
+		next_addr <= i_wb_addr + 1;
+
+	always @(posedge i_clk)
+	if (f_past_valid && !$past(i_reset) && !i_reset
+		&& $past(i_wb_stb)&&($past(i_wb_err|i_wb_rty|i_wb_ack))
+		&&($past(i_wb_cti != C_CLASSIC))&&($past(i_wb_cti != C_EOB)))
+	begin
+		assert(i_wb_stb);
+		if ($past(i_wb_cti) == C_FIXED)
+		begin
+			assert($stable(i_wb_addr));
+			assert((i_wb_cti == C_FIXED || i_wb_cti == C_EOB));
+		end else if ($past(i_wb_cti == C_INCR))
+		begin
+			assert($stable(i_wb_bte));
+			case(i_wb_bte)
+			B_LINEAR: assert(i_wb_addr == next_addr);
+			B_WRAP4: begin
+				// 4-beat wrap burst
+				assert(i_wb_addr[1:0] == next_addr[1:0]);
+				assert($stable(i_wb_addr[AW-1:2]));
+				end
+			B_WRAP8: begin
+				// 8-beat wrap burst
+				assert(i_wb_addr[2:0] == next_addr[2:0]);
+				assert($stable(i_wb_addr[AW-1:3]));
+				end
+			B_WRAP16: begin
+				// 16-beat wrap burst
+				assert(i_wb_addr[3:0] == next_addr[3:0]);
+				assert($stable(i_wb_addr[AW-1:4]));
+				end
+			endcase
+		end
+	end
+
+	generate if (F_MAX_DELAY > 0)
+	begin : DELAYCOUNT
+		//
+		// Assume the slave cannnot stall for more than F_MAX_STALL
+		// counts.  We'll count this forward any time STB and STALL
+		// are both true.
+		//
+		reg	[(DLYBITS-1):0]		f_stall_count;
+
+		initial	f_stall_count = 0;
+		always @(posedge i_clk)
+		if ((!i_reset)&&(i_wb_stb)&&(!i_wb_ack && !i_wb_err && !i_wb_rty))
+			f_stall_count <= f_stall_count + 1'b1;
+		else
+			f_stall_count <= 0;
+
+		always @(*)
+		if (i_wb_cyc)
+			`SLAVE_ASSERT(f_stall_count < F_MAX_DELAY);
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Some basic cover properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	reg	[3:0]	ack_count;
+
+	initial	ack_count = 0;
+	always @(posedge i_clk)
+	if (i_reset || !i_wb_cyc)
+		ack_count <= 0;
+	else if (f_past_valid && i_wb_ack)
+		ack_count <= ack_count + 1;
+
+	always @(*)
+		cover(!i_wb_cyc && ack_count > 4);
+	always @(*)
+		cover(!i_wb_cyc && ack_count > 3);
+
+endmodule
+//
+// Lest some other module want to use these macros, we undefine them here
+`undef	SLAVE_ASSUME
+`undef	SLAVE_ASSERT
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fwbc_slave.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fwbc_slave.v
new file mode 100644
index 0000000..58f25ee
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/fwbc_slave.v
@@ -0,0 +1,308 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename:	fwbc_slave.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	This file describes the rules of a wishbone *classic*
+//		interaction from the perspective of a wishbone classic slave.
+//	These formal rules may be used with SymbiYosys to *prove* that the
+//	slave properly handles outgoing responses to (assumed correct)
+//	incoming requests.
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+module	fwbc_slave(i_clk, i_reset,
+		// The Wishbone bus
+		i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel,
+			i_wb_cti, i_wb_bte,
+			i_wb_ack, i_wb_idata, i_wb_err, i_wb_rty);
+	parameter		AW=32, DW=32;
+	parameter		F_MAX_DELAY = 4;
+	parameter	[0:0]	OPT_BUS_ABORT = 0;
+	localparam	DLYBITS= $clog2(F_MAX_DELAY+1);
+	//
+	input	wire			i_clk, i_reset;
+	// Input/master bus
+	input	wire			i_wb_cyc, i_wb_stb, i_wb_we;
+	input	wire	[(AW-1):0]	i_wb_addr;
+	input	wire	[(DW-1):0]	i_wb_data;
+	input	wire	[(DW/8-1):0]	i_wb_sel;
+	input	wire	[2:0]		i_wb_cti;
+	input	wire	[1:0]		i_wb_bte;
+	//
+	input	wire			i_wb_ack;
+	input	wire	[(DW-1):0]	i_wb_idata;
+	input	wire			i_wb_err;
+	input	wire			i_wb_rty;
+	//
+
+`define	SLAVE_ASSUME	assume
+`define	SLAVE_ASSERT	assert
+
+	// next_addr, for use in calculating the next address within a
+	// burst
+	reg	[AW-1:0]	next_addr;
+
+
+	//
+	// Wrap the request line in a bundle.  The top bit, named STB_BIT,
+	// is the bit indicating whether the request described by this vector
+	// is a valid request or not.
+	//
+	localparam	STB_BIT = 2+AW+DW+DW/8+3+2-1;
+	wire	[STB_BIT:0]	f_request;
+	assign	f_request = { i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel,
+				i_wb_cti, i_wb_bte };
+
+	//
+	// A quick register to be used later to know if the $past() operator
+	// will yield valid result
+	reg	f_past_valid;
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+	always @(*)
+	if (!f_past_valid)
+		`SLAVE_ASSUME(i_reset);
+	//
+	//
+	// Assertions regarding the initial (and reset) state
+	//
+	//
+
+	//
+	// Assume we start from a reset condition
+	initial assert(i_reset);
+	initial `SLAVE_ASSUME(!i_wb_cyc);
+	initial `SLAVE_ASSUME(!i_wb_stb);
+	//
+	initial	`SLAVE_ASSERT(!i_wb_ack);
+	initial	`SLAVE_ASSERT(!i_wb_err);
+	initial	`SLAVE_ASSERT(!i_wb_rty);
+
+	always @(posedge i_clk)
+	if ((!f_past_valid)||($past(i_reset)))
+	begin
+		`SLAVE_ASSUME(!i_wb_cyc);
+		`SLAVE_ASSUME(!i_wb_stb);
+		//
+		`SLAVE_ASSERT(!i_wb_ack);
+		`SLAVE_ASSERT(!i_wb_err);
+		`SLAVE_ASSERT(!i_wb_rty);
+	end
+
+	//
+	//
+	// Bus requests
+	//
+	//
+
+	// This core only supports classic CTIs.  Burst types are therefore
+	// irrelevant and ignored.
+	always @(*)
+	if (i_wb_stb)
+		`SLAVE_ASSUME(i_wb_cti == 3'b0);
+
+	// STB can only be true if CYC is also true
+	always @(*)
+	if (i_wb_stb)
+		`SLAVE_ASSUME(i_wb_cyc);
+
+	// If a request was both outstanding and stalled on the last clock,
+	// then nothing should change on this clock regarding it.
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_reset))
+			&&($past(i_wb_stb))&&(i_wb_cyc)
+			&&(!$past(i_wb_ack | i_wb_err | i_wb_rty)))
+		`SLAVE_ASSUME(i_wb_stb);
+
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_reset))
+			&&($past(i_wb_stb))&&!$past(i_wb_ack|i_wb_err|i_wb_rty))
+	begin
+		`SLAVE_ASSUME(i_wb_stb);
+		`SLAVE_ASSUME($stable(i_wb_we));
+		`SLAVE_ASSUME($stable(i_wb_addr));
+		`SLAVE_ASSUME($stable(i_wb_sel));
+		`SLAVE_ASSUME($stable(i_wb_cti));
+		`SLAVE_ASSUME($stable(i_wb_bte));
+		if (i_wb_we)
+			`SLAVE_ASSUME($stable(i_wb_data));
+	end
+
+	//
+	//
+	// Bus responses
+	//
+	//
+
+	// If STB (or CYC) was low on the last two clock cycles, then both
+	// ACK and ERR should be low on this clock cycle.
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_wb_stb))&&(!i_wb_stb))
+	begin
+		`SLAVE_ASSERT(!i_wb_ack);
+		`SLAVE_ASSERT(!i_wb_err);
+		`SLAVE_ASSERT(!i_wb_rty);
+	end else if (f_past_valid && $past(i_wb_ack|i_wb_err|i_wb_rty)
+			&& !i_wb_stb)
+	begin
+		`SLAVE_ASSERT(!i_wb_ack);
+		`SLAVE_ASSERT(!i_wb_err);
+		`SLAVE_ASSERT(!i_wb_rty);
+	end
+
+	//
+	// OPT_BUS_ABORT
+	//
+	// If CYC is dropped, this will abort the transaction in
+	// progress.  Not all busses support this option, and it's
+	// not specifically called out in the spec.  Therefore, we'll
+	// check if this is set (it will be clear by default) and
+	// prohibit a transaction from being aborted otherwise
+	always @(posedge i_clk)
+	if (f_past_valid && !$past(i_reset) && !OPT_BUS_ABORT
+		&& $past(i_wb_stb && !(i_wb_ack|i_wb_err|i_wb_rty)))
+		`SLAVE_ASSUME(i_wb_stb);
+
+	//
+	// No more than one of ACK, ERR or RTY may ever be true at a given time
+	always @(*)
+	begin
+		if (i_wb_ack)
+			`SLAVE_ASSERT(!i_wb_err && !i_wb_rty);
+		else if (i_wb_err)
+			`SLAVE_ASSERT(!i_wb_rty);
+	end
+
+	localparam [2:0]	C_CLASSIC = 3'b000;
+	localparam [2:0]	C_FIXED   = 3'b001;
+	localparam [2:0]	C_INCR    = 3'b010;
+	localparam [2:0]	C_EOB     = 3'b111;
+	localparam [1:0]	B_LINEAR = 2'b00;
+	localparam [1:0]	B_WRAP4  = 2'b01;
+	localparam [1:0]	B_WRAP8  = 2'b10;
+	localparam [1:0]	B_WRAP16 = 2'b11;
+
+	// Burst address checking
+	always @(*)
+	if (i_wb_stb)
+	begin
+		// Several designations are reserved.  Using those
+		// designations is "illegal".
+		assert(i_wb_cti != 3'b011);
+		assert(i_wb_cti != 3'b100);
+		assert(i_wb_cti != 3'b101);
+		assert(i_wb_cti != 3'b110);
+	end
+
+	always @(posedge i_clk)
+		next_addr <= i_wb_addr + 1;
+
+	always @(posedge i_clk)
+	if (f_past_valid && !$past(i_reset) && !i_reset
+		&& $past(i_wb_stb)&&($past(i_wb_err|i_wb_rty|i_wb_ack))
+		&&($past(i_wb_cti != C_CLASSIC))&&($past(i_wb_cti != C_EOB)))
+	begin
+		assert(i_wb_stb);
+		if ($past(i_wb_cti) == C_FIXED)
+		begin
+			assert($stable(i_wb_addr));
+			assert((i_wb_cti == C_FIXED || i_wb_cti == C_EOB));
+		end else if ($past(i_wb_cti == C_INCR))
+		begin
+			assert($stable(i_wb_bte));
+			case(i_wb_bte)
+			B_LINEAR: assert(i_wb_addr == next_addr);
+			B_WRAP4: begin
+				// 4-beat wrap burst
+				assert(i_wb_addr[1:0] == next_addr[1:0]);
+				assert($stable(i_wb_addr[AW-1:2]));
+				end
+			B_WRAP8: begin
+				// 8-beat wrap burst
+				assert(i_wb_addr[2:0] == next_addr[2:0]);
+				assert($stable(i_wb_addr[AW-1:3]));
+				end
+			B_WRAP16: begin
+				// 16-beat wrap burst
+				assert(i_wb_addr[3:0] == next_addr[3:0]);
+				assert($stable(i_wb_addr[AW-1:4]));
+				end
+			endcase
+		end
+	end
+
+	generate if (F_MAX_DELAY > 0)
+	begin : DELAYCOUNT
+		//
+		// Assume the slave cannnot stall for more than F_MAX_STALL
+		// counts.  We'll count this forward any time STB and STALL
+		// are both true.
+		//
+		reg	[(DLYBITS-1):0]		f_stall_count;
+
+		initial	f_stall_count = 0;
+		always @(posedge i_clk)
+		if ((!i_reset)&&(i_wb_stb)&&(!i_wb_ack && !i_wb_err && !i_wb_rty))
+			f_stall_count <= f_stall_count + 1'b1;
+		else
+			f_stall_count <= 0;
+
+		always @(*)
+		if (i_wb_cyc)
+			`SLAVE_ASSERT(f_stall_count < F_MAX_DELAY);
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Some basic cover properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	reg	[3:0]	ack_count;
+
+	initial	ack_count = 0;
+	always @(posedge i_clk)
+	if (i_reset || !i_wb_cyc)
+		ack_count <= 0;
+	else if (f_past_valid && i_wb_ack)
+		ack_count <= ack_count + 1;
+
+	always @(*)
+		cover(!i_wb_cyc && ack_count > 4);
+	always @(*)
+		cover(!i_wb_cyc && ack_count > 3);
+
+endmodule
+//
+// Lest some other module want to use these macros, we undefine them here
+`undef	SLAVE_ASSUME
+`undef	SLAVE_ASSERT
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/passcheck.sh b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/passcheck.sh
new file mode 100755
index 0000000..422ba93
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/passcheck.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+################################################################################
+##
+## Filename: 	passcheck.sh
+##
+## Project:	WB2AXIPSP: bus bridges and other odds and ends
+##
+## Purpose:	This script simply checks for failing proofs of any type,
+##		printing out the files associated with any such failing proofs.
+##
+## Creator:	Dan Gisselquist, Ph.D.
+##		Gisselquist Technology, LLC
+##
+################################################################################
+##
+## This simple bash script is herein donated to the public domain
+##
+################################################################################
+##
+##
+## Sort these results to give them a consistent order
+##
+find . -name FAIL    | sort
+find . -name UNKNOWN | sort
+find . -name ERROR   | sort
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/sfifo.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/sfifo.sby
new file mode 100644
index 0000000..4602888
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/sfifo.sby
@@ -0,0 +1,34 @@
+[tasks]
+prf     prf
+prf_r	prf                 opt_read_on_empty
+prf_w	prf                                   opt_write_on_full
+prf_wr	prf                 opt_read_on_empty opt_write_on_full
+prf_a	prf opt_async_read
+prf_ar	prf opt_async_read opt_read_on_empty
+prf_aw	prf opt_async_read                   opt_write_on_full
+prf_awr	prf opt_async_read opt_read_on_empty opt_write_on_full
+cvr
+
+[options]
+cvr: mode cover
+cvr: depth 22
+prf: mode prove
+prf: depth 4
+
+[engines]
+smtbmc
+
+[script]
+read -define SFIFO
+read -formal sfifo.v
+--pycode-begin--
+cmd = "hierarchy -top sfifo"
+cmd += " -chparam OPT_ASYNC_READ  %d" % ( 1 if "opt_async_read" in tags else 0)
+cmd += " -chparam OPT_WRITE_ON_FULL  %d" % ( 1 if "opt_write_on_full" in tags else 0)
+cmd += " -chparam OPT_READ_ON_EMPTY  %d" % ( 1 if "opt_read_on_empty" in tags else 0)
+output(cmd)
+--pycode-end--
+prep -top sfifo
+
+[files]
+../../rtl/sfifo.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/skidbuffer.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/skidbuffer.gtkw
new file mode 100644
index 0000000..c944098
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/skidbuffer.gtkw
@@ -0,0 +1,51 @@
+[*]
+[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
+[*] Tue May 14 23:56:06 2019
+[*]
+[dumpfile] "(null)"
+[dumpfile_mtime] "Tue May 14 23:30:00 2019"
+[dumpfile_size] 3009
+[timestart] 0
+[size] 1177 600
+[pos] -1 -1
+*-5.436488 80 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 270
+[signals_width] 170
+[sst_expanded] 1
+[sst_vpaned_height] 143
+@28
+skidbuffer.i_clk
+skidbuffer.i_reset
+@200
+-
+@28
+[color] 3
+skidbuffer.i_valid
+[color] 2
+skidbuffer.o_ready
+@22
+[color] 3
+skidbuffer.i_data[7:0]
+@200
+-
+@28
+skidbuffer.r_valid
+@22
+skidbuffer.r_data[7:0]
+@200
+-
+@22
+skidbuffer.next_data[7:0]
+@200
+-
+@28
+[color] 2
+skidbuffer.o_valid
+@29
+[color] 3
+skidbuffer.i_ready
+@22
+[color] 2
+skidbuffer.o_data[7:0]
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/skidbuffer.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/skidbuffer.sby
new file mode 100644
index 0000000..5226d2e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/skidbuffer.sby
@@ -0,0 +1,29 @@
+[tasks]
+prfc prf
+prfo prf              opt_outreg
+lpc  prf opt_lowpower
+lpo  prf opt_lowpower opt_outreg
+cvr
+
+[options]
+prf: mode prove
+prf: depth 12
+cvr: mode cover
+cvr: depth 20
+
+[engines]
+smtbmc
+
+[script]
+read -define SKIDBUFFER
+read -formal skidbuffer.v
+--pycode-begin--
+cmd = "hierarchy -top skidbuffer"
+cmd += " -chparam OPT_LOWPOWER %d" % (1 if "opt_lowpower" in tags else 0)
+cmd += " -chparam OPT_OUTREG   %d" % (1 if "opt_outreg"   in tags else 0)
+output(cmd);
+--pycode-end--
+prep -top skidbuffer
+
+[files]
+../../rtl/skidbuffer.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbarbiter.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbarbiter.gtkw
new file mode 100644
index 0000000..0374c53
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbarbiter.gtkw
@@ -0,0 +1,71 @@
+[*]
+[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
+[*] Fri Dec 28 02:53:33 2018
+[*]
+[dumpfile] "(null)"
+[dumpfile_mtime] "Fri Dec 28 02:48:56 2018"
+[dumpfile_size] 13681
+[timestart] 0
+[size] 1441 600
+[pos] -1 -1
+*-4.552812 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 270
+[signals_width] 160
+[sst_expanded] 1
+[sst_vpaned_height] 143
+@28
+wbarbiter.i_clk
+wbarbiter.i_reset
+@200
+-
+@28
+wbarbiter.i_a_cyc
+wbarbiter.i_a_stb
+wbarbiter.i_a_we
+@22
+wbarbiter.i_a_adr[31:0]
+wbarbiter.i_a_dat[31:0]
+wbarbiter.i_a_sel[3:0]
+@29
+[color] 2
+wbarbiter.o_a_stall
+[color] 2
+wbarbiter.o_a_ack
+[color] 2
+wbarbiter.o_a_err
+@200
+-
+@28
+wbarbiter.i_b_cyc
+wbarbiter.i_b_stb
+wbarbiter.i_b_we
+@22
+wbarbiter.i_b_adr[31:0]
+wbarbiter.i_b_dat[31:0]
+wbarbiter.i_b_sel[3:0]
+@28
+[color] 2
+wbarbiter.o_b_stall
+[color] 2
+wbarbiter.o_b_ack
+[color] 2
+wbarbiter.o_b_err
+@200
+-
+@28
+wbarbiter.o_cyc
+wbarbiter.o_stb
+wbarbiter.o_we
+@22
+wbarbiter.o_adr[31:0]
+wbarbiter.o_dat[31:0]
+wbarbiter.o_sel[3:0]
+@28
+[color] 2
+wbarbiter.i_ack
+[color] 2
+wbarbiter.i_stall
+[color] 2
+wbarbiter.i_err
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbarbiter.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbarbiter.sby
new file mode 100644
index 0000000..c278a83
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbarbiter.sby
@@ -0,0 +1,23 @@
+[tasks]
+prf
+cvr
+
+[options]
+prf: mode prove
+prf: depth 4
+cvr: mode cover
+cvr: depth 32
+
+[engines]
+smtbmc
+
+[script]
+read -formal -D WBARBITER wbarbiter.v
+read -formal -D WBARBITER fwb_slave.v
+read -formal -D WBARBITER fwb_master.v
+prep -top wbarbiter
+
+[files]
+../../rtl/wbarbiter.v
+fwb_slave.v
+fwb_master.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbc2pipeline.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbc2pipeline.sby
new file mode 100644
index 0000000..21ec10d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbc2pipeline.sby
@@ -0,0 +1,23 @@
+[tasks]
+prf
+cvr
+
+[options]
+prf: mode prove
+prf: depth 14
+cvr: mode cover
+cvr: depth 40
+
+[engines]
+smtbmc
+
+[script]
+read -formal wbc2pipeline.v
+read -formal fwb_master.v
+read -formal fwbc_slave.v
+prep -top wbc2pipeline
+
+[files]
+../../rtl/wbc2pipeline.v
+fwb_master.v
+fwbc_slave.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbm2axilite.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbm2axilite.sby
new file mode 100644
index 0000000..d03f3c3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbm2axilite.sby
@@ -0,0 +1,23 @@
+[tasks]
+prf
+cvr
+
+[options]
+prf: mode prove
+prf: depth 18
+cvr: mode cover
+cvr: depth 32
+
+[engines]
+smtbmc
+
+[script]
+read -formal -D AXILRD2WBSP wbm2axilite.v
+read -formal -D AXILRD2WBSP faxil_master.v
+read -formal -D AXILRD2WBSP fwb_slave.v
+prep -top wbm2axilite
+
+[files]
+../../rtl/wbm2axilite.v
+faxil_master.v
+fwb_slave.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbm2axisp.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbm2axisp.sby
new file mode 100644
index 0000000..4216983
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbm2axisp.sby
@@ -0,0 +1,50 @@
+[tasks]
+cvr
+prfx8		prf
+prfx16		prf
+prfe32		prf
+prfx32		prf
+prfx64		prf
+prfx128		prf
+prfx256		prf
+prfx512		prf
+prfx1024	prf
+
+[options]
+prf: mode prove
+prf: depth 15
+cvr: mode cover
+cvr: depth 48
+
+[engines]
+smtbmc
+
+[script]
+read -formal -D WBM2AXISP wbm2axisp.v
+read -formal -D WBM2AXISP skidbuffer.v
+read -formal -D WBM2AXISP faxi_master.v
+read -formal -D WBM2AXISP faxi_addr.v
+read -formal -D WBM2AXISP faxi_wstrb.v
+read -formal -D WBM2AXISP faxi_valaddr.v
+read -formal -D WBM2AXISP fwb_slave.v
+prfx8:    hierarchy -top wbm2axisp -chparam DW  8 -chparam AW 20 -chparam C_AXI_DATA_WIDTH    8 -chparam C_AXI_ADDR_WIDTH 20
+prfx16:   hierarchy -top wbm2axisp -chparam DW  8 -chparam AW 20 -chparam C_AXI_DATA_WIDTH   16 -chparam C_AXI_ADDR_WIDTH 20
+prfe32:   hierarchy -top wbm2axisp -chparam DW  8 -chparam AW 20 -chparam C_AXI_DATA_WIDTH   32 -chparam C_AXI_ADDR_WIDTH 20
+prfx32:   hierarchy -top wbm2axisp -chparam DW 32 -chparam AW 20 -chparam C_AXI_DATA_WIDTH   32 -chparam C_AXI_ADDR_WIDTH 22
+prfx64:   hierarchy -top wbm2axisp -chparam DW 32 -chparam AW 20 -chparam C_AXI_DATA_WIDTH   64 -chparam C_AXI_ADDR_WIDTH 22
+prfx128:  hierarchy -top wbm2axisp -chparam DW 32 -chparam AW 20 -chparam C_AXI_DATA_WIDTH  128 -chparam C_AXI_ADDR_WIDTH 22
+prfx256:  hierarchy -top wbm2axisp -chparam DW 32 -chparam AW 20 -chparam C_AXI_DATA_WIDTH  256 -chparam C_AXI_ADDR_WIDTH 22
+prfx512:  hierarchy -top wbm2axisp -chparam DW 32 -chparam AW 20 -chparam C_AXI_DATA_WIDTH  512 -chparam C_AXI_ADDR_WIDTH 22
+prfx1024: hierarchy -top wbm2axisp -chparam DW 32 -chparam AW 20 -chparam C_AXI_DATA_WIDTH 1024 -chparam C_AXI_ADDR_WIDTH 22
+cvr:      hierarchy -top wbm2axisp -chparam DW 32 -chparam AW 20 -chparam C_AXI_DATA_WIDTH   32 -chparam C_AXI_ADDR_WIDTH 22
+#
+prep -top wbm2axisp
+
+[files]
+../../rtl/wbm2axisp.v
+../../rtl/skidbuffer.v
+faxi_master.v
+faxi_addr.v
+faxi_valaddr.v
+faxi_wstrb.v
+fwb_slave.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbm2axisp.ys b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbm2axisp.ys
new file mode 100644
index 0000000..3a8a9b5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbm2axisp.ys
@@ -0,0 +1,6 @@
+read_verilog -D WBM2AXISP -formal ../../rtl/wbm2axisp.v
+read_verilog -D WBM2AXISP -formal faxi_master.v
+read_verilog -D WBM2AXISP -formal fwb_slave.v
+prep -top wbm2axisp -nordff
+opt -share_all
+write_smt2 -wires wbm2axisp.smt2
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbp2classic.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbp2classic.gtkw
new file mode 100644
index 0000000..23f75b8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbp2classic.gtkw
@@ -0,0 +1,82 @@
+[*]
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Wed Apr 24 17:19:47 2019
+[*]
+[dumpfile] "(null)"
+[dumpfile_mtime] "Wed Apr 24 17:13:31 2019"
+[dumpfile_size] 14390
+[timestart] 0
+[size] 1673 812
+[pos] -1 -213
+*-5.270011 130 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 196
+[signals_width] 134
+[sst_expanded] 1
+[sst_vpaned_height] 230
+@28
+wbp2classic.i_clk
+wbp2classic.i_reset
+@200
+-
+@28
+[color] 3
+wbp2classic.i_mcyc
+[color] 3
+wbp2classic.i_mstb
+[color] 3
+wbp2classic.i_mwe
+@22
+[color] 3
+wbp2classic.i_maddr[11:0]
+[color] 3
+wbp2classic.i_mdata[31:0]
+[color] 3
+wbp2classic.i_msel[3:0]
+@200
+-
+@28
+[color] 2
+wbp2classic.o_mstall
+[color] 2
+wbp2classic.o_mack
+@22
+[color] 2
+wbp2classic.o_mdata[31:0]
+@28
+[color] 2
+wbp2classic.o_merr
+@200
+-
+@28
+[color] 3
+wbp2classic.o_scyc
+[color] 3
+wbp2classic.o_sstb
+[color] 3
+wbp2classic.o_swe
+@22
+[color] 3
+wbp2classic.o_saddr[11:0]
+[color] 3
+wbp2classic.o_sdata[31:0]
+@23
+[color] 3
+wbp2classic.o_ssel[3:0]
+@200
+-
+@28
+[color] 2
+wbp2classic.i_sack
+@22
+[color] 2
+wbp2classic.i_sdata[31:0]
+@28
+[color] 2
+wbp2classic.i_serr
+@200
+-
+@28
+wbp2classic.o_sbti[1:0]
+wbp2classic.o_scti[2:0]
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbp2classic.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbp2classic.sby
new file mode 100644
index 0000000..e1bb5f6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbp2classic.sby
@@ -0,0 +1,23 @@
+[tasks]
+prf
+cvr
+
+[options]
+prf: mode prove
+prf: depth 14
+cvr: mode cover
+cvr: depth 40
+
+[engines]
+smtbmc
+
+[script]
+read -formal wbp2classic.v
+read -formal fwb_slave.v
+read -formal fwbc_master.v
+prep -top wbp2classic
+
+[files]
+../../rtl/wbp2classic.v
+fwb_slave.v
+fwbc_master.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbsafety.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbsafety.gtkw
new file mode 100644
index 0000000..8a08a3c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbsafety.gtkw
@@ -0,0 +1,93 @@
+[*]
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Thu Feb 20 19:41:28 2020
+[*]
+[dumpfile] "(null)"
+[timestart] 0
+[size] 1920 1054
+[pos] -1 -1
+*-4.567505 40 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] wbsafety.
+[treeopen] wbsafety.wbs.
+[sst_width] 196
+[signals_width] 198
+[sst_expanded] 1
+[sst_vpaned_height] 315
+@28
+wbsafety.i_clk
+wbsafety.i_reset
+@200
+-
+@28
+[color] 3
+wbsafety.i_wb_cyc
+[color] 3
+wbsafety.i_wb_stb
+[color] 3
+wbsafety.i_wb_we
+@22
+[color] 3
+wbsafety.i_wb_addr[27:0]
+[color] 3
+wbsafety.i_wb_data[31:0]
+[color] 3
+wbsafety.i_wb_sel[3:0]
+@28
+wbsafety.o_wb_stall
+wbsafety.o_wb_ack
+@22
+wbsafety.o_wb_idata[31:0]
+@28
+wbsafety.o_wb_err
+@201
+-
+@22
+wbsafety.fwbs_nacks[3:0]
+wbsafety.fwbs_nreqs[3:0]
+wbsafety.fwbs_outstanding[3:0]
+@200
+-
+@28
+wbsafety.o_wb_cyc
+wbsafety.o_wb_stb
+wbsafety.o_wb_we
+@22
+wbsafety.o_wb_addr[27:0]
+wbsafety.o_wb_data[31:0]
+wbsafety.o_wb_sel[3:0]
+@28
+[color] 2
+wbsafety.i_wb_stall
+[color] 2
+wbsafety.i_wb_ack
+@22
+[color] 2
+wbsafety.i_wb_idata[31:0]
+@28
+[color] 2
+wbsafety.i_wb_err
+@200
+-
+@28
+[color] 1
+wbsafety.o_fault
+[color] 1
+wbsafety.o_reset
+@200
+-
+@22
+wbsafety.stall_timer[3:0]
+wbsafety.wait_timer[3:0]
+@200
+-
+@28
+wbsafety.timeout
+@200
+-
+@22
+wbsafety.expected_returns[3:0]
+@28
+wbsafety.none_expected
+wbsafety.faulty_return
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbsafety.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbsafety.sby
new file mode 100644
index 0000000..4dd83d9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbsafety.sby
@@ -0,0 +1,35 @@
+[tasks]
+prf
+cvr    fault     opt_reset
+fault        prf
+prfr         prf opt_reset
+faultr fault prf opt_reset
+
+[options]
+prf: mode prove
+prf: depth 6
+cvr: mode cover
+cvr: depth 32
+
+[engines]
+smtbmc
+
+[script]
+read -formal wbsafety.v
+read -formal skidbuffer.v
+read -formal fwb_slave.v
+read -formal fwb_master.v
+--pycode-begin--
+cmd = "hierarchy -top wbsafety"
+cmd += " -chparam F_OPT_FAULTLESS %d" % (0 if "fault"     in tags else 1)
+cmd += " -chparam OPT_SELF_RESET  %d" % (1 if "opt_reset" in tags else 0)
+cmd += " -chparam OPT_TIMEOUT 10"
+output(cmd)
+--pycode-end--
+prep -top wbsafety
+
+[files]
+../../rtl/skidbuffer.v
+../../rtl/wbsafety.v
+fwb_slave.v
+fwb_master.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbxbar.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbxbar.sby
new file mode 100644
index 0000000..a62ffef
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbxbar.sby
@@ -0,0 +1,92 @@
+[tasks]
+prf4x8_buflp	nxm opt_dblbuffer opt_lowpower
+prf4x8_buf	nxm opt_dblbuffer
+prf4x8_lp       nxm               opt_lowpower
+prf4x8_cheap    nxm
+cvr4x8_buflp	nxm opt_dblbuffer opt_lowpower cvr
+cvr4x8_buf	nxm opt_dblbuffer              cvr
+cvr4x8_lp       nxm               opt_lowpower cvr
+cvr4x8_cheap    nxm                            cvr
+prf4x8_buflpko	nxm opt_dblbuffer opt_lowpower opt_timeout
+prf4x8_bufko	nxm opt_dblbuffer              opt_timeout
+prf4x8_lpko     nxm               opt_lowpower opt_timeout
+prf4x8_cheapko  nxm                            opt_timeout
+prf4x8_buflpkos	nxm opt_dblbuffer opt_lowpower opt_timeout opt_starvation
+prf4x8_bufkos	nxm opt_dblbuffer              opt_timeout opt_starvation
+prf4x8_lpkos    nxm               opt_lowpower opt_timeout opt_starvation
+prf4x8_cheapkos nxm                            opt_timeout opt_starvation
+prf1x8_buflp	oxm opt_dblbuffer opt_lowpower
+prf1x8_buf	oxm opt_dblbuffer
+prf1x8_lp       oxm               opt_lowpower
+prf1x8_cheap    oxm
+cvr1x3_buflp	oxl opt_dblbuffer opt_lowpower cvr
+cvr1x3_buf	oxl opt_dblbuffer              cvr
+cvr1x3_lp       oxl               opt_lowpower cvr
+cvr1x3_cheap    oxl                            cvr
+prf1x8_buflpko	oxm opt_dblbuffer opt_lowpower opt_timeout
+prf1x8_bufko	oxm opt_dblbuffer              opt_timeout
+prf1x8_lpko     oxm               opt_lowpower opt_timeout
+prf1x8_cheapko  oxm                            opt_timeout
+prf1x8_buflpkos	oxm opt_dblbuffer opt_lowpower opt_timeout opt_starvation
+prf1x8_bufkos	oxm opt_dblbuffer              opt_timeout opt_starvation
+prf1x8_lpkos    oxm               opt_lowpower opt_timeout opt_starvation
+prf1x8_cheapkos oxm                            opt_timeout opt_starvation
+prf4x1_buflp	nxo opt_dblbuffer opt_lowpower
+prf4x1_buf	nxo opt_dblbuffer
+prf4x1_lp       nxo               opt_lowpower
+prf4x1_cheap    nxo
+cvr4x1_buflp	nxo opt_dblbuffer opt_lowpower cvr
+cvr4x1_buf	nxo opt_dblbuffer              cvr
+cvr4x1_lp       nxo               opt_lowpower cvr
+cvr4x1_cheap    nxo                            cvr
+prf4x1_buflpko	nxo opt_dblbuffer opt_lowpower opt_timeout
+prf4x1_bufko	nxo opt_dblbuffer              opt_timeout
+prf4x1_lpko     nxo               opt_lowpower opt_timeout
+prf4x1_cheapko  nxo                            opt_timeout
+prf4x1_buflpkos	nxo opt_dblbuffer opt_lowpower opt_timeout opt_starvation
+prf4x1_bufkos	nxo opt_dblbuffer              opt_timeout opt_starvation
+prf4x1_lpkos    nxo               opt_lowpower opt_timeout opt_starvation
+prf4x1_cheapkos nxo                            opt_timeout opt_starvation
+
+[options]
+~cvr: mode prove
+~cvr: depth 6
+cvr: mode cover
+cvr: depth 64
+
+[engines]
+smtbmc boolector
+# smtbmc yices
+# smtbmc z3
+
+
+[script]
+read -formal addrdecode.v
+read -formal skidbuffer.v
+read -formal wbxbar.v
+read -formal fwb_slave.v
+read -formal fwb_master.v
+--pycode-begin--
+cmd = "hierarchy -top wbxbar"
+if ("nxm" in tags):
+	cmd += " -chparam  NM 4 -chparam NS 8"
+if ("oxm" in tags):
+	cmd += " -chparam  NM 1 -chparam NS 8"
+if ("oxl" in tags):
+	cmd += " -chparam  NM 1 -chparam NS 3"
+if ("nxo" in tags):
+	cmd += " -chparam  NM 4 -chparam NS 1"
+cmd += " -chparam OPT_DBLBUFFER %d" % (1  if "opt_dblbuffer" in tags else 0)
+cmd += " -chparam OPT_LOWPOWER  %d" % (1  if "opt_lowpower"  in tags else 0)
+cmd += " -chparam OPT_TIMEOUT   %d" % (20 if "opt_timeout"   in tags else 0)
+cmd += " -chparam OPT_STARVATION_TIMEOUT %d" % (1 if "opt_starvation" in tags else 0)
+output(cmd)
+--pycode-end--
+prep -top wbxbar
+
+[files]
+../../rtl/skidbuffer.v
+../../rtl/addrdecode.v
+../../rtl/wbxbar.v
+fwb_slave.v
+fwb_master.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbxclk.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbxclk.gtkw
new file mode 100644
index 0000000..d84c5a1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbxclk.gtkw
@@ -0,0 +1,148 @@
+[*]
+[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
+[*] Mon May  4 03:06:56 2020
+[*]
+[dumpfile] "(null)"
+[timestart] 0
+[size] 1920 1021
+[pos] -1 -1
+*-5.552812 130 130 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] wbxclk.
+[treeopen] wbxclk.reqfifo.
+[sst_width] 270
+[signals_width] 240
+[sst_expanded] 1
+[sst_vpaned_height] 290
+@28
+wbxclk.i_reset
+wbxclk.i_wb_clk
+@200
+-
+@800200
+-Upstream WB
+@28
+[color] 3
+wbxclk.i_wb_cyc
+[color] 3
+wbxclk.i_wb_stb
+[color] 3
+wbxclk.i_wb_we
+@22
+[color] 3
+wbxclk.i_wb_addr[31:0]
+[color] 3
+wbxclk.i_wb_data[31:0]
+[color] 3
+wbxclk.i_wb_sel[3:0]
+@28
+[color] 2
+wbxclk.o_wb_stall
+[color] 2
+wbxclk.o_wb_ack
+@22
+[color] 2
+wbxclk.o_wb_data[31:0]
+@28
+[color] 2
+wbxclk.o_wb_err
+@22
+wbxclk.fwb_outstanding[5:0]
+@28
+wbxclk.wb_active
+@1000200
+-Upstream WB
+@28
+wbxclk.i_xclk_clk
+wbxclk.xck_reset
+wbxclk.bus_abort
+@800200
+-Downstream
+@28
+[color] 2
+wbxclk.o_xclk_cyc
+[color] 2
+wbxclk.o_xclk_stb
+[color] 2
+wbxclk.o_xclk_we
+@22
+[color] 2
+wbxclk.o_xclk_addr[31:0]
+[color] 2
+wbxclk.o_xclk_data[31:0]
+[color] 2
+wbxclk.o_xclk_sel[3:0]
+@28
+[color] 3
+wbxclk.i_xclk_stall
+[color] 3
+wbxclk.i_xclk_ack
+@22
+[color] 3
+wbxclk.i_xclk_data[31:0]
+@28
+[color] 1
+wbxclk.i_xclk_err
+@22
+wbxclk.fxck_outstanding[5:0]
+@29
+wbxclk.xclk_err_state
+@1000200
+-Downstream
+@800200
+-Req FIFO
+@28
+wbxclk.reqfifo.i_wclk
+wbxclk.reqfifo.i_wr_reset_n
+wbxclk.reqfifo.i_wr
+@22
+wbxclk.reqfifo.i_wr_data[69:0]
+@28
+wbxclk.reqfifo.o_wr_full
+@22
+wbxclk.reqfifo.wr_addr[5:0]
+@200
+-
+@28
+wbxclk.reqfifo.i_rclk
+wbxclk.reqfifo.i_rd_reset_n
+wbxclk.reqfifo.i_rd
+@22
+wbxclk.reqfifo.o_rd_data[69:0]
+@28
+wbxclk.reqfifo.o_rd_empty
+@22
+wbxclk.reqfifo.rd_addr[5:0]
+wbxclk.reqfifo_fill[5:0]
+@200
+-
+@22
+wbxclk.reqfifo.rd_addr[5:0]
+wbxclk.reqfifo.wr_addr[5:0]
+@1000200
+-Req FIFO
+@c00200
+-ACK FIFO
+@28
+wbxclk.ackfifo.i_wclk
+wbxclk.ackfifo.i_wr_reset_n
+wbxclk.ackfifo.i_wr
+@22
+wbxclk.ackfifo.i_wr_data[33:0]
+@28
+wbxclk.ackfifo.o_wr_full
+@200
+-
+@28
+wbxclk.ackfifo.i_rclk
+wbxclk.ackfifo.i_rd
+wbxclk.ackfifo.i_rd_reset_n
+@22
+wbxclk.ackfifo.o_rd_data[33:0]
+@28
+wbxclk.ackfifo.o_rd_empty
+@22
+wbxclk.ackfifo_fill[5:0]
+@1401200
+-ACK FIFO
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbxclk.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbxclk.sby
new file mode 100644
index 0000000..48a5a04
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/wbxclk.sby
@@ -0,0 +1,31 @@
+[tasks]
+bmc
+prf
+cvr
+
+[options]
+bmc: mode bmc
+bmc: depth 50
+prf: mode prove
+prf: depth 17
+cvr: mode cover
+cvr: depth 90	# 72 should be sufficient
+multiclock on
+
+[engines]
+smtbmc
+
+[script]
+~prf: read -formal -DBMC wbxclk.v
+prf:  read -formal       wbxclk.v
+read -formal afifo.v
+read -formal fwb_slave.v
+read -formal fwb_master.v
+cvr: hierarchy -top wbxclk -chparam LGFIFO 3
+prep -top wbxclk
+
+[files]
+../../rtl/afifo.v
+../../rtl/wbxclk.v
+fwb_slave.v
+fwb_master.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxdemo.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxdemo.gtkw
new file mode 100644
index 0000000..8b0c396
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxdemo.gtkw
@@ -0,0 +1,61 @@
+[*]
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Thu Dec 27 16:19:38 2018
+[*]
+[dumpfile] "(null)"
+[dumpfile_mtime] "Thu Dec 27 03:40:12 2018"
+[dumpfile_size] 68959
+[timestart] 0
+[size] 1473 600
+[pos] -474 -1
+*-6.470208 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 196
+[signals_width] 166
+[sst_expanded] 1
+[sst_vpaned_height] 155
+@29
+[color] 3
+xlnxdemo.S_AXI_ARESETN
+[color] 3
+xlnxdemo.S_AXI_ACLK
+@200
+-
+@28
+xlnxdemo.S_AXI_AWVALID
+xlnxdemo.S_AXI_AWREADY
+@22
+xlnxdemo.S_AXI_AWADDR[6:0]
+@200
+-
+@28
+xlnxdemo.S_AXI_WVALID
+xlnxdemo.S_AXI_WREADY
+@22
+xlnxdemo.S_AXI_WSTRB[3:0]
+xlnxdemo.S_AXI_WDATA[31:0]
+@200
+-
+@28
+[color] 2
+xlnxdemo.S_AXI_BVALID
+[color] 2
+xlnxdemo.S_AXI_BREADY
+@200
+-
+@28
+xlnxdemo.S_AXI_ARVALID
+xlnxdemo.S_AXI_ARREADY
+@22
+xlnxdemo.S_AXI_ARADDR[6:0]
+@200
+-
+@28
+[color] 2
+xlnxdemo.S_AXI_RVALID
+[color] 2
+xlnxdemo.S_AXI_RREADY
+@22
+[color] 2
+xlnxdemo.S_AXI_RDATA[31:0]
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxdemo.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxdemo.sby
new file mode 100644
index 0000000..7b61734
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxdemo.sby
@@ -0,0 +1,21 @@
+[tasks]
+cvr
+prf
+
+[options]
+cvr: mode cover
+cvr: depth 60
+prf: mode prove
+prf: depth 40
+
+[engines]
+smtbmc
+
+[script]
+read -formal xlnxdemo.v
+read -formal faxil_slave.v
+prep -top xlnxdemo
+
+[files]
+xlnxdemo.v
+faxil_slave.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxdemo.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxdemo.v
new file mode 100644
index 0000000..ee19767
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxdemo.v
@@ -0,0 +1,1103 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	xlnxdemo.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	To test the formal tools on an AXI-lite core that is "known"
+//		to work.  (Only this one doesn't--at least that was my purpose.
+//	Most of this code comes directly from Vivado's core generator--starting
+//	at the end of this comment block and going down directly to the
+//	`ifdef	FORMAL block at the bottom.  I have made superficial adjustments
+//	to Xilinx's code: I swapped spaces for tabs, I removed any white space
+//	at the ends of lines, I fixed a spelling error in the comments, added
+//	the default_nettype, added initial statements (at the bottom) for things
+//	that should've had them in the first place, etc.  I may have even
+//	swapped an always @(somevalue) for an always @(*), but that's as far
+//	as I've gone.
+//
+//	Since 2016, Vivado has made updates to their core.  The last time I
+//	checked, however, it still failed to pass a formal verification check.
+//
+//	This core will fail a verification check.
+//
+// Creator:	Vivado, 2016 (I think it was 2016.1)
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none	// Added to the raw demo
+`timescale 1 ns / 1 ps
+//
+module xlnxdemo #
+	(
+		// Users to add parameters here
+
+		// User parameters ends
+		// Do not modify the parameters beyond this line
+
+		// Width of S_AXI data bus
+		parameter integer C_S_AXI_DATA_WIDTH	= 32,
+		// Width of S_AXI address bus
+		parameter integer C_S_AXI_ADDR_WIDTH	= 7
+	)
+	(
+		// Users to add ports here
+
+		// User ports ends
+		// Do not modify the ports beyond this line
+
+		// Global Clock Signal
+		input wire  S_AXI_ACLK,
+		// Global Reset Signal. This Signal is Active LOW
+		input wire  S_AXI_ARESETN,
+		// Write address (issued by master, acceped by Slave)
+		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
+		// Write channel Protection type. This signal indicates the
+    		// privilege and security level of the transaction, and whether
+    		// the transaction is a data access or an instruction access.
+		input wire [2 : 0] S_AXI_AWPROT,
+		// Write address valid. This signal indicates that the master signaling
+    		// valid write address and control information.
+		input wire  S_AXI_AWVALID,
+		// Write address ready. This signal indicates that the slave is ready
+    		// to accept an address and associated control signals.
+		output wire  S_AXI_AWREADY,
+		// Write data (issued by master, acceped by Slave)
+		input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,
+		// Write strobes. This signal indicates which byte lanes hold
+    		// valid data. There is one write strobe bit for each eight
+    		// bits of the write data bus.
+		input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,
+		// Write valid. This signal indicates that valid write
+    		// data and strobes are available.
+		input wire  S_AXI_WVALID,
+		// Write ready. This signal indicates that the slave
+    		// can accept the write data.
+		output wire  S_AXI_WREADY,
+		// Write response. This signal indicates the status
+    		// of the write transaction.
+		output wire [1 : 0] S_AXI_BRESP,
+		// Write response valid. This signal indicates that the channel
+    		// is signaling a valid write response.
+		output wire  S_AXI_BVALID,
+		// Response ready. This signal indicates that the master
+    		// can accept a write response.
+		input wire  S_AXI_BREADY,
+		// Read address (issued by master, acceped by Slave)
+		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
+		// Protection type. This signal indicates the privilege
+    		// and security level of the transaction, and whether the
+    		// transaction is a data access or an instruction access.
+		input wire [2 : 0] S_AXI_ARPROT,
+		// Read address valid. This signal indicates that the channel
+    		// is signaling valid read address and control information.
+		input wire  S_AXI_ARVALID,
+		// Read address ready. This signal indicates that the slave is
+    		// ready to accept an address and associated control signals.
+		output wire  S_AXI_ARREADY,
+		// Read data (issued by slave)
+		output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
+		// Read response. This signal indicates the status of the
+    		// read transfer.
+		output wire [1 : 0] S_AXI_RRESP,
+		// Read valid. This signal indicates that the channel is
+    		// signaling the required read data.
+		output wire  S_AXI_RVALID,
+		// Read ready. This signal indicates that the master can
+    		// accept the read data and response information.
+		input wire  S_AXI_RREADY
+	);
+
+	// AXI4LITE signals
+	reg [C_S_AXI_ADDR_WIDTH-1 : 0] 	axi_awaddr;
+	reg  	axi_awready;
+	reg  	axi_wready;
+	reg [1 : 0] 	axi_bresp;
+	reg  	axi_bvalid;
+	reg [C_S_AXI_ADDR_WIDTH-1 : 0] 	axi_araddr;
+	reg  	axi_arready;
+	reg [C_S_AXI_DATA_WIDTH-1 : 0] 	axi_rdata;
+	reg [1 : 0] 	axi_rresp;
+	reg  	axi_rvalid;
+
+	// Example-specific design signals
+	// local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH
+	// ADDR_LSB is used for addressing 32/64 bit registers/memories
+	// ADDR_LSB = 2 for 32 bits (n downto 2)
+	// ADDR_LSB = 3 for 64 bits (n downto 3)
+	localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1;
+	localparam integer OPT_MEM_ADDR_BITS = 4;
+	//----------------------------------------------
+	//-- Signals for user logic register space example
+	//------------------------------------------------
+	//-- Number of Slave Registers 32
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg0;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg1;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg2;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg3;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg4;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg5;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg6;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg7;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg8;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg9;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg10;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg11;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg12;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg13;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg14;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg15;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg16;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg17;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg18;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg19;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg20;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg21;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg22;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg23;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg24;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg25;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg26;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg27;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg28;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg29;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg30;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg31;
+	wire	 slv_reg_rden;
+	wire	 slv_reg_wren;
+	reg [C_S_AXI_DATA_WIDTH-1:0]	 reg_data_out;
+	integer	 byte_index;
+
+	// I/O Connections assignments
+
+	assign S_AXI_AWREADY	= axi_awready;
+	assign S_AXI_WREADY	= axi_wready;
+	assign S_AXI_BRESP	= axi_bresp;
+	assign S_AXI_BVALID	= axi_bvalid;
+	assign S_AXI_ARREADY	= axi_arready;
+	assign S_AXI_RDATA	= axi_rdata;
+	assign S_AXI_RRESP	= axi_rresp;
+	assign S_AXI_RVALID	= axi_rvalid;
+	// Implement axi_awready generation
+	// axi_awready is asserted for one S_AXI_ACLK clock cycle when both
+	// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is
+	// de-asserted when reset is low.
+
+	always @( posedge S_AXI_ACLK )
+	begin
+	  if ( S_AXI_ARESETN == 1'b0 )
+	    begin
+	      axi_awready <= 1'b0;
+	    end
+	  else
+	    begin
+	      if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)
+	        begin
+	          // slave is ready to accept write address when
+	          // there is a valid write address and write data
+	          // on the write address and data bus. This design
+	          // expects no outstanding transactions.
+	          axi_awready <= 1'b1;
+	        end
+	      else
+	        begin
+	          axi_awready <= 1'b0;
+	        end
+	    end
+	end
+
+	// Implement axi_awaddr latching
+	// This process is used to latch the address when both
+	// S_AXI_AWVALID and S_AXI_WVALID are valid.
+
+	always @( posedge S_AXI_ACLK )
+	begin
+	  if ( S_AXI_ARESETN == 1'b0 )
+	    begin
+	      axi_awaddr <= 0;
+	    end
+	  else
+	    begin
+	      if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)
+	        begin
+	          // Write Address latching
+	          axi_awaddr <= S_AXI_AWADDR;
+	        end
+	    end
+	end
+
+	// Implement axi_wready generation
+	// axi_wready is asserted for one S_AXI_ACLK clock cycle when both
+	// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is
+	// de-asserted when reset is low.
+
+	always @( posedge S_AXI_ACLK )
+	begin
+	  if ( S_AXI_ARESETN == 1'b0 )
+	    begin
+	      axi_wready <= 1'b0;
+	    end
+	  else
+	    begin
+	      if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID)
+	        begin
+	          // slave is ready to accept write data when
+	          // there is a valid write address and write data
+	          // on the write address and data bus. This design
+	          // expects no outstanding transactions.
+	          axi_wready <= 1'b1;
+	        end
+	      else
+	        begin
+	          axi_wready <= 1'b0;
+	        end
+	    end
+	end
+
+	// Implement memory mapped register select and write logic generation
+	// The write data is accepted and written to memory mapped registers when
+	// axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to
+	// select byte enables of slave registers while writing.
+	// These registers are cleared when reset (active low) is applied.
+	// Slave register write enable is asserted when valid address and data are available
+	// and the slave is ready to accept the write address and write data.
+	assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;
+
+	always @( posedge S_AXI_ACLK )
+	begin
+	  if ( S_AXI_ARESETN == 1'b0 )
+	    begin
+	      slv_reg0 <= 0;
+	      slv_reg1 <= 0;
+	      slv_reg2 <= 0;
+	      slv_reg3 <= 0;
+	      slv_reg4 <= 0;
+	      slv_reg5 <= 0;
+	      slv_reg6 <= 0;
+	      slv_reg7 <= 0;
+	      slv_reg8 <= 0;
+	      slv_reg9 <= 0;
+	      slv_reg10 <= 0;
+	      slv_reg11 <= 0;
+	      slv_reg12 <= 0;
+	      slv_reg13 <= 0;
+	      slv_reg14 <= 0;
+	      slv_reg15 <= 0;
+	      slv_reg16 <= 0;
+	      slv_reg17 <= 0;
+	      slv_reg18 <= 0;
+	      slv_reg19 <= 0;
+	      slv_reg20 <= 0;
+	      slv_reg21 <= 0;
+	      slv_reg22 <= 0;
+	      slv_reg23 <= 0;
+	      slv_reg24 <= 0;
+	      slv_reg25 <= 0;
+	      slv_reg26 <= 0;
+	      slv_reg27 <= 0;
+	      slv_reg28 <= 0;
+	      slv_reg29 <= 0;
+	      slv_reg30 <= 0;
+	      slv_reg31 <= 0;
+	    end
+	  else begin
+	    if (slv_reg_wren)
+	      begin
+	        case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
+	          5'h00:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 0
+	                slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h01:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 1
+	                slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h02:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 2
+	                slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h03:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 3
+	                slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h04:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 4
+	                slv_reg4[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h05:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 5
+	                slv_reg5[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h06:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 6
+	                slv_reg6[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h07:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 7
+	                slv_reg7[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h08:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 8
+	                slv_reg8[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h09:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 9
+	                slv_reg9[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h0A:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 10
+	                slv_reg10[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h0B:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 11
+	                slv_reg11[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h0C:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 12
+	                slv_reg12[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h0D:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 13
+	                slv_reg13[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h0E:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 14
+	                slv_reg14[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h0F:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 15
+	                slv_reg15[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h10:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 16
+	                slv_reg16[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h11:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 17
+	                slv_reg17[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h12:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 18
+	                slv_reg18[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h13:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 19
+	                slv_reg19[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h14:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 20
+	                slv_reg20[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h15:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 21
+	                slv_reg21[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h16:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 22
+	                slv_reg22[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h17:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 23
+	                slv_reg23[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h18:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 24
+	                slv_reg24[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h19:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 25
+	                slv_reg25[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h1A:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 26
+	                slv_reg26[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h1B:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 27
+	                slv_reg27[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h1C:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 28
+	                slv_reg28[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h1D:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 29
+	                slv_reg29[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h1E:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 30
+	                slv_reg30[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          5'h1F:
+	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
+	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
+	                // Respective byte enables are asserted as per write strobes
+	                // Slave register 31
+	                slv_reg31[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
+	              end
+	          default : begin
+	                      slv_reg0 <= slv_reg0;
+	                      slv_reg1 <= slv_reg1;
+	                      slv_reg2 <= slv_reg2;
+	                      slv_reg3 <= slv_reg3;
+	                      slv_reg4 <= slv_reg4;
+	                      slv_reg5 <= slv_reg5;
+	                      slv_reg6 <= slv_reg6;
+	                      slv_reg7 <= slv_reg7;
+	                      slv_reg8 <= slv_reg8;
+	                      slv_reg9 <= slv_reg9;
+	                      slv_reg10 <= slv_reg10;
+	                      slv_reg11 <= slv_reg11;
+	                      slv_reg12 <= slv_reg12;
+	                      slv_reg13 <= slv_reg13;
+	                      slv_reg14 <= slv_reg14;
+	                      slv_reg15 <= slv_reg15;
+	                      slv_reg16 <= slv_reg16;
+	                      slv_reg17 <= slv_reg17;
+	                      slv_reg18 <= slv_reg18;
+	                      slv_reg19 <= slv_reg19;
+	                      slv_reg20 <= slv_reg20;
+	                      slv_reg21 <= slv_reg21;
+	                      slv_reg22 <= slv_reg22;
+	                      slv_reg23 <= slv_reg23;
+	                      slv_reg24 <= slv_reg24;
+	                      slv_reg25 <= slv_reg25;
+	                      slv_reg26 <= slv_reg26;
+	                      slv_reg27 <= slv_reg27;
+	                      slv_reg28 <= slv_reg28;
+	                      slv_reg29 <= slv_reg29;
+	                      slv_reg30 <= slv_reg30;
+	                      slv_reg31 <= slv_reg31;
+	                    end
+	        endcase
+	      end
+	  end
+	end
+
+	// Implement write response logic generation
+	// The write response and response valid signals are asserted by the slave
+	// when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted.
+	// This marks the acceptance of address and indicates the status of
+	// write transaction.
+
+	always @( posedge S_AXI_ACLK )
+	begin
+	  if ( S_AXI_ARESETN == 1'b0 )
+	    begin
+	      axi_bvalid  <= 0;
+	      axi_bresp   <= 2'b0;
+	    end
+	  else
+	    begin
+	      if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)
+	        begin
+	          // indicates a valid write response is available
+	          axi_bvalid <= 1'b1;
+	          axi_bresp  <= 2'b0; // 'OKAY' response
+	        end                   // work error responses in future
+	      else
+	        begin
+	          if (S_AXI_BREADY && axi_bvalid)
+	            //check if bready is asserted while bvalid is high)
+	            //(there is a possibility that bready is always asserted high)
+	            begin
+	              axi_bvalid <= 1'b0;
+	            end
+	        end
+	    end
+	end
+
+	// Implement axi_arready generation
+	// axi_arready is asserted for one S_AXI_ACLK clock cycle when
+	// S_AXI_ARVALID is asserted. axi_awready is
+	// de-asserted when reset (active low) is asserted.
+	// The read address is also latched when S_AXI_ARVALID is
+	// asserted. axi_araddr is reset to zero on reset assertion.
+
+	always @( posedge S_AXI_ACLK )
+	begin
+	  if ( S_AXI_ARESETN == 1'b0 )
+	    begin
+	      axi_arready <= 1'b0;
+	      axi_araddr  <= 7'b0;
+	    end
+	  else
+	    begin
+	      if (~axi_arready && S_AXI_ARVALID)
+	        begin
+	          // indicates that the slave has acceped the valid read address
+	          axi_arready <= 1'b1;
+	          // Read address latching
+	          axi_araddr  <= S_AXI_ARADDR;
+	        end
+	      else
+	        begin
+	          axi_arready <= 1'b0;
+	        end
+	    end
+	end
+
+	// Implement axi_arvalid generation
+	// axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both
+	// S_AXI_ARVALID and axi_arready are asserted. The slave registers
+	// data are available on the axi_rdata bus at this instance. The
+	// assertion of axi_rvalid marks the validity of read data on the
+	// bus and axi_rresp indicates the status of read transaction.axi_rvalid
+	// is deasserted on reset (active low). axi_rresp and axi_rdata are
+	// cleared to zero on reset (active low).
+	always @( posedge S_AXI_ACLK )
+	begin
+	  if ( S_AXI_ARESETN == 1'b0 )
+	    begin
+	      axi_rvalid <= 0;
+	      axi_rresp  <= 0;
+	    end
+	  else
+	    begin
+	      if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)
+	        begin
+	          // Valid read data is available at the read data bus
+	          axi_rvalid <= 1'b1;
+	          axi_rresp  <= 2'b0; // 'OKAY' response
+	        end
+	      else if (axi_rvalid && S_AXI_RREADY)
+	        begin
+	          // Read data is accepted by the master
+	          axi_rvalid <= 1'b0;
+	        end
+	    end
+	end
+
+	// Implement memory mapped register select and read logic generation
+	// Slave register read enable is asserted when valid address is available
+	// and the slave is ready to accept the read address.
+	assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;
+	always @(*)
+	begin
+	      reg_data_out = 0;
+	      // Address decoding for reading registers
+	      case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
+	        5'h00   : reg_data_out = slv_reg0;
+	        5'h01   : reg_data_out = slv_reg1;
+	        5'h02   : reg_data_out = slv_reg2;
+	        5'h03   : reg_data_out = slv_reg3;
+	        5'h04   : reg_data_out = slv_reg4;
+	        5'h05   : reg_data_out = slv_reg5;
+	        5'h06   : reg_data_out = slv_reg6;
+	        5'h07   : reg_data_out = slv_reg7;
+	        5'h08   : reg_data_out = slv_reg8;
+	        5'h09   : reg_data_out = slv_reg9;
+	        5'h0A   : reg_data_out = slv_reg10;
+	        5'h0B   : reg_data_out = slv_reg11;
+	        5'h0C   : reg_data_out = slv_reg12;
+	        5'h0D   : reg_data_out = slv_reg13;
+	        5'h0E   : reg_data_out = slv_reg14;
+	        5'h0F   : reg_data_out = slv_reg15;
+	        5'h10   : reg_data_out = slv_reg16;
+	        5'h11   : reg_data_out = slv_reg17;
+	        5'h12   : reg_data_out = slv_reg18;
+	        5'h13   : reg_data_out = slv_reg19;
+	        5'h14   : reg_data_out = slv_reg20;
+	        5'h15   : reg_data_out = slv_reg21;
+	        5'h16   : reg_data_out = slv_reg22;
+	        5'h17   : reg_data_out = slv_reg23;
+	        5'h18   : reg_data_out = slv_reg24;
+	        5'h19   : reg_data_out = slv_reg25;
+	        5'h1A   : reg_data_out = slv_reg26;
+	        5'h1B   : reg_data_out = slv_reg27;
+	        5'h1C   : reg_data_out = slv_reg28;
+	        5'h1D   : reg_data_out = slv_reg29;
+	        5'h1E   : reg_data_out = slv_reg30;
+	        5'h1F   : reg_data_out = slv_reg31;
+	        default : reg_data_out = 0;
+	      endcase
+	end
+
+	// Output register or memory read data
+	always @( posedge S_AXI_ACLK )
+	begin
+	  if ( S_AXI_ARESETN == 1'b0 )
+	    begin
+	      axi_rdata  <= 0;
+	    end
+	  else
+	    begin
+	      // When there is a valid read address (S_AXI_ARVALID) with
+	      // acceptance of read address by the slave (axi_arready),
+	      // output the read data
+	      if (slv_reg_rden)
+	        begin
+	          axi_rdata <= reg_data_out;     // register read data
+	        end
+	    end
+	end
+
+	// Add user logic here
+
+	// User logic ends
+	//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal Verification section begins here.
+//
+// The following code was not part of the original Xilinx demo.
+//
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	localparam	F_LGDEPTH = 4;
+
+	wire	[(F_LGDEPTH-1):0]	f_axi_awr_outstanding,
+					f_axi_wr_outstanding,
+					f_axi_rd_outstanding;
+
+	//
+	// Connect our slave to the AXI-lite property set
+	//
+	faxil_slave #(// .C_AXI_DATA_WIDTH(C_S_AXI_DATA_WIDTH),
+			.C_AXI_ADDR_WIDTH(C_S_AXI_ADDR_WIDTH),
+			.F_LGDEPTH(F_LGDEPTH)) properties(
+		.i_clk(S_AXI_ACLK),
+		.i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awaddr(S_AXI_AWADDR),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot(S_AXI_AWPROT),
+		.i_axi_awvalid(S_AXI_AWVALID),
+		.i_axi_awready(S_AXI_AWREADY),
+		//
+		.i_axi_wdata(S_AXI_WDATA),
+		.i_axi_wstrb(S_AXI_WSTRB),
+		.i_axi_wvalid(S_AXI_WVALID),
+		.i_axi_wready(S_AXI_WREADY),
+		//
+		.i_axi_bresp(S_AXI_BRESP),
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+		//
+		.i_axi_araddr(S_AXI_ARADDR),
+		.i_axi_arprot(S_AXI_ARPROT),
+		.i_axi_arcache(4'h0),
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+		//
+		.i_axi_rdata(S_AXI_RDATA),
+		.i_axi_rresp(S_AXI_RRESP),
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rready(S_AXI_RREADY),
+		//
+		.f_axi_rd_outstanding(f_axi_rd_outstanding),
+		.f_axi_wr_outstanding(f_axi_wr_outstanding),
+		.f_axi_awr_outstanding(f_axi_awr_outstanding));
+
+	reg	f_past_valid;
+	initial	f_past_valid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1'b1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Properties necessary to pass induction
+	// --- assuming we make it that far (we won't)
+	//
+	//
+	always @(*)
+	if (S_AXI_ARESETN)
+	begin
+		assert(f_axi_rd_outstanding == ((S_AXI_RVALID)? 1:0));
+		assert(f_axi_wr_outstanding == ((S_AXI_BVALID)? 1:0));
+	end
+
+	always @(*)
+		assert(f_axi_awr_outstanding == f_axi_wr_outstanding);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Cover properties
+	//
+	//
+	// Make sure it is possible to change our register
+	always @(posedge S_AXI_ACLK)
+		cover($changed(slv_reg0)&&(slv_reg0 == 32'hdeadbeef));
+
+	always @(posedge S_AXI_ACLK)
+		cover((axi_rvalid)&&(axi_rdata == 32'hdeadbeef)
+			&&($past(axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] == 0)));
+
+	// Make sure it is possible to read from our register
+	always @(posedge S_AXI_ACLK)
+		cover($past(reg_data_out == slv_reg0)
+			&&($past(axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB])==0)
+	        	&&(axi_rdata == slv_reg0));
+
+	// Performance test.  See if we can retire a request on every other
+	// instruction
+	//
+	// --- This first pair of cover statements will pass as written
+	//
+	// First a write check
+	always @(posedge S_AXI_ACLK)
+		cover( ((S_AXI_BVALID)&&(S_AXI_BREADY))
+			&&(!$past((S_AXI_BVALID)&&(S_AXI_BREADY),1))
+			&&( $past((S_AXI_BVALID)&&(S_AXI_BREADY),2))
+			&&(!$past((S_AXI_BVALID)&&(S_AXI_BREADY),3)));
+
+	// Now a read check
+	always @(posedge S_AXI_ACLK)
+		cover( ((S_AXI_RVALID)&&(S_AXI_RREADY))
+			&&(!$past((S_AXI_RVALID)&&(S_AXI_RREADY),1))
+			&&( $past((S_AXI_RVALID)&&(S_AXI_RREADY),2))
+			&&(!$past((S_AXI_RVALID)&&(S_AXI_RREADY),3)));
+
+	// Now let's see if we can retire one value every clock tick
+	//
+	// --- These two cover statements will fail, even though the ones
+	//     above will pass.  This is why I call the design "crippled".
+	//
+	// First a write check
+	always @(posedge S_AXI_ACLK)
+		cover( ((S_AXI_BVALID)&&(S_AXI_BREADY))
+			&&($past((S_AXI_BVALID)&&(S_AXI_BREADY),1))
+			&&($past((S_AXI_BVALID)&&(S_AXI_BREADY),2))
+			&&($past((S_AXI_BVALID)&&(S_AXI_BREADY),3)));
+
+	// Now a read check
+	always @(posedge S_AXI_ACLK)
+		cover( ((S_AXI_RVALID)&&(S_AXI_RREADY))
+			&&($past((S_AXI_RVALID)&&(S_AXI_RREADY),1))
+			&&($past((S_AXI_RVALID)&&(S_AXI_RREADY),2))
+			&&($past((S_AXI_RVALID)&&(S_AXI_RREADY),3)));
+
+	// Now let's spend some time to develop a more complicated read
+	// trace, showing the capabilities of the core.  We'll avoid the
+	// broken parts of the core, and just present ... something useful.
+	//
+	reg	[12:0]	fr_rdcover, fw_rdcover;
+
+	initial	fr_rdcover = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		fr_rdcover <= 0;
+	else
+		fr_rdcover <= fw_rdcover;
+
+	always @(*)
+	if ((!S_AXI_ARESETN)||(S_AXI_AWVALID)||(S_AXI_WVALID))
+		fw_rdcover = 0;
+	else begin
+		//
+		// A basic read request
+		fw_rdcover[0] = (S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rdcover[1] = fr_rdcover[0]
+				&&(S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rdcover[2] = fr_rdcover[1]
+				&&(!S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rdcover[3] = fr_rdcover[2]
+				&&(!S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rdcover[4] = fr_rdcover[3]
+				&&(!S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		//
+		// A high speed/pipelined read request
+		fw_rdcover[5] = fr_rdcover[4]
+				&&(S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rdcover[6] = fr_rdcover[5]
+				&&(S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rdcover[7] = fr_rdcover[6]
+				&&(S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rdcover[8] = fr_rdcover[7]
+				&&(S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rdcover[9] = fr_rdcover[8]
+				&&(S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rdcover[10] = fr_rdcover[9]
+				&&(S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rdcover[11] = fr_rdcover[10]
+				&&(!S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rdcover[12] = fr_rdcover[11]
+				&&(!S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+	end
+
+	always @(*)
+	begin
+		cover(fw_rdcover[0]);
+		cover(fw_rdcover[1]);
+		cover(fw_rdcover[2]);
+		cover(fw_rdcover[3]);
+		cover(fw_rdcover[4]);
+		cover(fw_rdcover[5]); //
+		cover(fw_rdcover[6]);
+		cover(fw_rdcover[7]);
+		cover(fw_rdcover[8]);
+		cover(fw_rdcover[9]);
+		cover(fw_rdcover[10]);
+		cover(fw_rdcover[11]);
+		cover(fw_rdcover[12]);
+	end
+
+	//
+	// Now let's repeat our complicated cover approach for the write
+	// channel.
+	//
+	reg	[24:0]	fr_wrcover, fw_wrcover;
+
+	initial	fr_wrcover = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		fr_wrcover <= 0;
+	else
+		fr_wrcover <= fw_wrcover;
+
+	always @(*)
+	if ((!S_AXI_ARESETN)||(S_AXI_ARVALID)||(!S_AXI_BREADY))
+		fw_wrcover = 0;
+	else begin
+		//
+		// A basic (synchronized) write request
+		fw_wrcover[0] = (S_AXI_AWVALID)
+				&&(S_AXI_WVALID);
+		fw_wrcover[1] = fr_wrcover[0]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID);
+		fw_wrcover[2] = fr_wrcover[1]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID);
+		fw_wrcover[3] = fr_wrcover[2]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID);
+		fw_wrcover[4] = fr_wrcover[3]
+				&&(!S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		//
+		// Address before data
+		fw_wrcover[5] = fr_wrcover[4]
+				&&(S_AXI_AWVALID)
+				&&(!S_AXI_WVALID);
+		fw_wrcover[6] = fr_wrcover[5]
+				&&(S_AXI_AWVALID)
+				&&(!S_AXI_WVALID);
+		fw_wrcover[7] = fr_wrcover[6]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID);
+		fw_wrcover[8] = fr_wrcover[7]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID);
+		fw_wrcover[9] = fr_wrcover[8]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID);
+		fw_wrcover[10] = fr_wrcover[9]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID);
+		//
+		// Data before address
+		fw_wrcover[11] = fr_wrcover[10]
+				&&(!S_AXI_AWVALID)
+				&&(S_AXI_WVALID);
+		fw_wrcover[12] = fr_wrcover[11]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID);
+		fw_wrcover[13] = fr_wrcover[12]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID);
+		fw_wrcover[14] = fr_wrcover[13]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID);
+		fw_wrcover[15] = fr_wrcover[14]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID);
+		//
+		// A high speed/pipelined read request
+		fw_wrcover[16] = fr_wrcover[15]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID);
+		fw_wrcover[17] = fr_wrcover[16]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID);
+		fw_wrcover[18] = fr_wrcover[17]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID);
+		fw_wrcover[19] = fr_wrcover[18]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID);
+		fw_wrcover[20] = fr_wrcover[19]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID);
+		fw_wrcover[21] = fr_wrcover[20]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID);
+		fw_wrcover[22] = fr_wrcover[21]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID);
+		fw_wrcover[23] = fr_wrcover[22]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID);
+		fw_wrcover[24] = fr_wrcover[23]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID);
+	end
+
+	always @(*)
+	begin
+		cover(fw_wrcover[0]);
+		cover(fw_wrcover[1]);
+		cover(fw_wrcover[2]);
+		cover(fw_wrcover[3]);
+		cover(fw_wrcover[4]);
+		cover(fw_wrcover[5]); //
+		cover(fw_wrcover[6]);
+		cover(fw_wrcover[7]);
+		cover(fw_wrcover[8]);
+		cover(fw_wrcover[9]);
+		cover(fw_wrcover[11]);
+		cover(fw_wrcover[12]);
+		cover(fw_wrcover[13]);
+		cover(fw_wrcover[14]);
+		cover(fw_wrcover[15]);
+		cover(fw_wrcover[16]);
+		cover(fw_wrcover[17]);
+		cover(fw_wrcover[18]);
+		cover(fw_wrcover[19]);
+		cover(fw_wrcover[20]);
+		cover(fw_wrcover[21]);
+		cover(fw_wrcover[22]);
+		cover(fw_wrcover[23]);
+		cover(fw_wrcover[24]);
+	end
+`endif
+	//
+	//
+	// Bug fixes section
+	//
+	// The lines below contain assumptions necessary to get the design
+	// to work.  They represent things Xilinx never thought of when
+	// building their demo.
+	//
+	// The following lines are only questionable a bug
+	initial	axi_arready = 1'b0;
+	initial	axi_awready = 1'b0;
+	initial	axi_wready  = 1'b0;
+	initial	axi_bvalid  = 1'b0;
+	initial	axi_rvalid  = 1'b0;
+
+	//
+	// This here is necessary to avoid the biggest bug within the design.
+	//
+	// If you uncomment the following two lines, the design will work as
+	// intended.  Only ... the bus now has more requirements to it.
+	//
+	// always @(posedge S_AXI_ACLK)
+	// if ($past(S_AXI_ARESETN))
+	//	assume((S_AXI_RREADY)&&(S_AXI_BREADY));
+
+	// verilator lint_off UNUSED
+	wire	[9:0]	unused;
+	assign	unused = { S_AXI_ARPROT, S_AXI_AWPROT,
+	       axi_awaddr[1:0], axi_araddr[1:0]	};
+	// verilator lint_on UNUSED
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxfull_2018_3.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxfull_2018_3.v
new file mode 100644
index 0000000..c610223
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxfull_2018_3.v
@@ -0,0 +1,924 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	xlnxfull.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	To test the formal tools on an AXI4 (full) core that is "known"
+//		to work.  (Only this one doesn't, but at least that was my
+//	initial purpose.) Most of this code comes directly from Vivado's core
+//	generator--starting at the end of this comment block and going down
+//	directly to the initial statements before the `ifdef FORMAL block at
+//	the bottom.  I have made superficial adjustments to Xilinx's code: I
+//	swapped spaces for tabs, I removed any white space at the ends of
+//	lines, I fixed any spelling errors that I noticed in the comments, added
+//	the default_nettype, added initial statements (just before the ifdef
+//	FORMAL) for things that should've had them in the first place, etc.
+//	I may have even swapped an always @(somevalue) for an always @(*), but
+//	that's as far as I've gone.
+//
+//	I was surprised to learn that this core passed, and would always pass,
+//	a Xilinx VIP check as is.  It does not pass a formal verification check.
+//
+// Creator:	Vivado, 2018.3
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none	// Added to the raw demo
+`timescale 1 ns / 1 ps
+//
+module xlnxfull_2018_3 #(
+	// Users to add parameters here
+
+	// User parameters ends
+	// Do not modify the parameters beyond this line
+
+	// Width of ID for for write address, write data, read address and read data
+	parameter integer C_S_AXI_ID_WIDTH	= 1,
+	// Width of S_AXI data bus
+	parameter integer C_S_AXI_DATA_WIDTH	= 32,
+	// Width of S_AXI address bus
+	parameter integer C_S_AXI_ADDR_WIDTH	= 6,
+	// Width of optional user defined signal in write address channel
+	parameter integer C_S_AXI_AWUSER_WIDTH	= 0,
+	// Width of optional user defined signal in read address channel
+	parameter integer C_S_AXI_ARUSER_WIDTH	= 0,
+	// Width of optional user defined signal in write data channel
+	parameter integer C_S_AXI_WUSER_WIDTH	= 0,
+	// Width of optional user defined signal in read data channel
+	parameter integer C_S_AXI_RUSER_WIDTH	= 0,
+	// Width of optional user defined signal in write response channel
+	parameter integer C_S_AXI_BUSER_WIDTH	= 0
+	) (
+		// Users to add ports here
+
+		// User ports ends
+		// Do not modify the ports beyond this line
+
+		// Global Clock Signal
+		input wire  S_AXI_ACLK,
+		// Global Reset Signal. This Signal is Active LOW
+		input wire  S_AXI_ARESETN,
+		// Write Address ID
+		input wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_AWID,
+		// Write address
+		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
+		// Burst length. The burst length gives the exact number of transfers in a burst
+		input wire [7 : 0] S_AXI_AWLEN,
+		// Burst size. This signal indicates the size of each transfer in the burst
+		input wire [2 : 0] S_AXI_AWSIZE,
+		// Burst type. The burst type and the size information, 
+		// determine how the address for each transfer within the burst is calculated.
+		input wire [1 : 0] S_AXI_AWBURST,
+		// Lock type. Provides additional information about the
+		// atomic characteristics of the transfer.
+		input wire  S_AXI_AWLOCK,
+		// Memory type. This signal indicates how transactions
+		// are required to progress through a system.
+		input wire [3 : 0] S_AXI_AWCACHE,
+		// Protection type. This signal indicates the privilege
+		// and security level of the transaction, and whether
+		// the transaction is a data access or an instruction access.
+		input wire [2 : 0] S_AXI_AWPROT,
+		// Quality of Service, QoS identifier sent for each
+		// write transaction.
+		input wire [3 : 0] S_AXI_AWQOS,
+		// Region identifier. Permits a single physical interface
+		// on a slave to be used for multiple logical interfaces.
+		input wire [3 : 0] S_AXI_AWREGION,
+		// Optional User-defined signal in the write address channel.
+//		input wire [C_S_AXI_AWUSER_WIDTH-1 : 0] S_AXI_AWUSER,
+		// Write address valid. This signal indicates that
+		// the channel is signaling valid write address and
+		// control information.
+		input wire  S_AXI_AWVALID,
+		// Write address ready. This signal indicates that
+		// the slave is ready to accept an address and associated
+		// control signals.
+		output wire  S_AXI_AWREADY,
+		// Write Data
+		input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,
+		// Write strobes. This signal indicates which byte
+		// lanes hold valid data. There is one write strobe
+		// bit for each eight bits of the write data bus.
+		input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,
+		// Write last. This signal indicates the last transfer
+		// in a write burst.
+		input wire  S_AXI_WLAST,
+		// Optional User-defined signal in the write data channel.
+//		input wire [C_S_AXI_WUSER_WIDTH-1 : 0] S_AXI_WUSER,
+		// Write valid. This signal indicates that valid write
+		// data and strobes are available.
+		input wire  S_AXI_WVALID,
+		// Write ready. This signal indicates that the slave
+		// can accept the write data.
+		output wire  S_AXI_WREADY,
+		// Response ID tag. This signal is the ID tag of the
+		// write response.
+		output wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_BID,
+		// Write response. This signal indicates the status
+		// of the write transaction.
+		output wire [1 : 0] S_AXI_BRESP,
+		// Optional User-defined signal in the write response channel.
+//		output wire [C_S_AXI_BUSER_WIDTH-1 : 0] S_AXI_BUSER,
+		// Write response valid. This signal indicates that the
+		// channel is signaling a valid write response.
+		output wire  S_AXI_BVALID,
+		// Response ready. This signal indicates that the master
+		// can accept a write response.
+		input wire  S_AXI_BREADY,
+		// Read address ID. This signal is the identification
+		// tag for the read address group of signals.
+		input wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_ARID,
+		// Read address. This signal indicates the initial
+		// address of a read burst transaction.
+		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
+		// Burst length. The burst length gives the exact number of transfers in a burst
+		input wire [7 : 0] S_AXI_ARLEN,
+		// Burst size. This signal indicates the size of each transfer in the burst
+		input wire [2 : 0] S_AXI_ARSIZE,
+		// Burst type. The burst type and the size information, 
+		// determine how the address for each transfer within the burst is calculated.
+		input wire [1 : 0] S_AXI_ARBURST,
+		// Lock type. Provides additional information about the
+		// atomic characteristics of the transfer.
+		input wire  S_AXI_ARLOCK,
+		// Memory type. This signal indicates how transactions
+		// are required to progress through a system.
+		input wire [3 : 0] S_AXI_ARCACHE,
+		// Protection type. This signal indicates the privilege
+		// and security level of the transaction, and whether
+		// the transaction is a data access or an instruction access.
+		input wire [2 : 0] S_AXI_ARPROT,
+		// Quality of Service, QoS identifier sent for each
+		// read transaction.
+		input wire [3 : 0] S_AXI_ARQOS,
+		// Region identifier. Permits a single physical interface
+		// on a slave to be used for multiple logical interfaces.
+//		input wire [3 : 0] S_AXI_ARREGION,
+		// Optional User-defined signal in the read address channel.
+//		input wire [C_S_AXI_ARUSER_WIDTH-1 : 0] S_AXI_ARUSER,
+		// Write address valid. This signal indicates that
+		// the channel is signaling valid read address and
+		// control information.
+		input wire  S_AXI_ARVALID,
+		// Read address ready. This signal indicates that
+		// the slave is ready to accept an address and associated
+		// control signals.
+		output wire  S_AXI_ARREADY,
+		// Read ID tag. This signal is the identification tag
+		// for the read data group of signals generated by the slave.
+		output wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_RID,
+		// Read Data
+		output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
+		// Read response. This signal indicates the status of
+		// the read transfer.
+		output wire [1 : 0] S_AXI_RRESP,
+		// Read last. This signal indicates the last transfer
+		// in a read burst.
+		output wire  S_AXI_RLAST,
+		// Optional User-defined signal in the read address channel.
+//		output wire [C_S_AXI_RUSER_WIDTH-1 : 0] S_AXI_RUSER,
+		// Read valid. This signal indicates that the channel
+		// is signaling the required read data.
+		output wire  S_AXI_RVALID,
+		// Read ready. This signal indicates that the master can
+		// accept the read data and response information.
+		input wire  S_AXI_RREADY
+	);
+
+	// AXI4FULL signals
+	reg [C_S_AXI_ADDR_WIDTH-1 : 0] 	axi_awaddr;
+	reg 			 	axi_awready;
+	reg  				axi_wready;
+	reg [1 : 0]		 	axi_bresp;
+//	reg [C_S_AXI_BUSER_WIDTH-1 : 0]	axi_buser;
+	reg 			 	axi_bvalid;
+	reg [C_S_AXI_ADDR_WIDTH-1 : 0] 	axi_araddr;
+	reg 			 	axi_arready;
+	reg [C_S_AXI_DATA_WIDTH-1 : 0] 	axi_rdata;
+	reg [1 : 0] 			axi_rresp;
+	reg 			 	axi_rlast;
+//	reg [C_S_AXI_RUSER_WIDTH-1 : 0] axi_ruser;
+	reg  				axi_rvalid;
+	// aw_wrap_en determines wrap boundary and enables wrapping
+	wire aw_wrap_en;
+	// ar_wrap_en determines wrap boundary and enables wrapping
+	wire ar_wrap_en;
+	// aw_wrap_size is the size of the write transfer, the
+	// write address wraps to a lower address if upper address
+	// limit is reached
+	wire [31:0]  aw_wrap_size ; 
+	// ar_wrap_size is the size of the read transfer, the
+	// read address wraps to a lower address if upper address
+	// limit is reached
+	wire [31:0]  ar_wrap_size ; 
+	// The axi_awv_awr_flag flag marks the presence of write address valid
+	reg axi_awv_awr_flag;
+	//The axi_arv_arr_flag flag marks the presence of read address valid
+	reg axi_arv_arr_flag; 
+	// The axi_awlen_cntr internal write address counter to keep track of beats in a burst transaction
+	reg [7:0] axi_awlen_cntr;
+	//The axi_arlen_cntr internal read address counter to keep track of beats in a burst transaction
+	reg [7:0] axi_arlen_cntr;
+	reg [1:0] axi_arburst;
+	reg [1:0] axi_awburst;
+	reg [7:0] axi_arlen;
+	reg [7:0] axi_awlen;
+	//local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH
+	//ADDR_LSB is used for addressing 32/64 bit registers/memories
+	//ADDR_LSB = 2 for 32 bits (n downto 2) 
+	//ADDR_LSB = 3 for 42 bits (n downto 3)
+
+	localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32)+ 1;
+	localparam integer OPT_MEM_ADDR_BITS = 3;
+	localparam integer USER_NUM_MEM = 1;
+	//----------------------------------------------
+	//-- Signals for user logic memory space example
+	//------------------------------------------------
+	wire [OPT_MEM_ADDR_BITS:0] mem_address;
+//	wire [USER_NUM_MEM-1:0] mem_select;
+	reg [C_S_AXI_DATA_WIDTH-1:0] mem_data_out[0 : USER_NUM_MEM-1];
+
+	genvar i;
+	genvar j;
+	genvar mem_byte_index;
+
+	// I/O Connections assignments
+
+	assign S_AXI_AWREADY	= axi_awready;
+	assign S_AXI_WREADY	= axi_wready;
+	assign S_AXI_BRESP	= axi_bresp;
+//	assign S_AXI_BUSER	= axi_buser;
+	assign S_AXI_BVALID	= axi_bvalid;
+	assign S_AXI_ARREADY	= axi_arready;
+	assign S_AXI_RDATA	= axi_rdata;
+	assign S_AXI_RRESP	= axi_rresp;
+	assign S_AXI_RLAST	= axi_rlast;
+//	assign S_AXI_RUSER	= axi_ruser;
+	assign S_AXI_RVALID	= axi_rvalid;
+	assign S_AXI_BID = S_AXI_AWID;
+	assign S_AXI_RID = S_AXI_ARID;
+	assign  aw_wrap_size = (C_S_AXI_DATA_WIDTH/8 * (axi_awlen)); 
+	assign  ar_wrap_size = (C_S_AXI_DATA_WIDTH/8 * (axi_arlen)); 
+	assign  aw_wrap_en = ((axi_awaddr & aw_wrap_size) == aw_wrap_size)? 1'b1: 1'b0;
+	assign  ar_wrap_en = ((axi_araddr & ar_wrap_size) == ar_wrap_size)? 1'b1: 1'b0;
+
+	// Implement axi_awready generation
+
+	// axi_awready is asserted for one S_AXI_ACLK clock cycle when both
+	// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is
+	// de-asserted when reset is low.
+
+	always @( posedge S_AXI_ACLK )
+	begin
+	  if ( S_AXI_ARESETN == 1'b0 )
+	    begin
+	      axi_awready <= 1'b0;
+	      axi_awv_awr_flag <= 1'b0;
+	    end 
+	  else
+	    begin
+	      if (~axi_awready && S_AXI_AWVALID && ~axi_awv_awr_flag && ~axi_arv_arr_flag)
+	        begin
+	          // slave is ready to accept an address and
+	          // associated control signals
+	          axi_awready <= 1'b1;
+	          axi_awv_awr_flag  <= 1'b1; 
+	          // used for generation of bresp() and bvalid
+	        end
+	      else if (S_AXI_WLAST && axi_wready)          
+	      // preparing to accept next address after current write burst tx completion
+	        begin
+	          axi_awv_awr_flag  <= 1'b0;
+	        end
+	      else
+	        begin
+	          axi_awready <= 1'b0;
+	        end
+	    end
+	end
+	// Implement axi_awaddr latching
+
+	// This process is used to latch the address when both
+	// S_AXI_AWVALID and S_AXI_WVALID are valid.
+
+	always @( posedge S_AXI_ACLK )
+	begin
+	  if ( S_AXI_ARESETN == 1'b0 )
+	    begin
+	      axi_awaddr <= 0;
+	      axi_awlen_cntr <= 0;
+	      axi_awburst <= 0;
+	      axi_awlen <= 0;
+	    end 
+	  else
+	    begin
+	      if (~axi_awready && S_AXI_AWVALID && ~axi_awv_awr_flag)
+	        begin
+	          // address latching
+	          axi_awaddr <= S_AXI_AWADDR[C_S_AXI_ADDR_WIDTH - 1:0];  
+	           axi_awburst <= S_AXI_AWBURST; 
+	           axi_awlen <= S_AXI_AWLEN;
+	          // start address of transfer
+	          axi_awlen_cntr <= 0;
+	        end   
+	      else if((axi_awlen_cntr <= axi_awlen) && axi_wready && S_AXI_WVALID)        
+	        begin
+
+	          axi_awlen_cntr <= axi_awlen_cntr + 1;
+
+	          case (axi_awburst)
+	            2'b00: // fixed burst
+	            // The write address for all the beats in the transaction are fixed
+	              begin
+	                axi_awaddr <= axi_awaddr;          
+	                //for awsize = 4 bytes (010)
+	              end   
+	            2'b01: //incremental burst
+	            // The write address for all the beats in the transaction are increments by awsize
+	              begin
+	                axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
+	                //awaddr aligned to 4 byte boundary
+	                axi_awaddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}};   
+	                //for awsize = 4 bytes (010)
+	              end   
+	            2'b10: //Wrapping burst
+	            // The write address wraps when the address reaches wrap boundary 
+	              if (aw_wrap_en)
+	                begin
+	                  axi_awaddr <= (axi_awaddr - aw_wrap_size); 
+	                end
+	              else 
+	                begin
+	                  axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
+	                  axi_awaddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}}; 
+	                end                      
+	            default: //reserved (incremental burst for example)
+	              begin
+	                axi_awaddr <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
+	                //for awsize = 4 bytes (010)
+	              end
+	          endcase
+	        end
+	    end
+	end
+	// Implement axi_wready generation
+
+	// axi_wready is asserted for one S_AXI_ACLK clock cycle when both
+	// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is
+	// de-asserted when reset is low.
+
+	always @( posedge S_AXI_ACLK )
+	begin
+	  if ( S_AXI_ARESETN == 1'b0 )
+	    begin
+	      axi_wready <= 1'b0;
+	    end
+	  else
+	    begin
+	      if (~axi_wready && S_AXI_WVALID && axi_awv_awr_flag)
+	        begin
+	          // slave can accept the write data
+	          axi_wready <= 1'b1;
+	        end
+	      //else if (~axi_awv_awr_flag)
+	      else if (S_AXI_WLAST && axi_wready)
+	        begin
+	          axi_wready <= 1'b0;
+	        end
+	    end
+	end
+	// Implement write response logic generation
+
+	// The write response and response valid signals are asserted by the slave
+	// when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted.
+	// This marks the acceptance of address and indicates the status of
+	// write transaction.
+
+	always @( posedge S_AXI_ACLK )
+	begin
+	  if ( S_AXI_ARESETN == 1'b0 )
+	    begin
+	      axi_bvalid  <= 0;
+	      axi_bresp   <= 2'b0;
+//	      axi_buser <= 0;
+	    end
+	  else
+	    begin    
+	      if (axi_awv_awr_flag && axi_wready && S_AXI_WVALID && ~axi_bvalid && S_AXI_WLAST )
+	        begin
+	          axi_bvalid <= 1'b1;
+	          axi_bresp  <= 2'b0; 
+	          // 'OKAY' response 
+	        end                   
+	      else
+	        begin
+	          if (S_AXI_BREADY && axi_bvalid)
+	            //check if bready is asserted while bvalid is high)
+	            //(there is a possibility that bready is always asserted high)
+	            begin
+	              axi_bvalid <= 1'b0;
+	            end
+	        end
+	    end
+	end
+	// Implement axi_arready generation
+
+	// axi_arready is asserted for one S_AXI_ACLK clock cycle when
+	// S_AXI_ARVALID is asserted. axi_awready is
+	// de-asserted when reset (active low) is asserted.
+	// The read address is also latched when S_AXI_ARVALID is
+	// asserted. axi_araddr is reset to zero on reset assertion.
+
+	always @( posedge S_AXI_ACLK )
+	begin
+	  if ( S_AXI_ARESETN == 1'b0 )
+	    begin
+	      axi_arready <= 1'b0;
+	      axi_arv_arr_flag <= 1'b0;
+	    end
+	  else
+	    begin
+	      if (~axi_arready && S_AXI_ARVALID && ~axi_awv_awr_flag && ~axi_arv_arr_flag)
+	        begin
+	          axi_arready <= 1'b1;
+	          axi_arv_arr_flag <= 1'b1;
+	        end
+	      else if (axi_rvalid && S_AXI_RREADY && axi_arlen_cntr == axi_arlen)
+	      // preparing to accept next address after current read completion
+	        begin
+	          axi_arv_arr_flag  <= 1'b0;
+	        end
+	      else
+	        begin
+	          axi_arready <= 1'b0;
+	        end
+	    end
+	end
+	// Implement axi_araddr latching
+
+	//This process is used to latch the address when both 
+	//S_AXI_ARVALID and S_AXI_RVALID are valid. 
+	always @( posedge S_AXI_ACLK )
+	begin
+	  if ( S_AXI_ARESETN == 1'b0 )
+	    begin
+	      axi_araddr <= 0;
+	      axi_arlen_cntr <= 0;
+	      axi_arburst <= 0;
+	      axi_arlen <= 0;
+	      axi_rlast <= 1'b0;
+//	      axi_ruser <= 0;
+	    end 
+	  else
+	    begin    
+	      if (~axi_arready && S_AXI_ARVALID && ~axi_arv_arr_flag)
+	        begin
+	          // address latching 
+	          axi_araddr <= S_AXI_ARADDR[C_S_AXI_ADDR_WIDTH - 1:0]; 
+	          axi_arburst <= S_AXI_ARBURST; 
+	          axi_arlen <= S_AXI_ARLEN;     
+	          // start address of transfer
+	          axi_arlen_cntr <= 0;
+	          axi_rlast <= 1'b0;
+	        end   
+	      else if((axi_arlen_cntr <= axi_arlen) && axi_rvalid && S_AXI_RREADY)        
+	        begin
+	         
+	          axi_arlen_cntr <= axi_arlen_cntr + 1;
+	          axi_rlast <= 1'b0;
+	        
+	          case (axi_arburst)
+	            2'b00: // fixed burst
+	             // The read address for all the beats in the transaction are fixed
+	              begin
+	                axi_araddr       <= axi_araddr;        
+	                //for arsize = 4 bytes (010)
+	              end   
+	            2'b01: //incremental burst
+	            // The read address for all the beats in the transaction are increments by awsize
+	              begin
+	                axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1; 
+	                //araddr aligned to 4 byte boundary
+	                axi_araddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}};   
+	                //for awsize = 4 bytes (010)
+	              end   
+	            2'b10: //Wrapping burst
+	            // The read address wraps when the address reaches wrap boundary 
+	              if (ar_wrap_en) 
+	                begin
+	                  axi_araddr <= (axi_araddr - ar_wrap_size); 
+	                end
+	              else 
+	                begin
+	                axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1; 
+	                //araddr aligned to 4 byte boundary
+	                axi_araddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}};   
+	                end                      
+	            default: //reserved (incremental burst for example)
+	              begin
+	                axi_araddr <= axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB]+1;
+	                //for arsize = 4 bytes (010)
+	              end
+	          endcase              
+	        end
+	      else if((axi_arlen_cntr == axi_arlen) && ~axi_rlast && axi_arv_arr_flag )   
+	        begin
+	          axi_rlast <= 1'b1;
+	        end          
+	      else if (S_AXI_RREADY)   
+	        begin
+	          axi_rlast <= 1'b0;
+	        end          
+	    end 
+	end       
+	// Implement axi_arvalid generation
+
+	// axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both 
+	// S_AXI_ARVALID and axi_arready are asserted. The slave registers 
+	// data are available on the axi_rdata bus at this instance. The 
+	// assertion of axi_rvalid marks the validity of read data on the 
+	// bus and axi_rresp indicates the status of read transaction.axi_rvalid 
+	// is deasserted on reset (active low). axi_rresp and axi_rdata are 
+	// cleared to zero on reset (active low).  
+
+	always @( posedge S_AXI_ACLK )
+	begin
+	  if ( S_AXI_ARESETN == 1'b0 )
+	    begin
+	      axi_rvalid <= 0;
+	      axi_rresp  <= 0;
+	    end 
+	  else
+	    begin    
+	      if (axi_arv_arr_flag && ~axi_rvalid)
+	        begin
+	          axi_rvalid <= 1'b1;
+	          axi_rresp  <= 2'b0; 
+	          // 'OKAY' response
+	        end   
+	      else if (axi_rvalid && S_AXI_RREADY)
+	        begin
+	          axi_rvalid <= 1'b0;
+	        end            
+	    end
+	end    
+	// ------------------------------------------
+	// -- Example code to access user logic memory region
+	// ------------------------------------------
+
+	generate
+	  if (USER_NUM_MEM >= 1)
+	    begin
+//	      assign mem_select  = 1;
+	      assign mem_address = (axi_arv_arr_flag? axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:(axi_awv_awr_flag? axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:0));
+	    end
+	endgenerate
+	     
+	// implement Block RAM(s)
+	generate 
+	  for(i=0; i<= USER_NUM_MEM-1; i=i+1)
+	    begin:BRAM_GEN
+	      wire mem_rden;
+	      wire mem_wren;
+	
+	      assign mem_wren = axi_wready && S_AXI_WVALID ;
+	
+	      assign mem_rden = axi_arv_arr_flag ; //& ~axi_rvalid
+	     
+	      for(mem_byte_index=0; mem_byte_index<= (C_S_AXI_DATA_WIDTH/8-1); mem_byte_index=mem_byte_index+1)
+	      begin:BYTE_BRAM_GEN
+	        wire [8-1:0] data_in ;
+	        wire [8-1:0] data_out;
+	        reg  [8-1:0] byte_ram [0 : 15];
+//	        integer  j;
+	     
+	        //assigning 8 bit data
+	        assign data_in  = S_AXI_WDATA[(mem_byte_index*8+7) -: 8];
+	        assign data_out = byte_ram[mem_address];
+	     
+	        always @( posedge S_AXI_ACLK )
+	        begin
+	          if (mem_wren && S_AXI_WSTRB[mem_byte_index])
+	            begin
+	              byte_ram[mem_address] <= data_in;
+	            end   
+	        end    
+	      
+	        always @( posedge S_AXI_ACLK )
+	        begin
+	          if (mem_rden)
+	            begin
+	              mem_data_out[i][(mem_byte_index*8+7) -: 8] <= data_out;
+	            end   
+	        end    
+	               
+	    end
+	  end       
+	endgenerate
+	//Output register or memory read data
+
+	always @(*) // @( mem_data_out, axi_rvalid)
+	begin
+	  if (axi_rvalid) 
+	    begin
+	      // Read address mux
+	      axi_rdata = mem_data_out[0];
+	    end   
+	  else
+	    begin
+	      axi_rdata = 32'h00000000;
+	    end       
+	end    
+
+// Verification logic starts here:
+	initial	axi_awready = 1'b0;
+	initial	axi_awv_awr_flag = 1'b0;
+	initial	axi_awaddr     = 0;
+	initial	axi_awlen_cntr = 0;
+	initial	axi_awburst    = 0;
+	initial	axi_awlen      = 0;
+	initial	axi_wready = 1'b0;
+	initial	axi_bvalid = 1'b0;
+	initial	axi_bresp  = 1'b0;
+//	initial	axi_buser  = 1'b0;
+	initial	axi_arready      = 1'b0;
+	initial	axi_arv_arr_flag = 1'b0;
+	initial	axi_araddr = 0;
+	initial	axi_arlen_cntr = 0;
+	initial	axi_arburst    = 0;
+	initial	axi_arlen      = 0;
+	initial	axi_rlast      = 0;
+//	initial	axi_ruser      = 0;
+	initial	axi_rvalid = 1'b0;
+	initial	axi_rresp  = 1'b0;
+`ifdef	FORMAL
+	//
+	// ...
+	//
+
+	faxi_slave	#(
+		.F_AXI_MAXSTALL(6),
+		.C_AXI_ID_WIDTH(C_S_AXI_ID_WIDTH),
+		.C_AXI_DATA_WIDTH(C_S_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_S_AXI_ADDR_WIDTH),
+		.OPT_NARROW_BURST(0),
+		.OPT_EXCLUSIVE(0),
+		.F_LGDEPTH(F_LGDEPTH))
+		f_slave(
+		// {{{
+		.i_clk(S_AXI_ACLK),
+		.i_axi_reset_n(S_AXI_ARESETN),
+		//
+		// Address write channel
+		//
+		// Write Address ID
+		.i_axi_awid(S_AXI_AWID),
+		// Write address
+		.i_axi_awaddr(S_AXI_AWADDR),
+		// Burst length. The burst length gives the exact number of transfers in a burst
+		.i_axi_awlen(S_AXI_AWLEN),
+		// Burst size. This signal indicates the size of each transfer in the burst
+		.i_axi_awsize(S_AXI_AWSIZE),
+		// Burst type. The burst type and the size information, 
+    		// determine how the address for each transfer within the burst is calculated.
+		.i_axi_awburst(S_AXI_AWBURST),
+		// Lock type. Provides additional information about the
+    		// atomic characteristics of the transfer.
+		.i_axi_awlock(S_AXI_AWLOCK),
+		// Memory type. This signal indicates how transactions
+    		// are required to progress through a system.
+		.i_axi_awcache(S_AXI_AWCACHE),
+		// Protection type. This signal indicates the privilege
+    		// and security level of the transaction, and whether
+    		// the transaction is a data access or an instruction access.
+		.i_axi_awprot(S_AXI_AWPROT),
+		// Quality of Service, QoS identifier sent for each
+    		// write transaction.
+		.i_axi_awqos(S_AXI_AWQOS),
+		// Write address valid. This signal indicates that
+    		// the channel is signaling valid write address and
+    		// control information.
+		.i_axi_awvalid(S_AXI_AWVALID),
+		// Write address ready. This signal indicates that
+    		// the slave is ready to accept an address and associated
+    		// control signals.
+		.i_axi_awready(S_AXI_AWREADY),
+	//
+	//
+		//
+		// Write Data Channel
+		//
+		// Write Data
+		.i_axi_wdata(S_AXI_WDATA),
+		// Write strobes. This signal indicates which byte
+    		// lanes hold valid data. There is one write strobe
+    		// bit for each eight bits of the write data bus.
+		.i_axi_wstrb(S_AXI_WSTRB),
+		// Write last. This signal indicates the last transfer
+    		// in a write burst.
+		.i_axi_wlast(S_AXI_WLAST),
+		// Write valid. This signal indicates that valid write
+    		// data and strobes are available.
+		.i_axi_wvalid(S_AXI_WVALID),
+		// Write ready. This signal indicates that the slave
+    		// can accept the write data.
+		.i_axi_wready(S_AXI_WREADY),
+	//
+	//
+		// Response ID tag. This signal is the ID tag of the
+    		// write response.
+		.i_axi_bid(S_AXI_BID),
+		// Write response. This signal indicates the status
+    		// of the write transaction.
+		.i_axi_bresp(S_AXI_BRESP),
+		// Write response valid. This signal indicates that the
+    		// channel is signaling a valid write response.
+		.i_axi_bvalid(S_AXI_BVALID),
+		// Response ready. This signal indicates that the master
+    		// can accept a write response.
+		.i_axi_bready(S_AXI_BREADY),
+	//
+	//
+		//
+		// Read address channel
+		//
+		// Read address ID. This signal is the identification
+		// tag for the read address group of signals.
+		.i_axi_arid(S_AXI_ARID),
+		// Read address. This signal indicates the initial
+    		// address of a read burst transaction.
+		.i_axi_araddr(S_AXI_ARADDR),
+		// Burst length. The burst length gives the exact number of transfers in a burst
+		.i_axi_arlen(S_AXI_ARLEN),
+		// Burst size. This signal indicates the size of each transfer in the burst
+		.i_axi_arsize(S_AXI_ARSIZE),
+		// Burst type. The burst type and the size information, 
+    		// determine how the address for each transfer within the burst is calculated.
+		.i_axi_arburst(S_AXI_ARBURST),
+		// Lock type. Provides additional information about the
+    		// atomic characteristics of the transfer.
+		.i_axi_arlock(S_AXI_ARLOCK),
+		// Memory type. This signal indicates how transactions
+    		// are required to progress through a system.
+		.i_axi_arcache(S_AXI_ARCACHE),
+		// Protection type. This signal indicates the privilege
+    		// and security level of the transaction, and whether
+    		// the transaction is a data access or an instruction access.
+		.i_axi_arprot(S_AXI_ARPROT),
+		// Quality of Service, QoS identifier sent for each
+    		// read transaction.
+		.i_axi_arqos(S_AXI_ARQOS),
+		// Write address valid. This signal indicates that
+    		// the channel is signaling valid read address and
+    		// control information.
+		.i_axi_arvalid(S_AXI_ARVALID),
+		// Read address ready. This signal indicates that
+    		// the slave is ready to accept an address and associated
+    		// control signals.
+		.i_axi_arready(S_AXI_ARREADY),
+	//
+	//
+		//
+		// Read data return channel
+		//
+		// Read ID tag. This signal is the identification tag
+		// for the read data group of signals generated by the slave.
+		.i_axi_rid(S_AXI_RID),
+		// Read Data
+		.i_axi_rdata(S_AXI_RDATA),
+		// Read response. This signal indicates the status of
+    		// the read transfer.
+		.i_axi_rresp(S_AXI_RRESP),
+		// Read last. This signal indicates the last transfer
+    		// in a read burst.
+		.i_axi_rlast(S_AXI_RLAST),
+		// Read valid. This signal indicates that the channel
+    		// is signaling the required read data.
+		.i_axi_rvalid(S_AXI_RVALID),
+		// Read ready. This signal indicates that the master can
+    		// accept the read data and response information.
+		.i_axi_rready(S_AXI_RREADY)
+		//
+		// ...
+		//
+		// }}}
+	);
+
+	//
+	// ...
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write induction properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// ...
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read induction properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// ...
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// ...
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Assumptions necessary to pass a formal check
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// BUG #1: The ID inputs, both ARID and AWID, are not registered.
+	// 	As a result, if the master changes these values mid burst,
+	//	the slave will return the wrong ID values
+
+	//
+	// ...
+	//
+
+	//
+	// BUG #2: This core using the S_AXI_WLAST signal, without first
+	//	checking that S_AXI_WVALID is also true.  Hence, if there's any
+	//	time between WVALIDs, the core might act on the last one
+	//	without receiving the data
+
+	//
+	// ...
+	//
+
+	//
+	// BUG #3: Like Xilinx's AXI-lite core, this core can't handle back
+	//	pressure.  Should S_AXI_BREADY not be accepted before the next
+	//	S_AXI_AWVALID & S_AXI_AWREADY, a burst would be dropped
+	//
+
+	//
+	// ...
+	//
+
+	//
+	// BAD PRACTICE: This particular core can't handle both reads and
+	//	writes at the same time.  To avoid failing a stall timeout,
+	//	we'll insist that no new transactions start while a
+	//	transaction on the other side is in process
+
+
+//
+// Comments:
+//
+//	- ID's are broken.  The ID should be registered and recorded within the
+//	    core, allowing the interconnect to change them after the transaction
+//	    has been accepted
+//
+//	- This core does not support narrow burst mode, but rather only
+//	    supports an AxSIZE of 2'b10 (32'bit bus).  It cannot handle busses
+//	    of other sizes, or transactions from smaller sources.
+//
+//		This might be considered a "feature"
+//
+//	- This core can only handle read or write transactions, but never both
+//	    at the same time
+//
+//		This might also be considered a "feature"
+//
+//	- The wrap logic depends upon a multiply
+//
+//		A good synthesis tool might simplify this
+//
+//	- Read transactions take place at one word every other clock at best
+//
+//		This is just plain crippled.
+//
+//	- Any back pressure could easily cause the core to lose a transaction,
+//	    as the newer transaction's response will overwrite the waiting
+//	    response from the previous transaction
+//
+`endif
+// User logic ends
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxstream_2018_3.gtkw b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxstream_2018_3.gtkw
new file mode 100644
index 0000000..901d9df
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxstream_2018_3.gtkw
@@ -0,0 +1,70 @@
+[*]
+[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
+[*] Fri Apr 26 10:36:20 2019
+[*]
+[dumpfile] "(null)"
+[timestart] 0
+[size] 1920 1021
+[pos] -1 -1
+*-5.403065 200 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] xlnxstream_2018_3.
+[sst_width] 270
+[signals_width] 240
+[sst_expanded] 1
+[sst_vpaned_height] 290
+@29
+xlnxstream_2018_3.f_past_valid
+@28
+xlnxstream_2018_3.M_AXIS_ACLK
+xlnxstream_2018_3.M_AXIS_ARESETN
+@200
+-
+@28
+[color] 3
+xlnxstream_2018_3.M_AXIS_TVALID
+[color] 2
+xlnxstream_2018_3.M_AXIS_TREADY
+@22
+[color] 3
+xlnxstream_2018_3.M_AXIS_TDATA[31:0]
+[color] 3
+xlnxstream_2018_3.M_AXIS_TSTRB[3:0]
+@28
+[color] 3
+xlnxstream_2018_3.M_AXIS_TLAST
+@200
+-
+@28
+xlnxstream_2018_3.axis_tvalid
+xlnxstream_2018_3.axis_tlast
+@200
+-
+@28
+xlnxstream_2018_3.axis_tvalid_delay
+xlnxstream_2018_3.axis_tlast_delay
+@200
+-
+@22
+xlnxstream_2018_3.count[4:0]
+@28
+xlnxstream_2018_3.mst_exec_state[1:0]
+@22
+xlnxstream_2018_3.read_pointer[3:0]
+xlnxstream_2018_3.stream_data_out[31:0]
+@28
+xlnxstream_2018_3.tx_done
+xlnxstream_2018_3.tx_en
+@200
+-
+@28
+xlnxstream_2018_3.f_routecheck[1:0]
+@22
+xlnxstream_2018_3.f_bytecount[5:0]
+@200
+-
+@22
+xlnxstream_2018_3.axi_stream_check.i_tkeep[3:0]
+xlnxstream_2018_3.axi_stream_check.i_tstrb[3:0]
+xlnxstream_2018_3.axi_stream_check.f_vbytes[5:0]
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxstream_2018_3.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxstream_2018_3.sby
new file mode 100644
index 0000000..40cb396
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxstream_2018_3.sby
@@ -0,0 +1,23 @@
+[tasks]
+prf
+cvr
+
+[options]
+prf: mode prove
+prf: depth 120
+prf: expect FAIL
+cvr: mode cover
+cvr: depth 60
+
+[engines]
+smtbmc
+
+[script]
+read -formal faxis_master.v
+read -formal xlnxstream_2018_3.v
+prep -top xlnxstream_2018_3
+chformal -assert -skip 2
+
+[files]
+faxis_master.v
+xlnxstream_2018_3.v
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxstream_2018_3.v b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxstream_2018_3.v
new file mode 100644
index 0000000..5a84604
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/formal/xlnxstream_2018_3.v
@@ -0,0 +1,367 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	xlnxstream_2018_3
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	To test the formal tools on an AXI stream master core that is
+//		"known" to work.  This core was generated via the IP packager
+//	in Vivado 2018.3.  Sadly, it's broken in a couple of ways, one which
+//	is prominently the TLAST signal which may be set even through the
+//	channel is stalled.  Feel free to try it out.
+//
+//	This core will fail a verification check.
+//
+// Creator:	Vivado, 2018.3
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+`timescale 1 ns / 1 ps
+
+module xlnxstream_2018_3 #
+	(
+		// Users to add parameters here
+
+		// User parameters ends
+		// Do not modify the parameters beyond this line
+
+		// Width of S_AXIS address bus. The slave accepts the read and write addresses of width C_M_AXIS_TDATA_WIDTH.
+		parameter integer C_M_AXIS_TDATA_WIDTH	= 32,
+		// Start count is the number of clock cycles the master will wait before initiating/issuing any transaction.
+		parameter integer C_M_START_COUNT	= 32
+	)
+	(
+		// Users to add ports here
+
+		// User ports ends
+		// Do not modify the ports beyond this line
+
+		// Global ports
+		input wire  M_AXIS_ACLK,
+		//
+		input wire  M_AXIS_ARESETN,
+		// Master Stream Ports. TVALID indicates that the master
+		// is driving a valid transfer, A transfer takes place
+		// when both TVALID and TREADY are asserted.
+		output wire  M_AXIS_TVALID,
+		// TDATA is the primary payload that is used to provide the
+		// data that is passing across the interface from the master.
+		output wire [C_M_AXIS_TDATA_WIDTH-1 : 0] M_AXIS_TDATA,
+		// TSTRB is the byte qualifier that indicates whether the
+		// content of the associated byte of TDATA is processed as a
+		// data byte or a position byte.
+		output wire [(C_M_AXIS_TDATA_WIDTH/8)-1 : 0] M_AXIS_TSTRB,
+		// TLAST indicates the boundary of a packet.
+		output wire  M_AXIS_TLAST,
+		// TREADY indicates that the slave can accept a transfer in
+		// the current cycle.
+		input wire  M_AXIS_TREADY
+	);
+	// Total number of output data
+	localparam NUMBER_OF_OUTPUT_WORDS = 8;
+
+	// function called clogb2 that returns an integer which has the
+	// value of the ceiling of the log base 2.
+	function integer clogb2 (input integer bit_depth);
+	begin
+		for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
+			bit_depth = bit_depth >> 1;
+	end endfunction
+
+	// WAIT_COUNT_BITS is the width of the wait counter.
+	localparam integer WAIT_COUNT_BITS = clogb2(C_M_START_COUNT-1);
+
+	// bit_num gives the minimum number of bits needed to address 'depth'
+	// size of FIFO.
+	localparam bit_num  = clogb2(NUMBER_OF_OUTPUT_WORDS);
+
+	// Define the states of state machine
+	// The control state machine oversees the writing of input streaming
+	// data to the FIFO, and outputs the streaming data from the FIFO
+	parameter [1:0] IDLE = 2'b00,	// This is the initial/idle state
+
+		INIT_COUNTER  = 2'b01,	// This state initializes the counter,
+					// once the counter reaches
+					// C_M_START_COUNT count, the state
+					// machine changes state to SEND_STREAM
+		SEND_STREAM   = 2'b10;	// In this state the
+					// stream data is output through M_AXIS_TDATA
+	// State variable
+	reg [1:0] mst_exec_state;
+	// Example design FIFO read pointer
+	reg [bit_num-1:0] read_pointer;
+
+	// AXI Stream internal signals
+	// wait counter. The master waits for the user defined number of
+	// clock cycles before initiating a transfer.
+	reg [WAIT_COUNT_BITS-1 : 0] 	count;
+	//streaming data valid
+	wire  	axis_tvalid;
+	//streaming data valid delayed by one clock cycle
+	reg  	axis_tvalid_delay;
+	//Last of the streaming data
+	wire  	axis_tlast;
+	//Last of the streaming data delayed by one clock cycle
+	reg  	axis_tlast_delay;
+	//FIFO implementation signals
+	reg [C_M_AXIS_TDATA_WIDTH-1 : 0] 	stream_data_out;
+	wire  	tx_en;
+	//The master has issued all the streaming data stored in FIFO
+	reg  	tx_done;
+
+
+	// I/O Connections assignments
+
+	assign M_AXIS_TVALID	= axis_tvalid_delay;
+	assign M_AXIS_TDATA	= stream_data_out;
+	assign M_AXIS_TLAST	= axis_tlast_delay;
+	assign M_AXIS_TSTRB	= {(C_M_AXIS_TDATA_WIDTH/8){1'b1}};
+
+
+	// Control state machine implementation
+	always @(posedge M_AXIS_ACLK)
+	if (!M_AXIS_ARESETN)
+	// Synchronous reset (active low)
+	begin
+		mst_exec_state <= IDLE;
+		count <= 0;
+	end else case (mst_exec_state)
+	IDLE:
+		// The slave starts accepting tdata when
+		// there tvalid is asserted to mark the
+		// presence of valid streaming data
+		//if ( count == 0 )
+		//  begin
+		mst_exec_state  <= INIT_COUNTER;
+		//  end
+		//else
+		//  begin
+		//    mst_exec_state  <= IDLE;
+		//  end
+
+	INIT_COUNTER:
+		// The slave starts accepting tdata when
+		// there tvalid is asserted to mark the
+		// presence of valid streaming data
+		if ( count == C_M_START_COUNT - 1 )
+			mst_exec_state  <= SEND_STREAM;
+		else begin
+			count <= count + 1;
+			mst_exec_state  <= INIT_COUNTER;
+		end
+
+	SEND_STREAM:
+		// The example design streaming master functionality starts when
+		// the master drives output tdata from the FIFO and the slave
+		// has finished storing the S_AXIS_TDATA
+		if (tx_done)
+			mst_exec_state <= IDLE;
+		else
+			mst_exec_state <= SEND_STREAM;
+	endcase
+
+
+	//tvalid generation
+	//axis_tvalid is asserted when the control state machine's state
+	// is SEND_STREAM and number of output streaming data is less than
+	// the NUMBER_OF_OUTPUT_WORDS.
+	assign axis_tvalid = ((mst_exec_state == SEND_STREAM) && (read_pointer < NUMBER_OF_OUTPUT_WORDS));
+
+	// AXI tlast generation
+	// axis_tlast is asserted number of output streaming data
+	// is NUMBER_OF_OUTPUT_WORDS-1 (0 to NUMBER_OF_OUTPUT_WORDS-1)
+	assign axis_tlast = (read_pointer == NUMBER_OF_OUTPUT_WORDS-1);
+
+
+	// Delay the axis_tvalid and axis_tlast signal by one clock cycle
+	// to match the latency of M_AXIS_TDATA
+	always @(posedge M_AXIS_ACLK)
+	if (!M_AXIS_ARESETN)
+	begin
+		axis_tvalid_delay <= 1'b0;
+		axis_tlast_delay <= 1'b0;
+	end else begin
+		axis_tvalid_delay <= axis_tvalid;
+		axis_tlast_delay <= axis_tlast;
+	end
+
+
+	//read_pointer pointer
+	always@(posedge M_AXIS_ACLK)
+	if(!M_AXIS_ARESETN)
+	begin
+		read_pointer <= 0;
+		tx_done <= 1'b0;
+	end else if (read_pointer <= NUMBER_OF_OUTPUT_WORDS-1)
+	begin
+		if (tx_en)
+		// read pointer is incremented after every read from the FIFO
+		// when FIFO read signal is enabled.
+		begin
+			read_pointer <= read_pointer + 1;
+			tx_done <= 1'b0;
+		end
+	end else if (read_pointer == NUMBER_OF_OUTPUT_WORDS)
+	begin
+		// tx_done is asserted when NUMBER_OF_OUTPUT_WORDS numbers
+		// of streaming data has been out.
+		tx_done <= 1'b1;
+	end
+
+
+	//FIFO read enable generation
+	assign tx_en = M_AXIS_TREADY && axis_tvalid;
+
+		// Streaming output data is read from FIFO
+	always @( posedge M_AXIS_ACLK )
+	if(!M_AXIS_ARESETN)
+		stream_data_out <= 1;
+	else if (tx_en)// && M_AXIS_TSTRB[byte_index]
+		stream_data_out <= read_pointer + 32'b1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Add user logic here
+	//
+	// The below initial lines, and FORMAL section following, were not in
+	// Xilinx's original demo example.
+	//
+	// This initial logic is used to keep the formal proof consistent
+	// below.  It's not strictly needed, neither was it part of Xilinx's
+	// original example demo.
+	initial count = 0;
+	initial mst_exec_state = IDLE;
+	initial	read_pointer = 0;
+	initial tx_done = 0;
+	// User logic ends
+`ifdef	FORMAL
+	localparam	F_LGDEPTH = $clog2(NUMBER_OF_OUTPUT_WORDS+1)+2;
+	localparam	AW  = 1;
+	localparam	IDW = 1;
+
+	wire	[F_LGDEPTH-1:0]	f_bytecount;
+	wire	[AW+IDW-1:0]	f_routecheck;
+
+	reg	f_past_valid;
+	initial	f_past_valid = 0;
+	always @(posedge M_AXIS_ACLK)
+		f_past_valid <= 1;
+
+	//
+	// Insist that the proof starts in reset
+	//
+	always @(*)
+	if (!f_past_valid)
+		assume(!M_AXIS_ARESETN);
+
+	//
+	// Insist on reset values
+	//
+	always @(posedge M_AXIS_ACLK)
+	if (!f_past_valid || $past(!M_AXIS_ARESETN))
+	begin
+		assert(mst_exec_state == IDLE);
+		assert(read_pointer == 0);
+		assert(count == 0);
+		assert(!tx_done);
+	end
+
+	//
+	faxis_master #(
+		.F_LGDEPTH(F_LGDEPTH),
+		.F_MAX_PACKET({NUMBER_OF_OUTPUT_WORDS, 2'b00}+4),
+		.C_S_AXI_DATA_WIDTH(C_M_AXIS_TDATA_WIDTH),
+		.OPT_ASYNC_RESET(1'b0),
+		.C_S_AXI_ADDR_WIDTH(AW),
+		.C_S_AXI_ID_WIDTH(IDW),
+		.C_S_AXI_USER_WIDTH(1))
+	axi_stream_check(.i_aclk(M_AXIS_ACLK),
+		.i_aresetn(M_AXIS_ARESETN),
+		.i_tvalid(M_AXIS_TVALID),
+		.i_tready(M_AXIS_TREADY),
+		.i_tdata(M_AXIS_TDATA),
+		.i_tstrb(M_AXIS_TSTRB),
+		.i_tkeep(4'hf),
+		.i_tid(0),
+		.i_tdest(0),
+		.i_tuser(0),
+		.i_tlast(M_AXIS_TLAST),
+		.f_bytecount(f_bytecount),
+		.f_routecheck(f_routecheck));
+
+// `define	INDUCTION_PROOF
+`ifdef	INDUCTION_PROOF
+	always @(*)
+		assert(count <= C_M_START_COUNT-1);
+
+	always @(*)
+	if (count != C_M_START_COUNT-1)
+	begin
+		assert(!M_AXIS_TVALID);
+		assert(read_pointer == 0);
+	end
+
+	always @(*)
+	if (tx_done)
+	begin
+		assert(read_pointer == NUMBER_OF_OUTPUT_WORDS);
+		// assert();
+	end
+
+	always @(*)
+		assert(read_pointer <= NUMBER_OF_OUTPUT_WORDS);
+
+	always @(*)
+	if (tx_done)
+		assert(!M_AXIS_TVALID);
+
+	always @(*)
+	if ((read_pointer > 0)&&(!tx_done))
+		assert(M_AXIS_TVALID);
+
+	always @(posedge M_AXIS_ACLK)
+	if (f_past_valid)
+		cover(M_AXIS_ARESETN && !M_AXIS_TVALID
+			&& $past(M_AXIS_TVALID && M_AXIS_TLAST));
+
+	always @(*)
+	if (tx_done || M_AXIS_TVALID)
+		assert(count == C_M_START_COUNT-1);
+
+	always @(*)
+		assert((mst_exec_state == IDLE)
+			||(mst_exec_state == INIT_COUNTER)
+			||(mst_exec_state == SEND_STREAM));
+
+	// If you actually want to get induction to pass, you'll also need
+	// to assume TREADY
+	// always @(*)
+	//	assume(M_AXIS_TREADY);
+`endif
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	[3:0]	final_counter = 0;
+
+	initial	final_counter = 0;
+	always @(posedge M_AXIS_ACLK)
+	if (!M_AXIS_ARESETN)
+		final_counter <= 0;
+	else if (tx_done)
+		final_counter <= final_counter + 1;
+
+	always @(*)
+		cover(tx_done);
+
+	always @(*)
+		cover(&final_counter);
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/.gitignore b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/.gitignore
new file mode 100644
index 0000000..e5174a6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/.gitignore
@@ -0,0 +1,7 @@
+database
+quickcheck
+tasks
+*.tgz
+faxil_slave.v
+easyaxil.v
+notes.txt
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/Makefile b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/Makefile
new file mode 100644
index 0000000..96ce5c9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/Makefile
@@ -0,0 +1,59 @@
+################################################################################
+##
+## Filename: 	bench/mcy/easyaxil/Makefile
+##
+## Project:	WB2AXIPSP: bus bridges and other odds and ends
+##
+## Purpose:	
+##
+## Creator:	Dan Gisselquist, Ph.D.
+##		Gisselquist Technology, LLC
+##
+################################################################################
+##
+## Copyright (C) 2019-2020, Gisselquist Technology, LLC
+##
+## This file is part of the WB2AXIP project.
+##
+## The WB2AXIP project contains free software and gateware, licensed under the
+## Apache License, Version 2.0 (the "License").  You may not use this project,
+## or this file, except in compliance with the License.  You may obtain a copy
+## of the License at
+##
+##	http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+## WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+## License for the specific language governing permissions and limitations
+## under the License.
+##
+################################################################################
+##
+##
+YYMMDD:= `date +%Y%m%d`
+.PHONY: archive
+# archive:	$(YYMMDD)-easyaxil.tgz
+
+FILES := $(wildcard *.sv) $(wildcard *.v) $(wildcard *.cpp) $(wildcard *.h) $(wildcard *.sh) $(wildcard *.mcy) test_fm.sby
+
+archive: $(FILES)
+	tar -cvzhf $(YYMMDD)-easyaxil.tgz --exclude tasks --exclude database  --transform "sm^m./$(YYMMDD)-easyaxil/m" $(FILES)
+
+easyaxil.v:
+	@bash -c "if [ ! -e easyaxil.v ]; then ln -s ../../../rtl/easyaxil.v .; fi"
+
+faxil_slave.v:
+	@bash -c "if [ ! -e faxil_slave.v ]; then ln -s ../../../bench/formal/faxil_slave.v; fi"
+
+.PHONY: mcy
+mcy: config.mcy easyaxil.v faxil_slave.v test_eq.sh test_sim.sh test_fm.sh test_fm.sby easyaxil_tb.cpp easyaxil_tb.sv
+	rm -rf database/
+	rm -rf tasks/
+	mcy init
+	mcy run -j4
+
+.PHONY: clean
+clean:
+	rm -rf easyaxil.v faxil_slave.v
+	rm -rf database/ tasks/
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/axi_tb.h b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/axi_tb.h
new file mode 100644
index 0000000..c3cd6f0
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/axi_tb.h
@@ -0,0 +1,425 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename:	axi_tb.cpp
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	To provide a fairly generic interface wrapper to an AXI bus,
+//		that can then be used to create a test-bench class.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <verilated.h>
+#include <verilated_vcd_c.h>
+#include "testb.h"
+#include "devbus.h"
+
+const int	BOMBCOUNT = 32;
+
+template <class TB>	class	AXI_TB : public DEVBUS {
+	bool	m_buserr;
+#ifdef	INTERRUPTWIRE
+	bool	m_interrupt;
+#endif
+	VerilatedVcdC	*m_trace;
+public:
+	TB		*m_tb;
+	typedef	uint32_t	BUSW;
+	
+	bool	m_bomb;
+
+	AXI_TB(void) {
+		m_tb = new TB;
+		Verilated::traceEverOn(true);
+
+		m_bomb = false;
+
+		m_tb->m_core->S_AXI_AWVALID = 0;
+		m_tb->m_core->S_AXI_WVALID = 0;
+		m_tb->m_core->S_AXI_BREADY = 0;
+
+		m_tb->m_core->S_AXI_ARVALID = 0;
+		m_tb->m_core->S_AXI_RREADY = 0;
+		m_buserr = false;
+#ifdef	INTERRUPTWIRE
+		m_interrupt = false;
+#endif
+	}
+
+	virtual	~AXI_TB(void) {
+		delete m_tb;
+	}
+
+	virtual	void	opentrace(const char *vcdname) {
+		m_tb->opentrace(vcdname);
+	}
+
+	virtual	void	closetrace(void) {
+		m_tb->closetrace();
+	}
+
+	virtual	void	close(void) {
+		// m_tb->close();
+	}
+
+	virtual	void	kill(void) {
+		close();
+	}
+
+	virtual	void	eval(void) {
+		m_tb->m_core->eval();
+	}
+
+#define	TICK	m_tb->tick
+	void	tick(void) {
+		m_tb->tick();
+#ifdef	INTERRUPTWIRE
+		if (m_tb->m_core->INTERRUPTWIRE)
+			m_interrupt = true;
+#endif
+	}
+
+	virtual	void	reset(void) {
+		// m_tb->m_core->S_AXI_ARESETN = 0;
+		m_tb->m_core->S_AXI_ARESETN = 0;
+		m_tb->m_core->S_AXI_AWVALID = 0;
+		m_tb->m_core->S_AXI_WVALID  = 0;
+		m_tb->m_core->S_AXI_ARVALID = 0;
+
+		for(int k=0; k<16; k++)
+			tick();
+
+		m_tb->m_core->S_AXI_ARESETN = 1;
+		tick();
+	}
+
+	unsigned long	tickcount(void) {
+		return m_tb->m_time_ps / 10000l;
+	}
+
+	void	idle(const unsigned counts = 1) {
+		m_tb->m_core->S_AXI_AWVALID = 0;
+		m_tb->m_core->S_AXI_WVALID  = 0;
+		m_tb->m_core->S_AXI_BREADY  = 0;
+		m_tb->m_core->S_AXI_ARVALID = 0;
+		m_tb->m_core->S_AXI_RREADY  = 0;
+		for(unsigned k=0; k<counts; k++) {
+			tick();
+			assert(!m_tb->m_core->S_AXI_RVALID);
+			assert(!m_tb->m_core->S_AXI_BVALID);
+		}
+	}
+
+	BUSW readio(BUSW a) {
+		BUSW		result;
+		uint32_t	delay_count = 0;
+
+		// printf("AXI-READM(%08x)\n", a);
+
+		m_tb->m_core->S_AXI_ARVALID = 1;
+		m_tb->m_core->S_AXI_ARADDR  = a;
+		m_tb->m_core->S_AXI_RREADY  = 1;
+
+		while(!m_tb->m_core->S_AXI_ARREADY) {
+			tick();
+			assert(delay_count++ < BOMBCOUNT);
+		}
+
+		tick();
+
+		m_tb->m_core->S_AXI_ARVALID = 0;
+		delay_count = 0;
+
+		while(!m_tb->m_core->S_AXI_RVALID) { // || !RVALID
+			tick();
+			assert(delay_count++ < BOMBCOUNT);
+		}
+
+		result = m_tb->m_core->S_AXI_RDATA;
+		if (m_tb->m_core->S_AXI_RRESP & 2)
+			m_buserr = true;
+		assert(m_tb->m_core->S_AXI_RRESP == 0);
+
+		tick();
+
+		return result;
+	}
+
+	uint64_t read64(BUSW a) {
+		uint64_t	result;
+		int32_t		buf[2];
+
+		readv(a, 2, buf);
+		result = buf[1];
+		result = (result << 32) | (uint64_t)buf[0];
+		return result;
+	}
+
+	void	readv(const BUSW a, int len, BUSW *buf, const int inc=1) {
+		int		cnt, rdidx, delay_count = 0;
+
+		printf("AXI-READM(%08x, %d)\n", a, len);
+		m_tb->m_core->S_AXI_ARVALID = 1;
+		m_tb->m_core->S_AXI_ARADDR  = a & -4;
+		//
+		m_tb->m_core->S_AXI_RREADY = 1;
+
+		rdidx =0; cnt = 0;
+
+		do {
+			int	s;
+
+			m_tb->m_core->S_AXI_ARVALID = 1;
+			s = ((m_tb->m_core->S_AXI_ARVALID)
+				&&(m_tb->m_core->S_AXI_ARREADY==0))?0:1;
+			tick();
+			m_tb->m_core->S_AXI_ARADDR += (inc&(s^1))?4:0;
+			cnt += (s^1);
+			if (m_tb->m_core->S_AXI_RVALID) {
+				buf[rdidx++] = m_tb->m_core->S_AXI_RDATA;
+				delay_count = 0;
+			}
+			if (m_tb->m_core->S_AXI_RVALID
+					&& m_tb->m_core->S_AXI_RRESP != 0)
+				m_buserr = true;
+			assert(delay_count++ < BOMBCOUNT);
+		} while(cnt < len);
+
+		m_tb->m_core->S_AXI_ARVALID = 0;
+		delay_count = 0;
+
+		while(rdidx < len) {
+			tick();
+			if ((m_tb->m_core->S_AXI_RVALID)&&(m_tb->m_core->S_AXI_RREADY))
+				buf[rdidx++] = m_tb->m_core->S_AXI_RDATA;
+			if (m_tb->m_core->S_AXI_RVALID && m_tb->m_core->S_AXI_RRESP != 0)
+				m_buserr = true;
+			assert(delay_count++ < BOMBCOUNT);
+		}
+
+		tick();
+		m_tb->m_core->S_AXI_RREADY = 0;
+		assert(!m_tb->m_core->S_AXI_BVALID);
+		assert(!m_tb->m_core->S_AXI_RVALID);
+	}
+
+	void	readi(const BUSW a, const int len, BUSW *buf) {
+		readv(a, len, buf, 1);
+	}
+
+	void	readz(const BUSW a, const int len, BUSW *buf) {
+		readv(a, len, buf, 0);
+	}
+
+	void	writeio(const BUSW a, const BUSW v) {
+		int	delay_count = 0;
+
+		// printf("AXI-WRITEM(%08x) <= %08x\n", a, v);
+		m_tb->m_core->S_AXI_ARVALID = 0;
+		m_tb->m_core->S_AXI_RREADY  = 0;
+
+		m_tb->m_core->S_AXI_AWVALID = 1;
+		m_tb->m_core->S_AXI_WVALID  = 1;
+		m_tb->m_core->S_AXI_AWADDR  = a & (-4);
+		m_tb->m_core->S_AXI_WDATA   = v;
+		m_tb->m_core->S_AXI_WSTRB   = 0x0f;
+
+		while((m_tb->m_core->S_AXI_AWVALID)
+			&&(m_tb->m_core->S_AXI_WVALID)) {
+			int	awready = m_tb->m_core->S_AXI_AWREADY;
+			int	wready = m_tb->m_core->S_AXI_WREADY;
+
+			tick();
+
+			if (awready)
+				m_tb->m_core->S_AXI_AWVALID = 0;
+			if (wready)
+				m_tb->m_core->S_AXI_WVALID = 0;
+			assert(delay_count++ < BOMBCOUNT);
+		}
+
+		m_tb->m_core->S_AXI_BREADY = 1;
+		delay_count = 0;
+
+		while(!m_tb->m_core->S_AXI_BVALID) {
+			tick();
+			assert(delay_count++ < BOMBCOUNT);
+		}
+
+		if (m_tb->m_core->S_AXI_BRESP & 2)
+			m_buserr = true;
+		tick();
+	}
+
+	void	write64(const BUSW a, const uint64_t v) {
+		uint32_t	buf[2];
+		// printf("AXI-WRITE64(%08x) <= %016lx\n", a, v);
+		buf[0] = (uint32_t)v;
+		buf[1] = (uint32_t)(v >> 32);
+		writei(a, 2, buf);
+	}
+
+	void	writev(const BUSW a, const int ln, const BUSW *buf, const int inc=1) {
+		unsigned nacks = 0, awcnt = 0, wcnt = 0, delay_count = 0;
+
+		// printf("AXI-WRITEM(%08x, %d, ...)\n", a, ln);
+		m_tb->m_core->S_AXI_AWVALID = 1;
+		m_tb->m_core->S_AXI_AWADDR  = a & -4;
+		m_tb->m_core->S_AXI_WVALID = 1;
+		m_tb->m_core->S_AXI_WSTRB  = 0x0f;
+		m_tb->m_core->S_AXI_WDATA  = buf[0];
+		m_tb->m_core->S_AXI_BREADY = 1;
+		m_tb->m_core->S_AXI_RREADY = 0;
+
+		do {
+			int	awready, wready;
+
+			m_tb->m_core->S_AXI_WDATA   = buf[wcnt];
+
+			m_tb->m_core->S_AXI_AWVALID = (awcnt < (unsigned)ln);
+			m_tb->m_core->S_AXI_WVALID  = (wcnt < (unsigned)ln);
+
+			awready = m_tb->m_core->S_AXI_AWREADY;
+			wready  = m_tb->m_core->S_AXI_WREADY;
+
+			tick();
+			if (m_tb->m_core->S_AXI_AWVALID && awready) {
+				delay_count = 0;
+				awcnt++;
+				// Update the address
+				m_tb->m_core->S_AXI_AWADDR += (inc)?4:0;
+			}
+
+			if (m_tb->m_core->S_AXI_WVALID && wready) {
+				delay_count = 0;
+				wcnt++;
+			}
+
+			if (m_tb->m_core->S_AXI_BVALID) {
+				nacks++;
+
+				// Check for any bus errors
+				if (m_tb->m_core->S_AXI_BRESP & 2)
+					m_buserr = true;
+			}
+
+			assert(delay_count++ < BOMBCOUNT);
+		} while((awcnt<(unsigned)ln)||(wcnt<(unsigned)ln));
+
+		m_tb->m_core->S_AXI_AWVALID = 0;
+		m_tb->m_core->S_AXI_WVALID  = 0;
+		while(nacks < (unsigned)ln) {
+			tick();
+			if (m_tb->m_core->S_AXI_BVALID) {
+				nacks++;
+				delay_count = 0;
+				if (m_tb->m_core->S_AXI_BRESP & 2)
+					m_buserr = true;
+			}
+			assert(delay_count++ < BOMBCOUNT);
+		}
+
+		tick();
+
+		// Release the bus
+		m_tb->m_core->S_AXI_BREADY = 0;
+		m_tb->m_core->S_AXI_RREADY = 0;
+
+		assert(!m_tb->m_core->S_AXI_BVALID);
+		assert(!m_tb->m_core->S_AXI_RVALID);
+		assert(!m_tb->m_core->S_AXI_AWVALID);
+		assert(!m_tb->m_core->S_AXI_WVALID);
+	}
+
+	void	writei(const BUSW a, const int ln, const BUSW *buf) {
+		writev(a, ln, buf, 1);
+	}
+
+	void	writez(const BUSW a, const int ln, const BUSW *buf) {
+		writev(a, ln, buf, 0);
+	}
+
+
+	bool	bombed(void) const { return m_bomb; }
+
+	// bool	debug(void) const	{ return m_debug; }
+	// bool	debug(bool nxtv)	{ return m_debug = nxtv; }
+
+	bool	poll(void) {
+#ifdef	INTERRUPTWIRE
+		return (m_interrupt)||(m_tb->m_core->INTERRUPTWIRE != 0);
+#else
+		return false;
+#endif
+	}
+
+	bool	bus_err(void) const {
+#ifdef	AXIERR
+		return m_buserr;
+#else
+		return false;
+#endif
+	}
+
+	void	reset_err(void) {
+#ifdef	AXIERR
+		m_buserr = false;;
+#endif
+	}
+
+	void	usleep(unsigned msec) {
+#ifdef	CLKRATEHZ
+		unsigned count = CLKRATEHZ / 1000 * msec;
+#else
+		// Assume 100MHz if no clockrate is given
+		unsigned count = 1000*100 * msec;
+#endif
+		while(count-- != 0)
+#ifdef	INTERRUPTWIRE
+			if (poll()) return; else
+#endif
+			tick();
+	}
+
+	void	clear(void) {
+#ifdef	INTERRUPTWIRE
+		m_interrupt = false;
+#endif
+	}
+
+	void	wait(void) {
+#ifdef	INTERRUPTWIRE
+		while(!poll())
+			tick();
+#else
+		assert(("No interrupt defined",0));
+#endif
+	}
+};
+
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/config.mcy b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/config.mcy
new file mode 100644
index 0000000..cc3fa34
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/config.mcy
@@ -0,0 +1,51 @@
+[options]
+size 1000
+tags COVERED UNCOVERED NOCHANGE EQGAP FMONLY
+
+[script]
+read -sv easyaxil.v
+prep -top easyaxil
+
+[files]
+easyaxil.v
+
+[logic]
+use_formal = True
+
+tb_okay = (result("test_sim") == "PASS")
+eq_okay = (result("test_eq") == "PASS")
+
+if tb_okay and use_formal:
+    tb_okay = (result("test_fm") == "PASS")
+    if not tb_okay:
+        tag("FMONLY")
+
+if tb_okay and not eq_okay:
+    tag("UNCOVERED")
+elif not tb_okay and not eq_okay:
+    tag("COVERED")
+elif tb_okay and eq_okay:
+    tag("NOCHANGE")
+elif not tb_okay and eq_okay:
+    tag("EQGAP")
+else:
+    assert 0
+
+[report]
+if tags("EQGAP"):
+    print("Found %d mutations exposing a formal equivalence gap!" % tags("EQGAP"))
+if tags("COVERED")+tags("UNCOVERED"):
+    print("Coverage: %.2f%%" % (100.0*tags("COVERED")/(tags("COVERED")+tags("UNCOVERED"))))
+
+[test test_sim]
+maxbatchsize 10
+expect PASS FAIL
+run bash $PRJDIR/test_sim.sh
+
+[test test_eq]
+expect PASS FAIL
+run bash $PRJDIR/test_eq.sh
+
+[test test_fm]
+expect PASS FAIL
+run bash $PRJDIR/test_fm.sh
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/devbus.h b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/devbus.h
new file mode 100644
index 0000000..578ad14
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/devbus.h
@@ -0,0 +1,144 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename:	devbus.h
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	The purpose of this file is to document an interface which
+//		any device with a bus, whether it be implemented over a UART,
+//	an ethernet, or a PCI express bus, must implement.  This describes
+//	only an interface, and not how that interface is to be accomplished.
+//
+//	The neat part of this interface is that, if programs are designed to
+//	work with it, than the implementation details may be changed later
+//	and any program that once worked with the interface should be able
+//	to continue to do so.  (i.e., switch from a UART controlled bus to a
+//	PCI express controlled bus, with minimal change to the software of
+//	interest.)
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+#ifndef	DEVBUS_H
+#define	DEVBUS_H
+
+#include <stdio.h>
+#include <unistd.h>
+
+typedef	unsigned int	uint32;
+
+class	BUSERR {
+public:
+	uint32 addr;
+	BUSERR(const uint32 a) : addr(a) {};
+};
+
+class	DEVBUS {
+public:
+	typedef	uint32	BUSW;
+
+	virtual	void	kill(void) = 0;
+	virtual	void	close(void) = 0;
+
+	// Write a single value to a single address
+	//	a is the address of the value to be read as it exists on the
+	//		wishbone bus within the FPGA.
+	//	v is the singular value to write to this address
+	virtual	void	writeio(const BUSW a, const BUSW v) = 0;
+
+	// Read a single value to a single address
+	//	a is the address of the value to be read as it exists on the
+	//		wishbone bus within the FPGA.
+	//	This function returns the value read from the device wishbone
+	//		at address a.
+	virtual	BUSW	readio(const BUSW a) = 0;
+
+	// Read a series of values from values from a block of memory
+	//	a is the address of the value to be read as it exists on the
+	//		wishbone bus within the FPGA.
+	//	len is the number of words to read
+	//	buf is a pointer to a place to store the words once read.
+	// This is equivalent to:
+	//	for(int i=0; i<len; i++)
+	//		buf[i] = readio(a+i);
+	// only it's faster in our implementation.
+	virtual	void	readi(const BUSW a, const int len, BUSW *buf) = 0;
+
+	// Read a series of values from the same address in memory.  This
+	// call is identical to readi, save that the address is not incremented
+	// from one read to the next.  It is equivalent to:
+	//	for(int i=0; i<len; i++)
+	//		buf[i] = readio(a);
+	// only it's faster in our implementation.
+	//
+	virtual	void	readz(const BUSW a, const int len, BUSW *buf) = 0;
+
+	// Write a series of values into a block of memory on the FPGA
+	//	a is the address of the value to be written as it exists on the
+	//		wishbone bus within the FPGA.
+	//	len is the number of words to write
+	//	buf is a pointer to a place to from whence to grab the data
+	//		to be written.
+	// This is equivalent to:
+	//	for(int i=0; i<len; i++)
+	//		writeio(a+i, buf[i]);
+	// only it's faster in our implementation.
+	virtual	void	writei(const BUSW a, const int len, const BUSW *buf) = 0;
+	// Write a series of values into the same address on the FPGA bus.  This
+	// call is identical to writei, save that the address is not incremented
+	// from one write to the next.  It is equivalent to:
+	//	for(int i=0; i<len; i++)
+	//		writeio(a, buf[i]);
+	// only it's faster in our implementation.
+	//
+	virtual	void	writez(const BUSW a, const int len, const BUSW *buf) = 0;
+
+	// Query whether or not an interrupt has taken place
+	virtual	bool	poll(void) = 0;
+
+	// Sleep until interrupt, but sleep no longer than msec milliseconds
+	virtual	void	usleep(unsigned msec) = 0;
+
+	// Sleep until an interrupt, no matter how long it takes for that
+	// interrupt to take place
+	virtual	void	wait(void) = 0;
+
+	// Query whether or not a bus error has taken place.  This is somewhat
+	// of a misnomer, as my current bus error detection code exits any
+	// interface, but ... it is what it is.
+	virtual	bool	bus_err(void) const = 0;
+
+	// Clear any bus error condition.
+	virtual	void	reset_err(void) = 0;
+
+	// Clear any interrupt condition that has already been noticed by
+	// the interface, does not check for further interrupt
+	virtual	void	clear(void) = 0;
+
+	virtual	~DEVBUS(void) { };
+};
+
+#endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/easyaxil_tb.cpp b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/easyaxil_tb.cpp
new file mode 100644
index 0000000..3facc49
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/easyaxil_tb.cpp
@@ -0,0 +1,125 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename:	easyaxil_tb.cpp
+//
+// Project:	AXI DMA Check: A utility to measure AXI DMA speeds
+//
+// Purpose:	This is an automatic test-bench script for the EasyAXIL
+//		core.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020, Gisselquist Technology, LLC
+//
+// This program is free software (firmware): you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or (at
+// your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
+// target there if the PDF file isn't present.)  If not, see
+// <http://www.gnu.org/licenses/> for a copy.
+//
+// License:	GPL, v3, as defined and found on www.gnu.org,
+//		http://www.gnu.org/licenses/gpl.html
+//
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "verilated.h"
+#include "Veasyaxil.h"
+
+#include "testb.h"
+#include "axi_tb.h"
+
+typedef	AXI_TB<TESTB<Veasyaxil> >	EASYAXIL_TB;
+
+bool	checkreg(EASYAXIL_TB *tb, int reg) {
+	// Convert to an address
+	unsigned addr = reg * 4;
+
+	// Check that we can write to each individual bit
+	for(int b=0; b<32; b++) {
+		uint32_t	v, c;
+
+		v = (1<<b);
+		tb->writeio(addr, v);
+		c = tb->readio(addr);
+
+		if (v != c)
+			return false;
+printf("CHECK-bit %d: 0x%08x == 0x%08x\n", b, v, c);
+	}
+
+	// Let's try writing some random data
+	for(int b=0; b<32; b++) {
+		uint32_t	v, c;
+
+		v = rand();
+		tb->writeio(addr, v);
+		c = tb->readio(addr);
+
+		if (v != c)
+			return false;
+printf("CHECK-rand %d: 0x%08x == 0x%08x\n", b, v, c);
+	}
+
+	// Success
+	return true;
+}
+
+void	usage(void) {
+	fprintf(stderr, "USAGE: easyaxil_tb <index>\n");
+	fprintf(stderr, "\t<index>\tControls which mutation we examin\n");
+}
+
+int	main(int argc, char **argv) {
+	const	char *trace_file = NULL; // "trace.vcd";
+	Verilated::commandArgs(argc, argv);
+	EASYAXIL_TB	*tb = new EASYAXIL_TB;
+	bool		failed = false;
+
+	if (argc > 2) {
+		fprintf(stderr, "ERR: Too many arguments\n");
+		usage();
+		exit(EXIT_FAILURE);
+	}
+
+	int	index = 0;
+	if (argc > 1)
+		index = atoi(argv[1]);
+
+	if (trace_file)
+		tb->opentrace(trace_file);
+
+	tb->m_tb->m_core->mutsel = index;
+	tb->reset();
+
+	if (!failed) failed = !checkreg(tb, 0);
+	if (!failed) failed = !checkreg(tb, 1);
+	if (!failed) failed = !checkreg(tb, 2);
+	if (!failed) failed = !checkreg(tb, 3);
+
+	if (failed) {
+		printf("TEST FAIL!\n");
+		return EXIT_FAILURE;
+	}
+	printf("SUCCESS!\n");
+	return	EXIT_SUCCESS;
+}
+
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/easyaxil_tb.sv b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/easyaxil_tb.sv
new file mode 100644
index 0000000..69ca871
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/easyaxil_tb.sv
@@ -0,0 +1,251 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	easyaxil
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	A formal miter core to compare the easyaxil core to a similar
+//		(but mutated) core.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+//
+`default_nettype none
+//
+module	easyaxil_tb #(
+		// {{{
+		//
+		// Size of the AXI-lite bus.  These are fixed, since 1) AXI-lite
+		// is fixed at a width of 32-bits by Xilinx def'n, and 2) since
+		// we only ever have 4 configuration words.
+		parameter	C_AXI_ADDR_WIDTH = 4,
+		localparam	C_AXI_DATA_WIDTH = 32,
+		parameter [0:0]	OPT_SKIDBUFFER = 1'b0,
+		parameter [0:0]	OPT_LOWPOWER = 0
+		// }}}
+	) (
+		// {{{
+		input	wire					S_AXI_ACLK,
+		input	wire					S_AXI_ARESETN,
+		//
+		input	wire					S_AXI_AWVALID,
+		output	wire					S_AXI_AWREADY,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]		S_AXI_AWADDR,
+		input	wire	[2:0]				S_AXI_AWPROT,
+		//
+		input	wire					S_AXI_WVALID,
+		output	wire					S_AXI_WREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]		S_AXI_WDATA,
+		input	wire	[C_AXI_DATA_WIDTH/8-1:0]	S_AXI_WSTRB,
+		//
+		output	wire					S_AXI_BVALID,
+		input	wire					S_AXI_BREADY,
+		output	wire	[1:0]				S_AXI_BRESP,
+		//
+		input	wire					S_AXI_ARVALID,
+		output	wire					S_AXI_ARREADY,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]		S_AXI_ARADDR,
+		input	wire	[2:0]				S_AXI_ARPROT,
+		//
+		output	wire					S_AXI_RVALID,
+		input	wire					S_AXI_RREADY,
+		output	wire	[C_AXI_DATA_WIDTH-1:0]		S_AXI_RDATA,
+		output	wire	[1:0]				S_AXI_RRESP,
+		// }}}
+		input	wire	[7:0]				mutation_index
+	);
+
+	easyaxil // #(.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		// .OPT_SKIDBUFFER(OPT_SKIDBUFFER),
+		// .OPT_LOWPOWER(OPT_LOWPOWER)
+		// )
+	gold (
+		.S_AXI_ACLK(   S_AXI_ACLK),
+		.S_AXI_ARESETN(S_AXI_ARESETN),
+		//
+		.S_AXI_AWVALID(S_AXI_AWVALID),
+		.S_AXI_AWREADY(S_AXI_AWREADY),
+		.S_AXI_AWADDR( S_AXI_AWADDR),
+		.S_AXI_AWPROT( S_AXI_AWPROT),
+		//
+		.S_AXI_WVALID( S_AXI_WVALID),
+		.S_AXI_WREADY( S_AXI_WREADY),
+		.S_AXI_WDATA(  S_AXI_WDATA),
+		.S_AXI_WSTRB(  S_AXI_WSTRB),
+		//
+		.S_AXI_BVALID( S_AXI_BVALID),
+		.S_AXI_BREADY( S_AXI_BREADY),
+		.S_AXI_BRESP(  S_AXI_BRESP),
+		//
+		.S_AXI_ARVALID(S_AXI_ARVALID),
+		.S_AXI_ARREADY(S_AXI_ARREADY),
+		.S_AXI_ARADDR( S_AXI_ARADDR),
+		.S_AXI_ARPROT( S_AXI_ARPROT),
+		//
+		.S_AXI_RVALID(S_AXI_RVALID),
+		.S_AXI_RREADY(S_AXI_RREADY),
+		.S_AXI_RDATA( S_AXI_RDATA),
+		.S_AXI_RRESP( S_AXI_RRESP),
+		.mutsel(0)
+	);
+
+	wire	uut_AWREADY, uut_WREADY, uut_BVALID, uut_ARREADY, uut_RVALID;
+	wire	[1:0]	uut_BRESP, uut_RRESP;
+	wire	[31:0]	uut_RDATA;
+
+	easyaxil // #(
+		// .C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		// .OPT_SKIDBUFFER(OPT_SKIDBUFFER),
+		// .OPT_LOWPOWER(OPT_LOWPOWER)
+		// )
+	uut (
+		.S_AXI_ACLK(   S_AXI_ACLK),
+		.S_AXI_ARESETN(S_AXI_ARESETN),
+		//
+		.S_AXI_AWVALID(S_AXI_AWVALID),
+		.S_AXI_AWREADY(uut_AWREADY),
+		.S_AXI_AWADDR( S_AXI_AWADDR),
+		.S_AXI_AWPROT( S_AXI_AWPROT),
+		//
+		.S_AXI_WVALID( S_AXI_WVALID),
+		.S_AXI_WREADY( uut_WREADY),
+		.S_AXI_WDATA(  S_AXI_WDATA),
+		.S_AXI_WSTRB(  S_AXI_WSTRB),
+		//
+		.S_AXI_BVALID( uut_BVALID),
+		.S_AXI_BREADY( S_AXI_BREADY),
+		.S_AXI_BRESP(  uut_BRESP),
+		//
+		.S_AXI_ARVALID(S_AXI_ARVALID),
+		.S_AXI_ARREADY(uut_ARREADY),
+		.S_AXI_ARADDR( S_AXI_ARADDR),
+		.S_AXI_ARPROT( S_AXI_ARPROT),
+		//
+		.S_AXI_RVALID(uut_RVALID),
+		.S_AXI_RREADY(S_AXI_RREADY),
+		.S_AXI_RDATA( uut_RDATA),
+		.S_AXI_RRESP( uut_RRESP),
+		.mutsel(mutation_index)
+	);
+
+`ifdef	FORMAL
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Formal properties used in verfiying this core
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	reg	f_past_valid;
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The AXI-lite control interface
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	localparam	F_AXIL_LGDEPTH = 4;
+	wire	[F_AXIL_LGDEPTH-1:0]	faxil_rd_outstanding,
+					faxil_wr_outstanding,
+					faxil_awr_outstanding;
+
+	faxil_slave #(
+		// {{{
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.F_LGDEPTH(F_AXIL_LGDEPTH),
+		.F_AXI_MAXWAIT(2),
+		.F_AXI_MAXDELAY(2),
+		.F_AXI_MAXRSTALL(3),
+		.F_OPT_COVER_BURST(4)
+		// }}}
+	) faxil(
+		// {{{
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXI_AWVALID),
+		.i_axi_awready(S_AXI_AWREADY),
+		.i_axi_awaddr( S_AXI_AWADDR),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot( S_AXI_AWPROT),
+		//
+		.i_axi_wvalid(S_AXI_WVALID),
+		.i_axi_wready(S_AXI_WREADY),
+		.i_axi_wdata( S_AXI_WDATA),
+		.i_axi_wstrb( S_AXI_WSTRB),
+		//
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+		.i_axi_bresp( S_AXI_BRESP),
+		//
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+		.i_axi_araddr( S_AXI_ARADDR),
+		.i_axi_arcache(4'h0),
+		.i_axi_arprot( S_AXI_ARPROT),
+		//
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rready(S_AXI_RREADY),
+		.i_axi_rdata( S_AXI_RDATA),
+		.i_axi_rresp( S_AXI_RRESP),
+		//
+		.f_axi_rd_outstanding(faxil_rd_outstanding),
+		.f_axi_wr_outstanding(faxil_wr_outstanding),
+		.f_axi_awr_outstanding(faxil_awr_outstanding)
+		// }}}
+		);
+
+	always @(*)
+	if (S_AXI_ARESETN)
+	begin
+		if (S_AXI_AWVALID)
+			assert(S_AXI_AWREADY == uut_AWREADY);
+
+		if (S_AXI_WVALID)
+			assert(S_AXI_WREADY == uut_WREADY);
+
+		if (S_AXI_ARVALID)
+			assert(S_AXI_ARREADY == uut_ARREADY);
+
+		assert(S_AXI_BVALID == uut_BVALID);
+		assert(S_AXI_RVALID == uut_RVALID);
+
+		if (S_AXI_BVALID)
+			assert( S_AXI_BRESP == uut_BRESP );
+
+		if (S_AXI_RVALID)
+			assert({ S_AXI_RRESP, S_AXI_RDATA }
+				== { uut_RRESP, uut_RDATA });
+	end
+
+	// }}}
+	// }}}
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/easyprops.sv b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/easyprops.sv
new file mode 100644
index 0000000..29401b1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/easyprops.sv
@@ -0,0 +1,385 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	easyprops
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+//
+`default_nettype none
+//
+module	easyprops #(
+		// {{{
+		//
+		// Size of the AXI-lite bus.  These are fixed, since 1) AXI-lite
+		// is fixed at a width of 32-bits by Xilinx def'n, and 2) since
+		// we only ever have 4 configuration words.
+		parameter	C_AXI_ADDR_WIDTH = 4,
+		localparam	C_AXI_DATA_WIDTH = 32,
+		parameter [0:0]	OPT_SKIDBUFFER = 1'b0,
+		parameter [0:0]	OPT_LOWPOWER = 0,
+		localparam	ADDRLSB = $clog2(C_AXI_DATA_WIDTH)-3
+		// }}}
+	) (
+		// {{{
+		input	wire					S_AXI_ACLK,
+		input	wire					S_AXI_ARESETN,
+		//
+		input	wire					S_AXI_AWVALID,
+		input	wire					S_AXI_AWREADY,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]		S_AXI_AWADDR,
+		input	wire	[2:0]				S_AXI_AWPROT,
+		//
+		input	wire					S_AXI_WVALID,
+		input	wire					S_AXI_WREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]		S_AXI_WDATA,
+		input	wire	[C_AXI_DATA_WIDTH/8-1:0]	S_AXI_WSTRB,
+		//
+		input	wire					S_AXI_BVALID,
+		input	wire					S_AXI_BREADY,
+		input	wire	[1:0]				S_AXI_BRESP,
+		//
+		input	wire					S_AXI_ARVALID,
+		input	wire					S_AXI_ARREADY,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]		S_AXI_ARADDR,
+		input	wire	[2:0]				S_AXI_ARPROT,
+		//
+		input	wire					S_AXI_RVALID,
+		input	wire					S_AXI_RREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]		S_AXI_RDATA,
+		input	wire	[1:0]				S_AXI_RRESP,
+		// }}}
+		// input	wire	i_clk,
+		input	wire	[31:0]	r0,
+		input	wire	[31:0]	r1,
+		input	wire	[31:0]	r2,
+		input	wire	[31:0]	r3,
+		input	wire	axil_read_ready, axil_write_ready,
+		input	wire	[1:0]	awskd_addr, arskd_addr,
+		input	wire	[31:0]	wskd_data,
+		input	wire	[3:0]	wskd_strb
+	);
+
+`ifdef	FORMAL
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Formal properties used in verfiying this core
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	reg	f_past_valid;
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The AXI-lite control interface
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	localparam	F_AXIL_LGDEPTH = 4;
+	wire	[F_AXIL_LGDEPTH-1:0]	faxil_rd_outstanding,
+					faxil_wr_outstanding,
+					faxil_awr_outstanding;
+
+	faxil_slave #(
+		// {{{
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.F_LGDEPTH(F_AXIL_LGDEPTH),
+		.F_AXI_MAXWAIT(3),
+		.F_AXI_MAXDELAY(3),
+		.F_AXI_MAXRSTALL(3),
+		.F_OPT_COVER_BURST(4)
+		// }}}
+	) faxil(
+		// {{{
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXI_AWVALID),
+		.i_axi_awready(S_AXI_AWREADY),
+		.i_axi_awaddr( S_AXI_AWADDR),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot( S_AXI_AWPROT),
+		//
+		.i_axi_wvalid(S_AXI_WVALID),
+		.i_axi_wready(S_AXI_WREADY),
+		.i_axi_wdata( S_AXI_WDATA),
+		.i_axi_wstrb( S_AXI_WSTRB),
+		//
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+		.i_axi_bresp( S_AXI_BRESP),
+		//
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+		.i_axi_araddr( S_AXI_ARADDR),
+		.i_axi_arcache(4'h0),
+		.i_axi_arprot( S_AXI_ARPROT),
+		//
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rready(S_AXI_RREADY),
+		.i_axi_rdata( S_AXI_RDATA),
+		.i_axi_rresp( S_AXI_RRESP),
+		//
+		.f_axi_rd_outstanding(faxil_rd_outstanding),
+		.f_axi_wr_outstanding(faxil_wr_outstanding),
+		.f_axi_awr_outstanding(faxil_awr_outstanding)
+		// }}}
+		);
+
+	always @(*)
+	if (OPT_SKIDBUFFER)
+	begin
+		assert(faxil_awr_outstanding== (S_AXI_BVALID ? 1:0)
+			+(S_AXI_AWREADY ? 0:1));
+		assert(faxil_wr_outstanding == (S_AXI_BVALID ? 1:0)
+			+(S_AXI_WREADY ? 0:1));
+
+		assert(faxil_rd_outstanding == (S_AXI_RVALID ? 1:0)
+			+(S_AXI_ARREADY ? 0:1));
+	end else begin
+		assert(faxil_wr_outstanding == (S_AXI_BVALID ? 1:0));
+		assert(faxil_awr_outstanding == faxil_wr_outstanding);
+
+		assert(faxil_rd_outstanding == (S_AXI_RVALID ? 1:0));
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $past(S_AXI_ARESETN
+			&& axil_read_ready))
+	begin
+		assert(S_AXI_RVALID);
+		case($past(arskd_addr))
+		0: assert(S_AXI_RDATA == $past(r0));
+		1: assert(S_AXI_RDATA == $past(r1));
+		2: assert(S_AXI_RDATA == $past(r2));
+		3: assert(S_AXI_RDATA == $past(r3));
+		endcase
+	end
+
+	//
+	// Check that our low-power only logic works by verifying that anytime
+	// S_AXI_RVALID is inactive, then the outgoing data is also zero.
+	//
+	always @(*)
+	if (OPT_LOWPOWER && !S_AXI_RVALID)
+		assert(S_AXI_RDATA == 0);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	// While there are already cover properties in the formal property
+	// set above, you'll probably still want to cover something
+	// application specific here
+
+	// }}}
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Round #1 -- double check writes to registers
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	(* anyconst *)	reg[3:0]	f_addr;
+	reg [7:0]	f_byte, f_rbyte;
+
+	generate if (OPT_SKIDBUFFER)
+	begin
+		initial	f_byte = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			f_byte <= 0;
+		else if (axil_write_ready)
+		begin
+			if (awskd_addr == f_addr[3:2]
+					&& wskd_strb[f_addr[1:0]])
+				f_byte <= S_AXI_WDATA >> (8*f_addr[1:0]);
+		end
+
+	end else begin
+	
+		initial	f_byte = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			f_byte <= 0;
+		else if (S_AXI_AWVALID && S_AXI_WVALID && S_AXI_AWREADY && S_AXI_WREADY)
+		begin
+			if (S_AXI_AWADDR[3:2] == f_addr[3:2]
+					&& S_AXI_WSTRB[f_addr[1:0]])
+				f_byte <= S_AXI_WDATA >> (8*f_addr[1:0]);
+		end
+
+	end endgenerate
+
+	always @(*)
+	case(f_addr[3:2])
+	2'b00: f_rbyte = (r0 >> (8*f_addr[1:0]));
+	2'b01: f_rbyte = (r1 >> (8*f_addr[1:0]));
+	2'b10: f_rbyte = (r2 >> (8*f_addr[1:0]));
+	2'b11: f_rbyte = (r3 >> (8*f_addr[1:0]));
+	endcase
+
+	always @(*)
+		assert(f_byte == f_rbyte);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Round #2 -- double check ?WREADY signaling
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// ???
+`endif
+endmodule
+
+
+module skidprops #(
+	parameter	[0:0]	OPT_LOWPOWER = 0,
+	parameter	[0:0]	OPT_OUTREG = 1,
+	//
+	parameter	[0:0]	OPT_PASSTHROUGH = 0,
+	parameter		DW = 8
+	) (
+	input	wire			i_clk, i_reset,
+	input	wire			i_valid,
+	input	wire			o_ready,
+	input	wire	[DW-1:0]	i_data,
+	input	wire			o_valid,
+	input	wire			i_ready,
+	input	wire	[DW-1:0]	o_data,
+
+	input	wire	[DW-1:0]	r_data
+	);
+
+	// Reset properties
+	property RESET_CLEARS_IVALID;
+		@(posedge i_clk) i_reset |=> !i_valid;
+	endproperty
+
+	property IDATA_HELD_WHEN_NOT_READY;
+		@(posedge i_clk) disable iff (i_reset)
+		i_valid && !o_ready |=> i_valid && $stable(i_data);
+	endproperty
+
+	assert	property (IDATA_HELD_WHEN_NOT_READY);
+
+	generate if (!OPT_PASSTHROUGH)
+	begin
+
+		assert property (@(posedge i_clk)
+			OPT_OUTREG && i_reset |=> o_ready && !o_valid);
+
+		assert property (@(posedge i_clk)
+			!OPT_OUTREG && i_reset |-> !o_valid);
+
+		// Rule #1:
+		//	Once o_valid goes high, the data cannot change until the
+		//	clock after i_ready
+		assert property (@(posedge i_clk)
+			disable iff (i_reset)
+			o_valid && !i_ready
+			|=> (o_valid && $stable(o_data)));
+
+		// Rule #2:
+		//	All incoming data must either go directly to the
+		//	output port, or into the skid buffer
+		assert property (@(posedge i_clk)
+			disable iff (i_reset)
+			(i_valid && o_ready
+				&& (!OPT_OUTREG || o_valid) && !i_ready)
+				|=> (!o_ready && r_data == $past(i_data)));
+
+		// Rule #3:
+		//	After the last transaction, o_valid should become idle
+		if (!OPT_OUTREG)
+		begin
+
+			assert property (@(posedge i_clk)
+				disable iff (i_reset)
+				i_ready |=> (o_valid == i_valid));
+
+		end else begin
+
+			assert property (@(posedge i_clk)
+				disable iff (i_reset)
+				i_valid && o_ready |=> o_valid);
+
+			assert property (@(posedge i_clk)
+				disable iff (i_reset)
+				!i_valid && o_ready && i_ready |=> !o_valid);
+
+		end
+
+		// Rule #4
+		//	Same thing, but this time for r_valid
+		assert property (@(posedge i_clk)
+			!o_ready && i_ready |=> o_ready);
+
+
+		if (OPT_LOWPOWER)
+		begin
+			//
+			// If OPT_LOWPOWER is set, o_data and r_data both need
+			// to be zero any time !o_valid or !r_valid respectively
+			assert property (@(posedge i_clk)
+				(OPT_OUTREG || !i_reset) && !o_valid |-> o_data == 0);
+
+			assert property (@(posedge i_clk)
+				o_ready |-> r_data == 0);
+
+			// else
+			//	if OPT_LOWPOWER isn't set, we can lower our
+			//	logic count by not forcing these values to zero.
+		end
+
+	end endgenerate
+
+endmodule
+
+bind easyaxil easyprops copy (.*);
+`ifdef	CHECK_SKID
+bind easyaxil.SKIDBUFFER_WRITE.axilawskid skidprops #(.OPT_OUTREG(0), .OPT_LOWPOWER(easyaxil.OPT_LOWPOWER), .DW(2)) copy (.*);
+bind easyaxil.SKIDBUFFER_WRITE.axilwskid  skidprops #(.OPT_OUTREG(0), .OPT_LOWPOWER(easyaxil.OPT_LOWPOWER), .DW(36)) copy (.*);
+bind easyaxil.SKIDBUFFER_READ.axilarskid  skidprops #(.OPT_OUTREG(0), .OPT_LOWPOWER(easyaxil.OPT_LOWPOWER), .DW(2)) copy (.*);
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/test_eq.sh b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/test_eq.sh
new file mode 100644
index 0000000..3324a39
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/test_eq.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+exec 2>&1
+set -ex
+
+export SCRIPT=/home/dan/work/rnd/opencores/tools/mcy/scripts/create_mutated.sh
+# create_mutated.sh -c
+. ${SCRIPT} -c
+## create yosys script with instructions how to export the mutated design
+# {
+#	# read synthesized design
+#	echo "read_ilang ../../database/design.il"
+#	while read -r idx mut; do
+#		# add mutation to the design, to be enabled by value ${idx} on 8-bit input `mutsel` added to the module
+#		echo "mutate -ctrl mutsel 8 ${idx} ${mut#* }"
+#	done < input.txt
+#	# export design to RTLIL
+#	echo "write_ilang mutated.il"
+#	echo "write_verilog mutated.v"
+#} > mutate.ys
+
+## run the above script to create mutated.il
+yosys -ql mutate.log mutate.ys
+
+## run formal property check
+ln -s ../../test_eq.sv     .
+ln -s ../../test_fm.sby    .
+ln -s ../../faxil_slave.v  .
+ln -s ../../easyaxil_tb.sv .
+# sed -e '1,$s/easyaxil/goldenaxil/' < ../../easyaxil.v > goldenaxil.v
+
+sby -f test_fm.sby bmc
+
+## obtain result
+gawk "{ print 1, \$1; }" test_fm_bmc/status >> output.txt
+
+exit 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/test_fm.sby b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/test_fm.sby
new file mode 100644
index 0000000..e4d6381
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/test_fm.sby
@@ -0,0 +1,28 @@
+[tasks]
+prf
+bmc
+
+[options]
+prf: mode prove
+bmc: mode bmc
+bmc: depth 15
+prf: depth 5
+expect pass,fail,unknown
+
+[engines]
+smtbmc boolector
+
+[script]
+read -formal faxil_slave.v
+bmc: read -formal easyaxil_tb.sv
+read -sv mutated.v
+bmc: prep -top easyaxil_tb
+bmc: fmcombine easyaxil_tb gold uut
+prf: read -formal easyprops.sv
+prf: prep -top easyaxil
+
+[files]
+faxil_slave.v
+mutated.v
+bmc: easyaxil_tb.sv
+prf: easyprops.sv
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/test_fm.sh b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/test_fm.sh
new file mode 100644
index 0000000..1157d4a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/test_fm.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+exec 2>&1
+set -ex
+
+export SCRIPT=/home/dan/work/rnd/opencores/tools/mcy/scripts/create_mutated.sh
+# create_mutated.sh
+. ${SCRIPT}
+
+## create yosys script with instructions how to export the mutated design
+# {
+#	# read synthesized design
+#	echo "read_ilang ../../database/design.il"
+#	# apply mutation
+#	# First line is numbered one, two, etc.
+#	# This cust off the '1' in the beginning, keeps the rest of the
+#	# mutate command
+#	cut -f2- -d' ' input.txt
+#	# export design to RTLIL
+#	echo "write_ilang mutated.il"
+#	echo "write_verilog mutated.v"
+#} > mutate.ys
+
+## run the above script to create mutated.il
+yosys -ql mutate.log mutate.ys
+
+## run formal property check
+ln -s ../../test_fm.sby    .
+ln -s ../../faxil_slave.v  .
+ln -s ../../easyprops.sv .
+
+sby -f test_fm.sby prf
+
+## obtain result
+gawk "{ print 1, \$1; }" test_fm_prf/status | sed -e "s/UNKNOWN/FAIL/" >> output.txt
+
+exit 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/test_sim.sh b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/test_sim.sh
new file mode 100644
index 0000000..85b7059
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/test_sim.sh
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+# Pipe standard error stream to stdout
+exec 2>&1
+
+# Exit on any non-zero error code along the way
+set -ex
+
+export SCRIPT=${HOME}/work/rnd/opencores/tools/mcy/scripts/create_mutated.sh
+. ${SCRIPT} -c
+
+VROOT=/usr/local/share/verilator
+VINC=${VROOT}/include
+INCFILES="-I${VROOT}/include -Iobj_dir"
+CFLAGS="-Wall -O3"
+# CPPDIR="../../../cpp"
+CPPDIR="../.."
+OBJ=obj_dir
+
+# {
+#	echo "read_ilang ../../database/design.il"
+#	while read -r idx mut; do
+#		echo "mutate -ctrl mutsel 8 ${idx} ${mut#* }"
+#	# One line goes into input.txt
+#	done < input.txt
+#	echo "write_verilog -attr2comment mutated.v"
+#} > mutate.ys
+
+yosys -ql mutate.log mutate.ys
+cp ${CPPDIR}/easyaxil_tb.cpp  .
+cp ${CPPDIR}/axi_tb.h         .
+cp ${CPPDIR}/devbus.h         .
+cp ${CPPDIR}/testb.h          .
+
+cp mutated.v easyaxil.v
+verilator -O3 --trace -Wno-UNOPTFLAT -Wno-CASEOVERLAP -Wno-WIDTH -cc easyaxil.v
+g++ ${CFLAGS} ${INCFILES} -DMCY -c easyaxil_tb.cpp -o ${OBJ}/easyaxil.o
+g++ ${CFLAGS} ${INCFILES} -c ${VINC}/verilated.cpp -o ${OBJ}/verilated.o
+g++ ${CFLAGS} ${INCFILES} -c ${VINC}/verilated_vcd_c.cpp -o ${OBJ}/verilated_vcd.o
+cd obj_dir
+make -f Veasyaxil.mk
+g++ easyaxil.o verilated.o verilated_vcd.o Veasyaxil__ALL.a -o ../easyaxil_tb
+cd ..
+
+./easyaxil_tb 0 > goodsim.out || true
+good_sum=$(md5sum goodsim.out | awk '{ print $1; }')
+while read idx mut; do
+
+	./easyaxil_tb ${idx} > sim_${idx}.out || true
+	this_sum=$(md5sum sim_${idx}.out | awk '{ print $1; }')
+	echo "SUM " $this_sum
+	if [ $good_sum = $this_sum ]; then
+		echo "$idx PASS" >> output.txt
+	else
+		echo "$idx FAIL" >> output.txt
+	fi
+done < input.txt
+exit 0
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/testb.h b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/testb.h
new file mode 100644
index 0000000..4819dc6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/mcy/easyaxil/testb.h
@@ -0,0 +1,231 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename:	./testb.h
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+#ifndef	TESTB_H
+#define	TESTB_H
+
+// #define TRACE_FST
+
+#include <stdio.h>
+#include <stdint.h>
+#ifdef	TRACE_FST
+#define	TRACECLASS	VerilatedFstC
+#include <verilated_fst_c.h>
+#else // TRACE_FST
+#define	TRACECLASS	VerilatedVcdC
+#include <verilated_vcd_c.h>
+#endif
+
+	//
+	// The TESTB class is a useful wrapper for interacting with a Verilator
+	// based design.  Key to its capabilities are the tick() method for
+	// advancing the simulation timestep, and the opentrace() and
+	// closetrace() methods for handling VCD tracefile generation.  To
+	// use a non-VCD trace, redefine TRACECLASS before calling this
+	// function to the trace class you wish to use.
+//
+template <class VA>	class TESTB {
+public:
+	VA	*m_core;
+	bool		m_changed;
+	TRACECLASS*	m_trace;
+	bool		m_done, m_paused_trace;
+	uint64_t	m_time_ps;
+
+	//
+	// Since design has only one clock within it, we won't need to use the
+	// multiclock techniques, and so those aren't included here at this time.
+	//
+
+	TESTB(void) {
+		m_core = new VA;
+		m_time_ps  = 0ul;
+		m_trace    = NULL;
+		m_done     = false;
+		m_paused_trace = false;
+		Verilated::traceEverOn(true);
+	}
+	virtual ~TESTB(void) {
+		if (m_trace) m_trace->close();
+		delete m_core;
+		m_core = NULL;
+	}
+
+	//
+	// opentrace()
+	//
+	// Useful for beginning a (VCD) trace.  To open such a trace, just call
+	// opentrace() with the name of the VCD file you'd like to trace
+	// everything into
+	virtual	void	opentrace(const char *vcdname, int depth=99) {
+		if (!m_trace) {
+			m_trace = new TRACECLASS;
+			m_core->trace(m_trace, 99);
+			m_trace->spTrace()->set_time_resolution("ps");
+			m_trace->spTrace()->set_time_unit("ps");
+			m_trace->open(vcdname);
+			m_paused_trace = false;
+		}
+	}
+
+	//
+	// trace()
+	//
+	// A synonym for opentrace() above.
+	//
+	void	trace(const char *vcdname) {
+		opentrace(vcdname);
+	}
+
+	//
+	// pausetrace(pause)
+	//
+	// Set/clear a flag telling us whether or not to write to the VCD trace
+	// file.  The default is to write to the file, but this can be changed
+	// by calling pausetrace.  pausetrace(false) will resume tracing,
+	// whereas pausetrace(true) will stop all calls to Verilator's trace()
+	// function
+	//
+	virtual	bool	pausetrace(bool pausetrace) {
+		m_paused_trace = pausetrace;
+		return m_paused_trace;
+	}
+
+	//
+	// pausetrace()
+	//
+	// Like pausetrace(bool) above, except that pausetrace() will return
+	// the current status of the pausetrace flag above.  Specifically, it
+	// will return true if the trace has been paused or false otherwise.
+	virtual	bool	pausetrace(void) {
+		return m_paused_trace;
+	}
+
+	//
+	// closetrace()
+	//
+	// Closes the open trace file.  No more information will be written
+	// to it
+	virtual	void	closetrace(void) {
+		if (m_trace) {
+			m_trace->close();
+			delete m_trace;
+			m_trace = NULL;
+		}
+	}
+
+	//
+	// eval()
+	//
+	// This is a synonym for Verilator's eval() function.  It evaluates all
+	// of the logic within the design.  AutoFPGA based designs shouldn't
+	// need to be calling this, they should call tick() instead.  However,
+	// in the off chance that your design inputs depend upon combinatorial
+	// expressions that would be output based upon other input expressions,
+	// you might need to call this function.
+	virtual	void	eval(void) {
+		m_core->eval();
+	}
+
+	//
+	// tick()
+	//
+	// tick() is the main entry point into this helper core.  In general,
+	// tick() will advance the clock by one clock tick.  In a multiple clock
+	// design, this will advance the clocks up until the nearest clock
+	// transition.
+	virtual	void	tick(void) {
+		// Pre-evaluate, to give verilator a chance
+		// to settle any combinatorial logic that
+		// that may have changed since the last clock
+		// evaluation, and then record that in the
+		// trace.
+		eval();
+		if (m_trace && !m_paused_trace) m_trace->dump(m_time_ps+2500);
+
+		// Advance the one simulation clock, clk
+		m_time_ps+= 5000;
+		m_core->S_AXI_ACLK = 1;
+		eval();
+		// If we are keeping a trace, dump the current state to that
+		// trace now
+		if (m_trace && !m_paused_trace) {
+			m_trace->dump(m_time_ps);
+			m_trace->flush();
+		}
+
+		// <SINGLE CLOCK ONLY>:
+		// Advance the clock again, so that it has its negative edge
+		m_core->S_AXI_ACLK = 0;
+		m_time_ps+= 5000;
+		eval();
+		if (m_trace && !m_paused_trace) m_trace->dump(m_time_ps);
+
+		// Call to see if any simulation components need
+		// to advance their inputs based upon this clock
+		sim_clk_tick();
+	}
+
+	virtual	void	sim_clk_tick(void) {
+		// AutoFPGA will override this method within main_tb.cpp if any
+		// @SIM.TICK key is present within a design component also
+		// containing a @SIM.CLOCK key identifying this clock.  That
+		// component must also set m_changed to true.
+		m_changed = false;
+	}
+	virtual bool	done(void) {
+		if (m_done)
+			return true;
+
+		if (Verilated::gotFinish())
+			m_done = true;
+
+		return m_done;
+	}
+
+	//
+	// reset()
+	//
+	// Sets the i_reset input for one clock tick.  It's really just a
+	// function for the capabilies shown below.  You'll want to reset any
+	// external input values before calling this though.
+	virtual	void	reset(void) {
+		m_core->S_AXI_ARESETN = 0;
+		tick();
+		m_core->S_AXI_ARESETN = 1;
+		// printf("RESET\n");
+	}
+};
+
+#endif	// TESTB
+
diff --git a/verilog/rtl/softshell/third_party/wb2axip/bench/rtl/saxi_slave.v b/verilog/rtl/softshell/third_party/wb2axip/bench/rtl/saxi_slave.v
new file mode 100644
index 0000000..1f96a8c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/bench/rtl/saxi_slave.v
@@ -0,0 +1,1247 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	saxi_slave.v (Simulation properties of an AXI4 (full) slave)
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	This file contains a set of SVA properties designed to help
+//		verify whether or not an AXI4 core complies with the
+//	specification within a given simulation.  As written, the properties are
+//	not designed for formal verification and may (or may not) work in a
+//	formal context.
+//
+//	My intent is to base a set of formal properties, useful for verifying
+//	a design using induction, off of these properties.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// }}}
+module saxi_slave #(
+		// {{{
+		// AXI ID width
+		parameter C_AXI_ID_WIDTH	= 3,
+		// Data width
+		parameter C_AXI_DATA_WIDTH	= 128,
+		parameter C_AXI_ADDR_WIDTH	= 28,
+		// OPT_MAXBURST - Maximum burst length, minus 1
+		parameter [7:0] OPT_MAXBURST	= 8'hff,
+		// Exclusive access allowed
+		parameter [0:0] OPT_EXCLUSIVE	= 1,
+		// User design uses async resets -- not the default
+		parameter [0:0]	OPT_ASYNC_RESET  = 0,
+		// F_OPT_ASSUME_RESET, if set, will cause the design to
+		// *assume* the existence of a correct reset, rather than
+		// asserting it.  (No difference under simulation.)  It is
+		// appropriate anytime the reset logic is outside of the
+		/// circuit being examined
+		parameter [0:0]			F_OPT_ASSUME_RESET = 1'b1,
+		// F_OPT_RESET_WIDTH -- insist on a minimum reset width.
+		// (Xilinx recommends a minimum width of 16 clocks.  The
+		// AXI specification isn't that specific.)
+		parameter [0:0]			F_OPT_RESET_WIDTH = 1'b1,
+		// F_LGDEPTH is the number of bits necessary to count the
+		// maximum number of items in flight.
+		parameter				F_LGDEPTH      = 10,
+		// MAXSTALL -- the maximum number of stall cycles the slave can
+		// make the master wait.
+		parameter	[(F_LGDEPTH-1):0]	F_AXI_MAXSTALL = 3,
+		// MAXRSTALL (reverse stall) -- the maximum number of stall
+		// cycles the master can make the slave wait
+		parameter	[(F_LGDEPTH-1):0]	F_AXI_MAXRSTALL= 3,
+		// MAXDELAY -- maximum number of clock cycles to wait for an
+		// accepted packet to be returned.
+		parameter	[(F_LGDEPTH-1):0]	F_AXI_MAXDELAY = 3,
+		// F_OPT_BURSTS -- true if the maximum burst length is longer
+		// than a single beat
+		localparam	[0:0]	F_OPT_BURSTS    = (OPT_MAXBURST != 0),
+		// IW, DW, AW, and NUM_IDS are just short-hand notations
+		localparam IW			= C_AXI_ID_WIDTH,
+		localparam DW			= C_AXI_DATA_WIDTH,
+		localparam AW			= C_AXI_ADDR_WIDTH,
+		localparam NUM_IDS		= (1<<C_AXI_ID_WIDTH)
+	// }}}
+	) (
+		// {{{
+		input	wire			i_clk,	// System clock
+		input	wire			i_axi_aresetn,
+
+		// AXI write address channel signals
+		// {{{
+		input	wire			i_axi_awvalid,
+		input	wire			i_axi_awready,
+		input	wire	[IW-1:0]	i_axi_awid,
+		input	wire	[AW-1:0]	i_axi_awaddr,
+		input	wire	[7:0]		i_axi_awlen,
+		input	wire	[2:0]		i_axi_awsize,
+		input	wire	[1:0]		i_axi_awburst,
+		input	wire			i_axi_awlock,
+		input	wire	[3:0]		i_axi_awcache,
+		input	wire	[2:0]		i_axi_awprot,
+		input	wire	[3:0]		i_axi_awqos,
+		// }}}
+		// AXI write data channel signals
+		// {{{
+		input	wire			i_axi_wvalid,
+		input	wire			i_axi_wready, 
+		input	wire	[DW-1:0]	i_axi_wdata,
+		input	wire	[DW/8-1:0]	i_axi_wstrb,
+		input	wire			i_axi_wlast,
+		// }}}
+		// AXI write response channel signals
+		// {{{
+		input	wire			i_axi_bvalid,
+		input	wire			i_axi_bready, 
+		input	wire	[IW-1:0]	i_axi_bid,
+		input	wire	[1:0]		i_axi_bresp,
+		// }}}
+		// AXI read address channel signals
+		// {{{
+		input	wire			i_axi_arvalid,
+		input	wire			i_axi_arready,
+		input	wire	[IW-1:0]	i_axi_arid,
+		input	wire	[AW-1:0]	i_axi_araddr,
+		input	wire	[7:0]		i_axi_arlen,
+		input	wire	[2:0]		i_axi_arsize,
+		input	wire	[1:0]		i_axi_arburst,
+		input	wire	[0:0]		i_axi_arlock,
+		input	wire	[3:0]		i_axi_arcache,
+		input	wire	[2:0]		i_axi_arprot,
+		input	wire	[3:0]		i_axi_arqos,
+		// }}}
+		// AXI read data channel signals
+		// {{{
+		input	wire			i_axi_rvalid,
+		input	wire			i_axi_rready,
+		input wire [C_AXI_ID_WIDTH-1:0] i_axi_rid,
+		input	wire	[DW-1:0]	i_axi_rdata,
+		input	wire			i_axi_rlast,
+		input	wire	[1:0]		i_axi_rresp
+		// }}}
+	//  }}}
+	);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Parameter declarations
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	localparam [1:0]	EXOKAY = 2'b01;
+	localparam		F_AXI_MAXWAIT = F_AXI_MAXSTALL;
+
+	// Because of the nature and size of bursts, which can be up to
+	// 256 in length (AxLEN), the F_LGDEPTH parameter necessary to capture
+	// this *must* be at least 8 bits wide
+	always @(*)
+		assert(F_LGDEPTH > 8);
+
+	// Only power of two data sizes are supported from 8-bits on up to
+	// 1024
+	always @(*)
+		assert((DW == 8)
+			||(DW ==  16)
+			||(DW ==  32)
+			||(DW ==  64)
+			||(DW == 128)
+			||(DW == 256)
+			||(DW == 512)
+			||(DW == 1024));
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Internal register and wire declarations
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	wire	axi_rd_ack, axi_wr_ack, axi_ard_req, axi_awr_req, axi_wr_req,
+		axi_rd_err, axi_wr_err;
+	//
+	assign	axi_ard_req = (i_axi_arvalid)&&(i_axi_arready);
+	assign	axi_awr_req = (i_axi_awvalid)&&(i_axi_awready);
+	assign	axi_wr_req  = (i_axi_wvalid )&&(i_axi_wready);
+	//
+	assign	axi_rd_ack = (i_axi_rvalid)&&(i_axi_rready);
+	assign	axi_wr_ack = (i_axi_bvalid)&&(i_axi_bready);
+	assign	axi_rd_err = (axi_rd_ack)&&(i_axi_rresp[1]);
+	assign	axi_wr_err = (axi_wr_ack)&&(i_axi_bresp[1]);
+
+	//
+	reg	[F_LGDEPTH-1:0]		f_axi_awr_nbursts;
+	reg	[9-1:0]			f_axi_wr_pending;
+	reg	[F_LGDEPTH-1:0]		f_axi_rd_nbursts;
+	reg	[F_LGDEPTH-1:0]		f_axi_rd_outstanding;
+	//
+	reg				awfifo_read;
+	wire				awfifo_full, awfifo_empty;
+	wire	[F_LGDEPTH:0]		awfifo_fill;
+	wire [C_AXI_ID_WIDTH-1:0]	awfifo_id;
+	wire [C_AXI_ADDR_WIDTH-1:0]	awfifo_addr;
+	wire	[7:0]			awfifo_len;
+	wire	[1:0]			awfifo_burst;
+	wire	[2:0]			awfifo_size;
+	wire				awfifo_lock;
+	wire	[3:0]			awfifo_cache;
+	wire	[2:0]			awfifo_prot;
+	wire	[3:0]			awfifo_qos;
+
+	reg	[C_AXI_ID_WIDTH-1:0]	f_axi_wr_this_id;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	f_axi_wr_this_addr;
+	reg	[7:0]			f_axi_wr_this_len;
+	reg	[1:0]			f_axi_wr_this_burst;
+	reg	[2:0]			f_axi_wr_this_size;
+	reg				f_axi_wr_this_lock;
+	reg	[3:0]			f_axi_wr_this_cache;
+	reg	[2:0]			f_axi_wr_this_prot;
+	reg	[3:0]			f_axi_wr_this_qos;
+
+	reg	[C_AXI_ID_WIDTH-1:0]	r_axi_wr_id;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	r_axi_wr_addr;
+	reg	[7:0]			r_axi_wr_len;
+	reg	[1:0]			r_axi_wr_burst;
+	reg	[2:0]			r_axi_wr_size;
+	reg				r_axi_wr_lock;
+	reg	[3:0]			r_axi_wr_cache;
+	reg	[2:0]			r_axi_wr_prot;
+	reg	[3:0]			r_axi_wr_qos;
+	wire	[C_AXI_ADDR_WIDTH-1:0]	next_write_addr;
+	wire	[7:0]			f_axi_wr_this_incr;
+
+	reg	[8:0]			r_wr_pending;
+
+	reg				wfifo_read;
+	wire				wfifo_full, wfifo_empty;
+	wire	[F_LGDEPTH:0]		wfifo_fill;
+	wire	[C_AXI_DATA_WIDTH-1:0]	wfifo_data;
+	wire [C_AXI_DATA_WIDTH/8-1:0]	wfifo_strb;
+	wire 				wfifo_last;
+	wire				valid_iwaddr, // Incoming write address
+					valid_iraddr;
+	reg				f_past_valid;
+	reg				awr_aligned,
+					ard_aligned;
+	wire	[AW-1:0]		next_rd_addr;
+
+	reg				wstb_valid;
+
+	genvar	gk;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Pre-setup
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// Within the slave core, we will *assume* properties from the master,
+	// and *assert* properties of signals coming from the slave and
+	// returning to the master.  This order will be reversed within the
+	// master, and the following two definitions help us do that.
+`define	ASSUME		assume
+`define	SLAVE_ASSUME	assume
+`define	SLAVE_ASSERT	assert
+
+	// f_past_valid
+	// {{{
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Reset properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Insist that the reset signal start out asserted (negative), and
+	// remain so for 16 clocks.
+	//
+
+	// The reset should be active initially
+	// {{{
+	generate if (F_OPT_ASSUME_RESET)
+	begin : ASSUME_INITIAL_RESET
+
+		`ASSUME property (@(posedge i_clk)
+			!f_past_valid |-> !i_axi_aresetn);
+
+	end else begin : ASSERT_INITIAL_RESET
+
+		assert property (@(posedge i_clk)
+			!f_past_valid |-> !i_axi_aresetn);
+
+	end endgenerate
+	// }}}
+
+	// If !F_OPT_NO_RESET, insist on a minimum 16-clock reset
+	// {{{
+	generate if (F_OPT_ASSUME_RESET && F_OPT_RESET_WIDTH > 1)
+	begin
+		`ASSUME property (@(posedge i_clk)
+			(!f_past_valid || $fell(i_axi_aresetn))
+				|-> !i_axi_aresetn [*F_OPT_RESET_WIDTH]);
+
+	end else if (F_OPT_RESET_WIDTH > 1)
+	begin
+
+		`SLAVE_ASSUME property (@(posedge i_clk)
+			(!f_past_valid || $fell(i_axi_aresetn))
+				|-> !i_axi_aresetn [*F_OPT_RESET_WIDTH]);
+
+	end endgenerate
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Clear everything on a reset
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	`SLAVE_ASSUME property (@(posedge i_clk)
+		!i_axi_aresetn |=> !i_axi_awvalid && !i_axi_wvalid
+				&& !i_axi_arvalid);
+
+	`SLAVE_ASSERT property (@(posedge i_clk)
+		!i_axi_aresetn |=> !i_axi_bvalid && !i_axi_rvalid);
+
+	generate if (OPT_ASYNC_RESET)
+	begin : ASYNC_RESET_CHECKING
+		// {{{
+		property ASYNC_CLEAR_REQUEST_ON_RESET;
+			@(posedge i_clk)
+			!i_axi_aresetn |-> !i_axi_awvalid && !i_axi_wvalid
+					&& !i_axi_arvalid;
+		endproperty
+
+		property ASYNC_CLEAR_RETURN_ON_RESET;
+			@(posedge i_clk)
+			!i_axi_aresetn |-> !i_axi_bvalid && !i_axi_rvalid;
+		endproperty
+
+		`SLAVE_ASSUME property(ASYNC_CLEAR_REQUEST_ON_RESET);
+		`SLAVE_ASSERT property(ASYNC_CLEAR_RETURN_ON_RESET);
+		// }}}
+	end endgenerate
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Stability properties--what happens if valid and not ready
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// Assume any response from the bus will not change prior to that
+	// response being accepted
+
+	// Write address channel
+	// {{{
+	property STABLE_AW;
+		@(posedge i_clk)
+		i_axi_aresetn && i_axi_awvalid && !i_axi_awready
+		##1 (!OPT_ASYNC_RESET || i_axi_aresetn)
+		|-> i_axi_awvalid
+			&& $stable({ i_axi_awid, i_axi_awaddr, i_axi_awlen,
+				i_axi_awsize, i_axi_awburst, i_axi_awlock,
+				i_axi_awcache, i_axi_awprot, i_axi_awqos });
+	endproperty
+	// }}}
+
+	// Write data channel
+	// {{{
+	property STABLE_W;
+		@(posedge i_clk)
+		i_axi_aresetn && i_axi_wvalid && !i_axi_wready
+		##1 (!OPT_ASYNC_RESET || i_axi_aresetn)
+		|-> i_axi_wvalid
+			&& $stable({ i_axi_wdata, i_axi_wstrb, i_axi_wlast });
+	endproperty
+	// }}}
+
+	// Write return channel
+	// {{{
+	property STABLE_B;
+		@(posedge i_clk)
+		i_axi_aresetn && i_axi_bvalid && !i_axi_bready
+		##1 (!OPT_ASYNC_RESET || i_axi_aresetn)
+		|-> i_axi_bvalid
+			&& $stable({ i_axi_bid, i_axi_bresp });
+	endproperty
+	// }}}
+
+	// Read address channel
+	// {{{
+	property STABLE_AR;
+		@(posedge i_clk)
+		i_axi_aresetn && i_axi_arvalid && !i_axi_arready
+		##1 (!OPT_ASYNC_RESET || i_axi_aresetn)
+		|-> i_axi_arvalid
+			&& $stable({ i_axi_arid, i_axi_araddr, i_axi_arlen,
+				i_axi_arsize, i_axi_arburst, i_axi_arlock,
+				i_axi_arcache, i_axi_arprot, i_axi_arqos });
+	endproperty
+	// }}}
+
+	// Read return channel
+	// {{{
+	property STABLE_R;
+		@(posedge i_clk)
+		i_axi_aresetn && i_axi_rvalid && !i_axi_rready
+		##1 (!OPT_ASYNC_RESET || i_axi_aresetn)
+		|-> i_axi_rvalid
+			&& $stable({ i_axi_rid, i_axi_rdata, i_axi_rlast,
+				i_axi_rresp });
+	endproperty
+	// }}}
+
+	`SLAVE_ASSUME property(STABLE_AW);
+	`SLAVE_ASSUME property(STABLE_W);
+	`SLAVE_ASSUME property(STABLE_AR);
+
+	`SLAVE_ASSERT property(STABLE_B);
+	`SLAVE_ASSERT property(STABLE_R);
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Insist upon a maximum number of stalls before a request is accepted
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate if (F_AXI_MAXWAIT > 0)
+	begin : CHECK_STALL_COUNT
+
+		// AXI write address channel
+		// {{{
+		// Insist that AW channel can stall no more than F_AXI_MAXWAIT
+		// cycles before AWREADY is raised.  However, if
+		// BVALID && !BREADY, then the slave  has a reason why it might
+		// not want to accepting any more transactions.  Similarly,
+		// many cores will only ever accept one request at a time,
+		// hence we won't count things as stalls if we are still
+		// waiting on write data--that's handled in another assertion
+		// below.
+
+		property MAX_AW_STALLS;
+			@(posedge i_clk)
+			disable iff (!i_axi_aresetn || f_axi_wr_pending > 0)
+			i_axi_awvalid && !i_axi_awready [*F_AXI_MAXWAIT]
+			|=> i_axi_awready;
+		endproperty
+
+		`SLAVE_ASSERT property(MAX_AW_STALLS);
+		// }}}
+
+		// AXI write data channel
+		// {{{
+		// Insist that the write data channel be stalled  no more than
+		// F_AXI_MAXWAIT cycles.  Since things can back up if
+		// BVALID & !BREADY, we avoid counting clock cycles in that
+		// circumstance
+
+		property MAX_WREADY_STALLS;
+			@(posedge i_clk)
+			disable iff (!i_axi_aresetn || f_axi_wr_pending == 0
+					|| (i_axi_bvalid && !i_axi_bready))
+			i_axi_wvalid && !i_axi_wready [*F_AXI_MAXWAIT]
+			|=> i_axi_wready;
+		endproperty
+
+		`SLAVE_ASSERT property(MAX_WREADY_STALLS);
+		// }}}
+
+		// AXI read address channel
+		// {{{
+		// Similar to the first two above, once the master raises
+		// ARVALID, insist that the slave accept the read address
+		// request within a minimum number of clock cycles.
+		// Exceptions include any time RVALID is true, since that can
+		// back up the whole system, and any time the number of bursts
+		// is greater than zero, since many slaves can only accept one
+		// request at a time.
+
+		property MAX_AR_STALLS;
+			@(posedge i_clk)
+			disable iff (!i_axi_aresetn || f_axi_rd_nbursts > 0)
+			i_axi_arvalid && !i_axi_arready [*F_AXI_MAXWAIT]
+			|=> i_axi_arready;
+		endproperty
+
+		`SLAVE_ASSERT property(MAX_AR_STALLS);
+		// }}}
+	end endgenerate
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Insist upon a maximum delay before any response is accepted
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Note that this is a *response* channel property, so it is separate
+	// from the earlier properties in case you wish to control it
+	// separately.  For example, an interconnect might be forced to let a
+	// channel wait indefinitely for access, but it might not be
+	// appropriate to require the response to be able to wait indefinitely
+	// as well.  So, here we check the response time.
+	//
+	//
+
+	generate if (F_AXI_MAXRSTALL > 0)
+	begin : CHECK_RESPONSE_STALLS
+		// AXI write channel valid
+		// {{{
+		// The first master stall check: guarantee that the master
+		// provides the required write data in fairly short order,
+		// and without much delay.  That is, once AWVALID && AWREADY
+		// are true, the slave needs to provide the W* values.
+		// This is the only "forward" property check among our response
+		// channel checks, since it's a master and not a slave property.
+
+		property MAX_WDATA_STALLS;
+			@(posedge i_clk)
+			i_axi_aresetn
+			&& (!i_axi_bvalid || i_axi_bready)
+			&& (f_axi_wr_pending > 0)
+			&& (!i_axi_wvalid) [*F_AXI_MAXRSTALL]
+			|=> i_axi_wvalid;
+		endproperty
+
+		`SLAVE_ASSUME property(MAX_WDATA_STALLS);
+		// }}}
+
+		// AXI write response channel
+		// {{{
+		// Insist on a maximum number of clocks that BVALID can be
+		// high while BREADY is low
+		property MAX_B_STALLS;
+			@(posedge i_clk)
+			i_axi_bvalid && !i_axi_bready [*F_AXI_MAXRSTALL]
+			|=> i_axi_bready;
+		endproperty
+
+		`SLAVE_ASSUME property(MAX_B_STALLS);
+		// /}}}
+
+		// AXI read response channel
+		// {{{
+		// Insist on a maximum number of clocks that RVALID can be
+		// high while RREADY is low
+		property MAX_R_STALLS;
+			@(posedge i_clk)
+			i_axi_rvalid && !i_axi_rready [*F_AXI_MAXRSTALL]
+			|=> i_axi_rready;
+		endproperty
+
+		`SLAVE_ASSUME property(MAX_R_STALLS);
+		// }}}
+	end endgenerate
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write property checking
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// Validate the incoming address channel packet
+	// {{{
+	faxi_valaddr #(.C_AXI_DATA_WIDTH(DW), .C_AXI_ADDR_WIDTH(AW),
+			.OPT_MAXBURST(OPT_MAXBURST),
+			.OPT_EXCLUSIVE(OPT_EXCLUSIVE),
+			.OPT_NARROW_BURST(1'b1))
+		f_wraddr_validate(i_axi_awaddr, i_axi_awlen, i_axi_awsize,
+			i_axi_awburst, i_axi_awlock,
+			1'b1, awr_aligned, valid_iwaddr);
+
+	`SLAVE_ASSUME property (@(posedge i_clk)
+		i_axi_awvalid |-> valid_iwaddr);
+	// }}}
+
+	// Write address request FIFO
+	// {{{
+	// Queue write address requests so we can process them one packet
+	// at a time.
+	sfifo #(
+		// {{{
+		.BW(C_AXI_ID_WIDTH + C_AXI_ADDR_WIDTH + 8 + 2 + 3+1+4+3+4),
+		.LGFLEN(F_LGDEPTH),
+		.OPT_ASYNC_READ(1'b0),
+		.OPT_WRITE_ON_FULL(1'b1),
+		.OPT_READ_ON_EMPTY(1'b1)
+		// }}}
+	) awrequests (
+		// {{{
+		.i_clk(i_clk), .i_reset(!i_axi_aresetn),
+		.i_wr(i_axi_awvalid && i_axi_awready),
+		.i_data({ i_axi_awid, i_axi_awaddr, i_axi_awlen,
+			i_axi_awburst, i_axi_awsize, i_axi_awlock,
+			i_axi_awcache, i_axi_awprot, i_axi_awqos }),
+		.o_full(awfifo_full), .o_fill(awfifo_fill),
+		.i_rd(awfifo_read),
+		.o_data({ awfifo_id, awfifo_addr, awfifo_len,
+			awfifo_burst, awfifo_size, awfifo_lock,
+			awfifo_cache, awfifo_prot, awfifo_qos }),
+		.o_empty(awfifo_empty)
+		// }}}
+	);
+
+	always @(*)
+		awfifo_read = (r_wr_pending == 0);
+	// }}}
+
+	// Write data FIFO
+	// {{{
+	// In AXI, the write data can come before the address.  In such
+	// circumstances, you need to hold on to that data in a queue (FIFO)
+	// until the address is available so that you can compare the two
+	// against each other for validity.
+	sfifo #(
+		// {{{
+		.BW(C_AXI_DATA_WIDTH + (C_AXI_DATA_WIDTH/8) + 1),
+		.LGFLEN(F_LGDEPTH),
+		.OPT_ASYNC_READ(1'b0),
+		.OPT_WRITE_ON_FULL(1'b1),
+		.OPT_READ_ON_EMPTY(1'b1)
+		// }}}
+	) wrequests (
+		// {{{
+		.i_clk(i_clk), .i_reset(!i_axi_aresetn),
+		.i_wr(i_axi_wvalid && i_axi_wready),
+		.i_data({ i_axi_wdata, i_axi_wstrb, i_axi_wlast }),
+		.o_full(wfifo_full), .o_fill(wfifo_fill),
+		.i_rd(wfifo_read),
+		.o_data({ wfifo_data, wfifo_strb, wfifo_last }),
+		.o_empty(wfifo_empty)
+		// }}}
+	);
+
+	always @(*)
+		wfifo_read = (r_wr_pending > 0)||(awfifo_read && !awfifo_empty);
+	// }}}
+
+	// Make sure AWLOCK is low if !OPT_EXCLUSIVE
+	// {{{
+	generate if (!OPT_EXCLUSIVE)
+	begin
+
+		`SLAVE_ASSUME property (@(posedge i_clk)
+			(!i_axi_awvalid || !i_axi_awlock));
+
+	end endgenerate
+	// }}}
+
+	// Build f_axi_wr_this_*
+	// {{{
+	always @(*)
+	if (r_wr_pending == 0)
+	begin
+		f_axi_wr_this_id    = awfifo_id;
+		f_axi_wr_this_addr  = awfifo_addr;
+		f_axi_wr_this_len   = awfifo_len;
+		f_axi_wr_this_burst = awfifo_burst;
+		f_axi_wr_this_size  = awfifo_size;
+		f_axi_wr_this_lock  = awfifo_lock;
+		f_axi_wr_this_cache = awfifo_cache;
+		f_axi_wr_this_prot  = awfifo_prot;
+		f_axi_wr_this_qos   = awfifo_qos;
+	end else begin
+		f_axi_wr_this_id    = r_axi_wr_id;
+		f_axi_wr_this_addr  = r_axi_wr_addr;
+		f_axi_wr_this_len   = r_axi_wr_len;
+		f_axi_wr_this_burst = r_axi_wr_burst;
+		f_axi_wr_this_size  = r_axi_wr_size;
+		f_axi_wr_this_lock  = r_axi_wr_lock;
+		f_axi_wr_this_cache = r_axi_wr_cache;
+		f_axi_wr_this_prot  = r_axi_wr_prot;
+		f_axi_wr_this_qos   = r_axi_wr_qos;
+	end
+	// }}}
+
+	// r_axi_wr_*
+	// {{{
+	initial	r_wr_pending = 0;
+	always @(posedge i_clk)
+	begin
+		if (awfifo_read && !awfifo_empty)
+		begin
+			r_axi_wr_id   <= awfifo_id;
+			r_axi_wr_addr <= awfifo_addr;
+			r_axi_wr_len  <= awfifo_len;
+			r_axi_wr_burst<= awfifo_burst;
+			r_axi_wr_size <= awfifo_size;
+			r_axi_wr_lock <= awfifo_lock;
+			r_axi_wr_cache<= awfifo_cache;
+			r_axi_wr_prot <= awfifo_prot;
+			r_axi_wr_qos  <= awfifo_qos;
+
+			r_wr_pending <= awfifo_len + 1;
+			if (wfifo_read && !wfifo_empty)
+			begin
+				r_axi_wr_addr <= next_write_addr;
+				r_wr_pending  <= awfifo_len;
+			end
+		end else if (wfifo_read && !wfifo_empty)
+		begin
+			r_axi_wr_addr <= next_write_addr;
+			r_wr_pending  <= r_wr_pending - 1;
+		end
+
+		if (!i_axi_aresetn)
+			r_wr_pending <= 0;
+	end
+	// }}}
+
+	// f_axi_wr_pending
+	// {{{	
+	always @(*)
+	if (r_wr_pending == 0)
+	begin
+		f_axi_wr_pending = awfifo_len + 1;
+		if (awfifo_empty || !awfifo_read)
+			f_axi_wr_pending = 0;
+	end else
+		f_axi_wr_pending = r_wr_pending;
+	// }}}
+
+	// next_write_addr
+	// {{{
+	faxi_addr #(.AW(AW))
+	get_next_write_addr(
+		f_axi_wr_this_addr, f_axi_wr_this_size, f_axi_wr_this_burst,
+		f_axi_wr_this_len,
+		f_axi_wr_this_incr, next_write_addr);
+	// }}}
+
+	// Check WSTRB
+	// {{{
+	faxi_wstrb #(.C_AXI_DATA_WIDTH(DW))
+		f_wstrbck (f_axi_wr_this_addr, f_axi_wr_this_size,
+				wfifo_strb, wstb_valid);
+
+	// Insist the only the appropriate bits be valid
+	// For example, if the lower address bit is one, then the
+	// strobe LSB cannot be 1, but must be zero.  This is just
+	// enforcing the rules of the sub-address which must match
+	// the write strobe.  An STRB of 0 is always allowed.
+	//
+	always @(*)
+	if (!wfifo_empty)
+		`SLAVE_ASSUME(wstb_valid);
+	// }}}
+
+	// Check WLAST
+	`SLAVE_ASSUME property (@(posedge i_clk)
+		!wfifo_empty && r_wr_pending > 0
+		|-> ((r_wr_pending == 1) == wfifo_last));
+
+	`SLAVE_ASSUME property (@(posedge i_clk)
+		!wfifo_empty && r_wr_pending == 0 && !awfifo_empty
+		|-> ((awfifo_len == 0) == wfifo_last));
+
+	// Check BID and BRESP
+	// {{{
+	generate for(gk=0; gk<NUM_IDS; gk=gk+1)
+	begin : CHECK_BID
+		// {{{
+
+		// Register/net declarations
+		// {{{
+		wire	[F_LGDEPTH:0]	bid_count;
+		reg			block_fifo_write, block_fifo_check,
+					block_fifo_read;
+		wire			block_possible;
+		wire			block_fifo_empty;
+		// }}}
+
+		always @(*)
+			block_fifo_write = (wfifo_read && !wfifo_empty
+				&& wfifo_last && f_axi_wr_this_id == gk);
+
+		always @(*)
+			block_fifo_check = (i_axi_bvalid && i_axi_bid == gk);
+
+		always @(*)
+			block_fifo_read = block_fifo_check && i_axi_bready;
+
+		if (OPT_EXCLUSIVE)
+		begin : EXCLUSIVE_WRITE_RETURN_CHECK
+			// {{{
+			wire		block_fifo_full;
+
+			sfifo #(
+				// {{{
+				.BW(1),
+				.LGFLEN(F_LGDEPTH),
+				.OPT_ASYNC_READ(1'b0),
+				.OPT_WRITE_ON_FULL(1'b1),
+				.OPT_READ_ON_EMPTY(1'b0)
+				// }}}
+			) block_fifo (
+				// {{{
+				.i_clk(i_clk), .i_reset(!i_axi_aresetn),
+				.i_wr(block_fifo_write),
+				.i_data(f_axi_wr_this_lock),
+				.o_full(block_fifo_full), .o_fill(bid_count),
+				.i_rd(block_fifo_read),
+				.o_data(block_possible),
+				.o_empty(block_fifo_empty)
+				// }}}
+			);
+
+			`SLAVE_ASSERT property (@(posedge i_clk)
+				!block_possible
+				|-> !block_fifo_check || i_axi_bresp != EXOKAY);
+			// }}}
+		end else begin : NO_EXCLUSIVE_WRITE_RETURNS
+			// {{{
+			reg	[F_LGDEPTH-1:0]	r_bid_count;
+
+			initial	r_bid_count = 0;
+			always @(posedge i_clk)
+			if (!i_axi_aresetn)
+				r_bid_count = 0;
+			else case ({ block_fifo_write, block_fifo_read })
+			2'b10: r_bid_count <= r_bid_count + 1;
+			2'b01: r_bid_count <= r_bid_count - 1;
+			default: begin end
+			endcase
+
+			assign	block_fifo_empty = (r_bid_count == 0);
+
+			`SLAVE_ASSERT property (@(posedge i_clk)
+				!block_fifo_check || i_axi_bresp != EXOKAY);
+			// }}}
+		end
+
+		`SLAVE_ASSUME property (@(posedge i_clk)
+			block_fifo_write && !block_fifo_read
+			|-> (bid_count != {(F_LGDEPTH){1'b1}}));
+
+		`SLAVE_ASSERT property (@(posedge i_clk)
+			block_fifo_check |-> !block_fifo_empty);
+
+		// }}}
+	end endgenerate
+	// }}}
+	
+	// f_axi_awr_nbursts
+	// {{{
+	// Count the number of outstanding BVALID's to expect
+	initial	f_axi_awr_nbursts = 0;
+	always @(posedge i_clk)
+	if (!i_axi_aresetn)
+		f_axi_awr_nbursts <= 0;
+	else case({ (axi_awr_req), (axi_wr_ack) })
+	2'b10: f_axi_awr_nbursts <= f_axi_awr_nbursts + 1'b1;
+	2'b01: f_axi_awr_nbursts <= f_axi_awr_nbursts - 1'b1;
+	default: begin end
+	endcase
+	// }}}
+
+	// f_axi_rd_nbursts
+	// {{{
+	// Count the number of reads bursts outstanding.  This defines the
+	// number of RDVALID && RLAST's we expect to see before becoming idle
+	//
+	initial	f_axi_rd_nbursts = 0;
+	always @(posedge i_clk)
+	if (!i_axi_aresetn)
+		f_axi_rd_nbursts <= 0;
+	else case({ (axi_ard_req), (axi_rd_ack)&&(i_axi_rlast) })
+	2'b01: f_axi_rd_nbursts <= f_axi_rd_nbursts - 1'b1;
+	2'b10: f_axi_rd_nbursts <= f_axi_rd_nbursts + 1'b1;
+	endcase
+	// }}}
+
+	// f_axi_rd_outstanding
+	// {{{
+	// f_axi_rd_outstanding counts the number of RDVALID's we expect to
+	// see before becoming idle.  This must always be greater than or
+	// equal to the number of RVALID & RLAST's counted above
+	//
+	initial	f_axi_rd_outstanding = 0;
+	always @(posedge i_clk)
+	if (!i_axi_aresetn)
+		f_axi_rd_outstanding <= 0;
+	else case({ (axi_ard_req), (axi_rd_ack) })
+	2'b01: f_axi_rd_outstanding <= f_axi_rd_outstanding - 1'b1;
+	2'b10: f_axi_rd_outstanding <= f_axi_rd_outstanding + i_axi_arlen+1;
+	2'b11: f_axi_rd_outstanding <= f_axi_rd_outstanding + i_axi_arlen;
+	endcase
+	// }}}
+
+	//
+	// Do not let the number of outstanding requests overflow.
+	// {{{
+	// This is a responsibility of both the master and the slave to never
+	// allow 2^F_LGDEPTH-1 requests (or more) to be outstanding.
+	//
+	assert property (@(posedge i_clk)
+		!i_axi_aresetn || f_axi_awr_nbursts  < {(F_LGDEPTH){1'b1}});
+	assert property (@(posedge i_clk)
+		!i_axi_aresetn || f_axi_wr_pending  <= 256);
+	assert property (@(posedge i_clk)
+		!i_axi_aresetn || f_axi_rd_nbursts  < {(F_LGDEPTH){1'b1}});
+	assert property (@(posedge i_clk)
+		!i_axi_aresetn || f_axi_rd_outstanding  < {(F_LGDEPTH){1'b1}});
+	// }}}
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read property checking
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	generate if (!OPT_EXCLUSIVE)
+	begin : NO_EXCLUSIVE_READS
+
+		`SLAVE_ASSUME property (@(posedge i_clk)
+			(!i_axi_arvalid || !i_axi_arlock));
+
+		`SLAVE_ASSERT property (@(posedge i_clk)
+			(!i_axi_rvalid || i_axi_rresp != EXOKAY));
+
+	end endgenerate
+
+	// Validate the read address packet
+	// {{{
+	faxi_valaddr #(.C_AXI_DATA_WIDTH(DW), .C_AXI_ADDR_WIDTH(AW),
+			.OPT_MAXBURST(OPT_MAXBURST),
+			.OPT_EXCLUSIVE(OPT_EXCLUSIVE),
+			.OPT_NARROW_BURST(1'b1))
+		f_rdaddr_validate(i_axi_araddr, i_axi_arlen,
+			i_axi_arsize, i_axi_arburst, i_axi_arlock,
+			1'b1, ard_aligned, valid_iraddr);
+
+	`SLAVE_ASSUME property (@(posedge i_clk)
+		i_axi_arvalid |-> valid_iraddr);
+	// }}}
+
+	// Read return handling must be done on a per-ID basis
+	generate for(gk=0; gk<NUM_IDS; gk=gk+1)
+	begin : PER_READ_ID_PROCESSING
+		// {{{
+
+		// Register/wire declarations
+		// {{{
+		wire			arfifo_empty, arfifo_full;
+		wire	[F_LGDEPTH:0]	arfifo_fill;
+		reg			arfifo_write, arfifo_read;
+
+		wire	[C_AXI_ADDR_WIDTH-1:0]	arfifo_addr;
+		wire	[7:0]			arfifo_len;
+		wire	[1:0]			arfifo_burst;
+		wire	[2:0]			arfifo_size;
+		wire				arfifo_lock;
+		wire	[3:0]			arfifo_cache;
+		wire	[2:0]			arfifo_prot;
+		wire	[3:0]			arfifo_qos;
+
+		reg	[C_AXI_ADDR_WIDTH-1:0]	f_axi_rd_this_addr;
+		reg	[7:0]			f_axi_rd_this_len;
+		reg	[1:0]			f_axi_rd_this_burst;
+		reg	[2:0]			f_axi_rd_this_size;
+		reg				f_axi_rd_this_lock;
+		reg	[3:0]			f_axi_rd_this_cache;
+		reg	[2:0]			f_axi_rd_this_prot;
+		reg	[3:0]			f_axi_rd_this_qos;
+
+		reg	[C_AXI_ID_WIDTH-1:0]	r_axi_rd_id;
+		reg	[C_AXI_ADDR_WIDTH-1:0]	r_axi_rd_addr;
+		reg	[7:0]			r_axi_rd_len;
+		reg	[1:0]			r_axi_rd_burst;
+		reg	[2:0]			r_axi_rd_size;
+		reg				r_axi_rd_lock;
+		reg	[3:0]			r_axi_rd_cache;
+		reg	[2:0]			r_axi_rd_prot;
+		reg	[3:0]			r_axi_rd_qos;
+		wire	[C_AXI_ADDR_WIDTH-1:0]	next_read_addr;
+		wire	[7:0]			f_axi_rd_this_incr;
+		reg	[8:0]			r_rd_pending;
+		// }}}
+
+		// Read address FIFO
+		// {{{
+		// Record any read address request for comparing against the
+		// subsequent response
+
+		// arfifo_write - Write on any address request
+		// {{{
+		always @(*)
+			arfifo_write = i_axi_arvalid && i_axi_arready
+				&& i_axi_arid == gk;
+		// }}}
+
+		// arfifo_read
+		// {{{
+		// Read if nothing we know of is pending, or if we just
+		// read the last value from the last burst.
+		always @(*)
+			arfifo_read = (r_rd_pending == 0)
+			|| (i_axi_rvalid && i_axi_rready && i_axi_rlast
+				&& i_axi_rid == gk);
+		// }}}
+
+		sfifo #(
+			// {{{
+			.BW(C_AXI_ADDR_WIDTH+8+2+3+1+4+3+4),
+			.LGFLEN(F_LGDEPTH),
+			.OPT_ASYNC_READ(1'b0),
+			.OPT_WRITE_ON_FULL(1'b1),
+			.OPT_READ_ON_EMPTY(1'b1)
+			// }}}
+		) arrequests (
+			// {{{
+			.i_clk(i_clk), .i_reset(!i_axi_aresetn),
+			.i_wr(arfifo_write),
+			.i_data({ i_axi_araddr, i_axi_arlen,
+				i_axi_arburst, i_axi_arsize, i_axi_arlock,
+				i_axi_arcache, i_axi_arprot, i_axi_arqos }),
+			.o_full(arfifo_full), .o_fill(arfifo_fill),
+			.i_rd(arfifo_read),
+			.o_data({ arfifo_addr, arfifo_len,
+				arfifo_burst, arfifo_size, arfifo_lock,
+				arfifo_cache, arfifo_prot, arfifo_qos }),
+			.o_empty(arfifo_empty)
+			// }}}
+		);
+		// }}}
+
+		// f_axi_rd_this_*
+		// {{{
+		// These record the current burst that is being returned by
+		// this ID (if any).  The current burst might still be in the
+		// FIFO, so this is combinatorial.
+		always @(*)
+		if (r_rd_pending == 0)
+		begin
+			f_axi_rd_this_addr  = arfifo_addr;
+			f_axi_rd_this_len   = arfifo_len;
+			f_axi_rd_this_burst = arfifo_burst;
+			f_axi_rd_this_size  = arfifo_size;
+			f_axi_rd_this_lock  = arfifo_lock;
+			f_axi_rd_this_cache = arfifo_cache;
+			f_axi_rd_this_prot  = arfifo_prot;
+			f_axi_rd_this_qos   = arfifo_qos;
+		end else begin
+			f_axi_rd_this_addr  = r_axi_rd_addr;
+			f_axi_rd_this_len   = r_axi_rd_len;
+			f_axi_rd_this_burst = r_axi_rd_burst;
+			f_axi_rd_this_size  = r_axi_rd_size;
+			f_axi_rd_this_lock  = r_axi_rd_lock;
+			f_axi_rd_this_cache = r_axi_rd_cache;
+			f_axi_rd_this_prot  = r_axi_rd_prot;
+			f_axi_rd_this_qos   = r_axi_rd_qos;
+		end
+		// }}}
+
+		// r_axi_rd_*
+		// {{{
+		// Register the details of the next read burst to be returned.
+		// We'll adjust the pending value and the address along the
+		// way.  Hence, the address should always point to the address
+		// of the next value to be read, and the r_rd_pending to the
+		// next item to be read.
+
+		initial	r_rd_pending = 0;
+		always @(posedge i_clk)
+		if (!i_axi_aresetn)
+			r_rd_pending <= 0;
+		else if (arfifo_read)
+		begin
+			r_rd_pending   = arfifo_len + 1;
+			if (arfifo_empty)
+				r_rd_pending = 0;
+		end else if (i_axi_rvalid && i_axi_rready && i_axi_rid == gk
+				&& r_rd_pending > 0)
+			r_rd_pending = r_rd_pending - 1;
+
+		always @(posedge i_clk)
+		if (arfifo_read)
+		begin
+			r_axi_rd_addr  = arfifo_addr;
+			r_axi_rd_len   = arfifo_len;
+			r_axi_rd_burst = arfifo_burst;
+			r_axi_rd_size  = arfifo_size;
+			r_axi_rd_lock  = arfifo_lock;
+			r_axi_rd_cache = arfifo_cache;
+			r_axi_rd_prot  = arfifo_prot;
+			r_axi_rd_qos   = arfifo_qos;
+		end else if (i_axi_rvalid && i_axi_rready && i_axi_rid == gk
+				&& r_rd_pending > 0)
+			r_axi_rd_addr= next_read_addr;
+		// }}}
+
+		// next_read_addr
+		// {{{
+		// Compute the next read address, after the current one, using
+		// the current burst values.
+		faxi_addr #(.AW(AW))
+		get_next_read_addr(
+			f_axi_rd_this_addr, f_axi_rd_this_size,
+			f_axi_rd_this_burst, f_axi_rd_this_len,
+			f_axi_rd_this_incr, next_read_addr);
+		// }}}
+
+		`SLAVE_ASSERT property (@(posedge i_clk)
+			i_axi_aresetn && i_axi_rvalid && i_axi_rid == gk
+			|-> (r_rd_pending > 0));
+
+		`SLAVE_ASSERT property (@(posedge i_clk)
+			i_axi_aresetn && i_axi_rvalid && i_axi_rid == gk
+			|-> (i_axi_rlast == (r_rd_pending == 1)));
+
+		`SLAVE_ASSERT property (@(posedge i_clk)
+			i_axi_aresetn && i_axi_rvalid && i_axi_rid == gk
+			&& !f_axi_rd_this_lock |-> i_axi_rresp != EXOKAY);
+
+		// }}}
+	end endgenerate
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Maximum response time delay
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Insist that all responses are returned in less than a maximum delay
+	//
+	// A unique feature to the backpressure mechanism within AXI is that
+	// we have to reset our delay count in the case of any push back, since
+	// the response can't move forward if the master isn't (yet) ready for
+	// it.
+	//
+
+	generate if (F_AXI_MAXDELAY > 0)
+	begin : CHECK_MAX_DELAY
+		// {{{
+		`SLAVE_ASSERT property (@(posedge i_clk)
+			i_axi_aresetn && !i_axi_bvalid
+			&& f_axi_awr_nbursts > awrfifo_fill
+					+ ((f_axi_wr_pending>0) ? 1:0)
+			[*F_AXI_MAXDELAY-1]
+			##1 (!OPT_ASYNC_RESET || i_axi_aresetn)
+			|-> i_axi_bvalid);
+
+		`SLAVE_ASSERT property (@(posedge i_clk)
+			i_axi_aresetn && !i_axi_rvalid
+			&& (f_axi_rd_outstanding > 0) [*F_AXI_MAXDELAY-1]
+			##1 (!OPT_ASYNC_RESET || i_axi_aresetn)
+			|-> i_axi_rvalid);
+		// }}}
+	end endgenerate
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Exclusive properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	generate if (!OPT_EXCLUSIVE)
+	begin : EXCLUSIVE_DISALLOWED
+		// {{{
+		// These properties are captured above
+		// }}}
+	end else begin : EXCLUSIVE_ACCESS_CHECKER
+		// {{{
+
+		//
+		// 1. Exclusive access burst lengths max out at 16
+		//	(Checked within valaddr)
+		// 2. Exclusive access bursts must be aligned
+		//	(NOT CHECKED)
+		// 3. Write must take place when the read channel is idle (on
+		//	this ID) -- (NOT CHECKED)
+		// (4. Further read accesses on this ID are not allowed)
+		//	(NOT CHECKED)
+		//
+		`SLAVE_ASSUME property (@(posedge i_clk)
+			i_axi_aresetn && i_axi_awvalid && i_axi_awlock
+			|-> !i_axi_awcache[0]);
+
+		`SLAVE_ASSUME property (@(posedge i_clk)
+			i_axi_aresetn && i_axi_arvalid && i_axi_arlock
+			|-> !i_axi_arcache[0]);
+
+		// }}}
+	end endgenerate
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AxCACHE properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Table A4-5 ??
+	//
+
+	`SLAVE_ASSUME property (@(posedge i_clk)
+		i_axi_awvalid && !i_axi_awcache[1]
+		|-> i_axi_awcache[3:2] == 2'b00);
+
+	`SLAVE_ASSUME property (@(posedge i_clk)
+		i_axi_arvalid && !i_axi_arcache[1]
+		|-> i_axi_arcache[3:2] == 2'b00);
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Option for no bursts, only single transactions
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate if (!F_OPT_BURSTS)
+	begin
+
+		`SLAVE_ASSUME property(@(posedge i_clk)
+			i_axi_awvalid |-> i_axi_awlen == 0);
+
+		`SLAVE_ASSUME property(@(posedge i_clk)
+			i_axi_wvalid |-> i_axi_wlast);
+
+		`SLAVE_ASSUME property(@(posedge i_clk)
+			i_axi_arvalid |-> i_axi_arlen == 0);
+
+		`SLAVE_ASSERT property(@(posedge i_clk)
+			i_axi_rvalid |-> i_axi_rlast);
+
+	end endgenerate
+	// }}}
+`undef	SLAVE_ASSUME
+`undef	SLAVE_ASSERT
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/.gitignore b/verilog/rtl/softshell/third_party/wb2axip/doc/.gitignore
new file mode 100644
index 0000000..66aa986
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/.gitignore
@@ -0,0 +1,8 @@
+*.aux
+*.dvi
+*.bm
+*.log
+*.toc
+orconf2019.ps
+nup.ps
+*.vrb
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/Makefile b/verilog/rtl/softshell/third_party/wb2axip/doc/Makefile
new file mode 100644
index 0000000..5db9479
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/Makefile
@@ -0,0 +1,74 @@
+################################################################################
+##
+## Filename: 	Makefile
+##
+## Project:	Pipelined Wishbone to AXI converter
+##
+## Purpose:	To coordinate the build of documentation PDFs from their
+##		LaTeX sources.
+##
+##	Targets include:
+##		all		Builds all documents
+##
+##		spec.pdf	Builds the specification for the SDSPI
+##					controller.
+##
+## Creator:	Dan Gisselquist, Ph.D.
+##		Gisselquist Technology, LLC
+##
+################################################################################
+##
+## Copyright (C) 2015-2020 Gisselquist Technology, LLC
+##
+## This file is part of the pipelined Wishbone to AXI converter project, a
+## project that contains multiple bus bridging designs and formal bus property
+## sets.
+##
+## The bus bridge designs and property sets are free RTL designs: you can
+## redistribute them and/or modify any of them under the terms of the GNU
+## Lesser General Public License as published by the Free Software Foundation,
+## either version 3 of the License, or (at your option) any later version.
+##
+## The bus bridge designs and property sets are distributed in the hope that
+## they will be useful, but WITHOUT ANY WARRANTY; without even the implied
+## warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with these designs.  (It's in the $(ROOT)/doc directory.  Run make
+## with no target there if the PDF file isn't present.)  If not, see
+## <http://www.gnu.org/licenses/> for a copy.
+##
+## License:	LGPL, v3, as defined and found on www.gnu.org,
+##		http://www.gnu.org/licenses/lgpl.html
+##
+################################################################################
+##
+##
+all:
+	echo "See the comments internal to the various RTL files for any documentation"
+
+pdf:	spec
+DSRC := src
+
+.PHONY: spec
+spec: spec.pdf
+
+spec.pdf: $(DSRC)/spec.tex $(DSRC)/gqtekspec.cls $(DSRC)/GT.eps
+	cd $(DSRC)/; latex spec.tex
+	cd $(DSRC)/; latex spec.tex
+	cd $(DSRC)/; dvips -q -z -t letter -P pdf -o ../spec.ps spec.dvi
+	ps2pdf -dAutoRotatePages=/All spec.ps spec.pdf
+	-grep -i warning $(DSRC)/spec.log
+	@rm -f $(DSRC)/spec.dvi $(DSRC)/spec.log
+	@rm -f $(DSRC)/spec.aux $(DSRC)/spec.toc
+	@rm -f $(DSRC)/spec.lot $(DSRC)/spec.lof
+	@rm -f $(DSRC)/spec.out spec.ps
+
+.PHONY: clean
+clean:
+	rm -f $(DSRC)/spec.dvi $(DSRC)/spec.log
+	rm -f $(DSRC)/spec.aux $(DSRC)/spec.toc
+	rm -f $(DSRC)/spec.lot $(DSRC)/spec.lof
+	rm -f $(DSRC)/spec.out spec.ps spec.pdf
+	rm -f $(LICENSE).pdf
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axi-multiwrite.dia b/verilog/rtl/softshell/third_party/wb2axip/doc/axi-multiwrite.dia
new file mode 100644
index 0000000..cb6a6a6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axi-multiwrite.dia
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axi-multiwrite.png b/verilog/rtl/softshell/third_party/wb2axip/doc/axi-multiwrite.png
new file mode 100644
index 0000000..f2b3b0e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axi-multiwrite.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_mb.json b/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_mb.json
new file mode 100644
index 0000000..f33e226
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_mb.json
@@ -0,0 +1,19 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'P..............'},
+  {},
+  {name: 'cmd_start',     wave: '010............'},
+  {name: 'cmd_length',    wave: '2..............', data: ['9']},
+  {name: 'cmd_threshold', wave: '2..............', data: ['4']},
+  {name: 'fifo_fill',     wave: '2.34......5....', data: ['2','3','4','3']},
+  {name: 'r_busy',        wave: '0.1...........0'},
+  {name: 'done_interrupt',wave: '0.............1'},
+  {},
+  {name: 'M_AXI_AWVALID', wave: '0...10..10.10..'},
+  {name: 'M_AXI_AWLEN',   wave: 'x...2x..2x.2xx.', data: ['3','2','1']},
+    {},
+  {name: 'S_AXI_WVALID',  wave: '0...1........0.'},
+  {name: 'S_AXI_WDATA',   wave: 'x...234523452x.'},
+  {name: 'S_AXI_WLAST',   wave: 'x...0..10.101x.'},
+  {},
+  {name: 'S_AXI_BVALID',  wave: '0.........101.0'}
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_mb.png b/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_mb.png
new file mode 100644
index 0000000..32a0ae7
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_mb.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_mb.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_mb.svg
new file mode 100644
index 0000000..9fb83ec
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_mb.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="510" width="760" viewBox="0 0 760 510" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(140.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_1_0" d="m 40,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_2_0" d="m 80,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_3_0" d="m 120,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_4_0" d="m 160,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_5_0" d="m 200,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_6_0" d="m 240,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_7_0" d="m 280,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_8_0" d="m 320,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_9_0" d="m 360,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_10_0" d="m 400,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_11_0" d="m 440,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_12_0" d="m 480,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_13_0" d="m 520,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_14_0" d="m 560,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_15_0" d="m 600,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#Pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#Pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#Pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#Pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#Pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/><use xlink:href="#Pclk" transform="translate(200)"/><use xlink:href="#nclk" transform="translate(220)"/><use xlink:href="#Pclk" transform="translate(240)"/><use xlink:href="#nclk" transform="translate(260)"/><use xlink:href="#Pclk" transform="translate(280)"/><use xlink:href="#nclk" transform="translate(300)"/><use xlink:href="#Pclk" transform="translate(320)"/><use xlink:href="#nclk" transform="translate(340)"/><use xlink:href="#Pclk" transform="translate(360)"/><use xlink:href="#nclk" transform="translate(380)"/><use xlink:href="#Pclk" transform="translate(400)"/><use xlink:href="#nclk" transform="translate(420)"/><use xlink:href="#Pclk" transform="translate(440)"/><use xlink:href="#nclk" transform="translate(460)"/><use xlink:href="#Pclk" transform="translate(480)"/><use xlink:href="#nclk" transform="translate(500)"/><use xlink:href="#Pclk" transform="translate(520)"/><use xlink:href="#nclk" transform="translate(540)"/><use xlink:href="#Pclk" transform="translate(560)"/><use xlink:href="#nclk" transform="translate(580)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"/></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>cmd_start</tspan></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#1m0" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/></g></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>cmd_length</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#vvv-2" transform="translate(0)"/><use xlink:href="#vvv-2" transform="translate(20)"/><use xlink:href="#vvv-2" transform="translate(40)"/><use xlink:href="#vvv-2" transform="translate(60)"/><use xlink:href="#vvv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vvv-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vvv-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vvv-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vvv-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vvv-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vvv-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vvv-2" transform="translate(360)"/><use xlink:href="#vvv-2" transform="translate(380)"/><use xlink:href="#vvv-2" transform="translate(400)"/><use xlink:href="#vvv-2" transform="translate(420)"/><use xlink:href="#vvv-2" transform="translate(440)"/><use xlink:href="#vvv-2" transform="translate(460)"/><use xlink:href="#vvv-2" transform="translate(480)"/><use xlink:href="#vvv-2" transform="translate(500)"/><use xlink:href="#vvv-2" transform="translate(520)"/><use xlink:href="#vvv-2" transform="translate(540)"/><use xlink:href="#vvv-2" transform="translate(560)"/><use xlink:href="#vvv-2" transform="translate(580)"/><text x="296" y="15" text-anchor="middle" xml:space="preserve"><tspan>9</tspan></text></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>cmd_threshold</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#vvv-2" transform="translate(0)"/><use xlink:href="#vvv-2" transform="translate(20)"/><use xlink:href="#vvv-2" transform="translate(40)"/><use xlink:href="#vvv-2" transform="translate(60)"/><use xlink:href="#vvv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vvv-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vvv-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vvv-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vvv-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vvv-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vvv-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vvv-2" transform="translate(360)"/><use xlink:href="#vvv-2" transform="translate(380)"/><use xlink:href="#vvv-2" transform="translate(400)"/><use xlink:href="#vvv-2" transform="translate(420)"/><use xlink:href="#vvv-2" transform="translate(440)"/><use xlink:href="#vvv-2" transform="translate(460)"/><use xlink:href="#vvv-2" transform="translate(480)"/><use xlink:href="#vvv-2" transform="translate(500)"/><use xlink:href="#vvv-2" transform="translate(520)"/><use xlink:href="#vvv-2" transform="translate(540)"/><use xlink:href="#vvv-2" transform="translate(560)"/><use xlink:href="#vvv-2" transform="translate(580)"/><text x="296" y="15" text-anchor="middle" xml:space="preserve"><tspan>4</tspan></text></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>fifo_fill</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#vvv-2" transform="translate(0)"/><use xlink:href="#vvv-2" transform="translate(20)"/><use xlink:href="#vvv-2" transform="translate(40)"/><use xlink:href="#vvv-2" transform="translate(60)"/><use xlink:href="#vmv-2-3" transform="translate(80)"/><use xlink:href="#vvv-3" transform="translate(100)"/><use xlink:href="#vmv-3-4" transform="translate(120)"/><use xlink:href="#vvv-4" transform="translate(140)"/><use xlink:href="#vvv-4" transform="translate(160)"/><use xlink:href="#vvv-4" transform="translate(180)"/><use xlink:href="#vvv-4" transform="translate(200)"/><use xlink:href="#vvv-4" transform="translate(220)"/><use xlink:href="#vvv-4" transform="translate(240)"/><use xlink:href="#vvv-4" transform="translate(260)"/><use xlink:href="#vvv-4" transform="translate(280)"/><use xlink:href="#vvv-4" transform="translate(300)"/><use xlink:href="#vvv-4" transform="translate(320)"/><use xlink:href="#vvv-4" transform="translate(340)"/><use xlink:href="#vvv-4" transform="translate(360)"/><use xlink:href="#vvv-4" transform="translate(380)"/><use xlink:href="#vmv-4-5" transform="translate(400)"/><use xlink:href="#vvv-5" transform="translate(420)"/><use xlink:href="#vvv-5" transform="translate(440)"/><use xlink:href="#vvv-5" transform="translate(460)"/><use xlink:href="#vvv-5" transform="translate(480)"/><use xlink:href="#vvv-5" transform="translate(500)"/><use xlink:href="#vvv-5" transform="translate(520)"/><use xlink:href="#vvv-5" transform="translate(540)"/><use xlink:href="#vvv-5" transform="translate(560)"/><use xlink:href="#vvv-5" transform="translate(580)"/><text x="36" y="15" text-anchor="middle" xml:space="preserve"><tspan>2</tspan></text><text x="106" y="15" text-anchor="middle" xml:space="preserve"><tspan>3</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>4</tspan></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan>3</tspan></text></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>r_busy</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#1m0" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>done_interrupt</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#0m1" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"/></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_AWVALID</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#0m1" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#1m0" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#0m1" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#1m0" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#0m1" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#1m0" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/></g></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_AWLEN</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xmv-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vmx-2" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xmv-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vmx-2" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xxx" transform="translate(400)"/><use xlink:href="#xxx" transform="translate(420)"/><use xlink:href="#xmv-2" transform="translate(440)"/><use xlink:href="#vvv-2" transform="translate(460)"/><use xlink:href="#vmx-2" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xmx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><text x="186" y="15" text-anchor="middle" xml:space="preserve"><tspan>3</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>2</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>1</tspan></text></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"/></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WVALID</tspan></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#0m1" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#1m0" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/></g></g><g id="wavelane_13_0" transform="translate(0,395)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WDATA</tspan></text><g id="wavelane_draw_13_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xmv-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vmv-2-3" transform="translate(200)"/><use xlink:href="#vvv-3" transform="translate(220)"/><use xlink:href="#vmv-3-4" transform="translate(240)"/><use xlink:href="#vvv-4" transform="translate(260)"/><use xlink:href="#vmv-4-5" transform="translate(280)"/><use xlink:href="#vvv-5" transform="translate(300)"/><use xlink:href="#vmv-5-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vmv-2-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vmv-3-4" transform="translate(400)"/><use xlink:href="#vvv-4" transform="translate(420)"/><use xlink:href="#vmv-4-5" transform="translate(440)"/><use xlink:href="#vvv-5" transform="translate(460)"/><use xlink:href="#vmv-5-2" transform="translate(480)"/><use xlink:href="#vvv-2" transform="translate(500)"/><use xlink:href="#vmx-2" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/></g></g><g id="wavelane_14_0" transform="translate(0,425)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WLAST</tspan></text><g id="wavelane_draw_14_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xm0" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#0m1" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#1m0" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#0m1" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#1m0" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#0m1" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#1mx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/></g></g><g id="wavelane_15_0" transform="translate(0,455)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_15_0" transform="translate(0, 0)"/></g><g id="wavelane_16_0" transform="translate(0,485)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_BVALID</tspan></text><g id="wavelane_draw_16_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#0m1" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#1m0" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#0m1" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#1m0" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/><g id="wavegap_13_0" transform="translate(0,395)"/><g id="wavegap_14_0" transform="translate(0,425)"/><g id="wavegap_15_0" transform="translate(0,455)"/><g id="wavegap_16_0" transform="translate(0,485)"/></g></g><g id="groups_0">g</g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_sb.json b/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_sb.json
new file mode 100644
index 0000000..0f71083
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_sb.json
@@ -0,0 +1,19 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'P..................'},
+  {},
+  {name: 'cmd_start',     wave: '010................'},
+  {name: 'cmd_length',    wave: '2..................', data: ['9']},
+  {name: 'cmd_threshold', wave: '2..................', data: ['9']},
+  {name: 'fifo_fill',     wave: '2.22222..34523452x.', data: ['4','5','6','7','8','9','8','7','6','5','4','3','2','1','0']},
+  {name: 'r_busy',        wave: '0.1...............0'},
+  {name: 'done_interrupt',wave: '0.................1'},
+  {},
+  {name: 'M_AXI_AWVALID', wave: '0.......10.........'},
+  {name: 'M_AXI_AWLEN',   wave: 'x.......2x.........', data: ['8','1']},
+    {},
+  {name: 'S_AXI_WVALID',  wave: '0.......1........0.'},
+  {name: 'S_AXI_WDATA',   wave: 'x.......234523452x.'},
+  {name: 'S_AXI_WLAST',   wave: 'x.......0.......1x.'},
+  {},
+  {name: 'S_AXI_BVALID',  wave: '0................10'}
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_sb.png b/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_sb.png
new file mode 100644
index 0000000..b1fdc77
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_sb.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_sb.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_sb.svg
new file mode 100644
index 0000000..048a698
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axis2mm_sb.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="510" width="920" viewBox="0 0 920 510" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(140.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_1_0" d="m 40,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_2_0" d="m 80,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_3_0" d="m 120,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_4_0" d="m 160,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_5_0" d="m 200,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_6_0" d="m 240,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_7_0" d="m 280,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_8_0" d="m 320,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_9_0" d="m 360,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_10_0" d="m 400,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_11_0" d="m 440,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_12_0" d="m 480,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_13_0" d="m 520,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_14_0" d="m 560,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_15_0" d="m 600,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_16_0" d="m 640,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_17_0" d="m 680,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_18_0" d="m 720,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_19_0" d="m 760,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#Pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#Pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#Pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#Pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#Pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/><use xlink:href="#Pclk" transform="translate(200)"/><use xlink:href="#nclk" transform="translate(220)"/><use xlink:href="#Pclk" transform="translate(240)"/><use xlink:href="#nclk" transform="translate(260)"/><use xlink:href="#Pclk" transform="translate(280)"/><use xlink:href="#nclk" transform="translate(300)"/><use xlink:href="#Pclk" transform="translate(320)"/><use xlink:href="#nclk" transform="translate(340)"/><use xlink:href="#Pclk" transform="translate(360)"/><use xlink:href="#nclk" transform="translate(380)"/><use xlink:href="#Pclk" transform="translate(400)"/><use xlink:href="#nclk" transform="translate(420)"/><use xlink:href="#Pclk" transform="translate(440)"/><use xlink:href="#nclk" transform="translate(460)"/><use xlink:href="#Pclk" transform="translate(480)"/><use xlink:href="#nclk" transform="translate(500)"/><use xlink:href="#Pclk" transform="translate(520)"/><use xlink:href="#nclk" transform="translate(540)"/><use xlink:href="#Pclk" transform="translate(560)"/><use xlink:href="#nclk" transform="translate(580)"/><use xlink:href="#Pclk" transform="translate(600)"/><use xlink:href="#nclk" transform="translate(620)"/><use xlink:href="#Pclk" transform="translate(640)"/><use xlink:href="#nclk" transform="translate(660)"/><use xlink:href="#Pclk" transform="translate(680)"/><use xlink:href="#nclk" transform="translate(700)"/><use xlink:href="#Pclk" transform="translate(720)"/><use xlink:href="#nclk" transform="translate(740)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"/></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>cmd_start</tspan></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#1m0" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>cmd_length</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#vvv-2" transform="translate(0)"/><use xlink:href="#vvv-2" transform="translate(20)"/><use xlink:href="#vvv-2" transform="translate(40)"/><use xlink:href="#vvv-2" transform="translate(60)"/><use xlink:href="#vvv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vvv-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vvv-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vvv-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vvv-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vvv-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vvv-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vvv-2" transform="translate(360)"/><use xlink:href="#vvv-2" transform="translate(380)"/><use xlink:href="#vvv-2" transform="translate(400)"/><use xlink:href="#vvv-2" transform="translate(420)"/><use xlink:href="#vvv-2" transform="translate(440)"/><use xlink:href="#vvv-2" transform="translate(460)"/><use xlink:href="#vvv-2" transform="translate(480)"/><use xlink:href="#vvv-2" transform="translate(500)"/><use xlink:href="#vvv-2" transform="translate(520)"/><use xlink:href="#vvv-2" transform="translate(540)"/><use xlink:href="#vvv-2" transform="translate(560)"/><use xlink:href="#vvv-2" transform="translate(580)"/><use xlink:href="#vvv-2" transform="translate(600)"/><use xlink:href="#vvv-2" transform="translate(620)"/><use xlink:href="#vvv-2" transform="translate(640)"/><use xlink:href="#vvv-2" transform="translate(660)"/><use xlink:href="#vvv-2" transform="translate(680)"/><use xlink:href="#vvv-2" transform="translate(700)"/><use xlink:href="#vvv-2" transform="translate(720)"/><use xlink:href="#vvv-2" transform="translate(740)"/><text x="376" y="15" text-anchor="middle" xml:space="preserve"><tspan>9</tspan></text></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>cmd_threshold</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#vvv-2" transform="translate(0)"/><use xlink:href="#vvv-2" transform="translate(20)"/><use xlink:href="#vvv-2" transform="translate(40)"/><use xlink:href="#vvv-2" transform="translate(60)"/><use xlink:href="#vvv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vvv-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vvv-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vvv-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vvv-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vvv-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vvv-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vvv-2" transform="translate(360)"/><use xlink:href="#vvv-2" transform="translate(380)"/><use xlink:href="#vvv-2" transform="translate(400)"/><use xlink:href="#vvv-2" transform="translate(420)"/><use xlink:href="#vvv-2" transform="translate(440)"/><use xlink:href="#vvv-2" transform="translate(460)"/><use xlink:href="#vvv-2" transform="translate(480)"/><use xlink:href="#vvv-2" transform="translate(500)"/><use xlink:href="#vvv-2" transform="translate(520)"/><use xlink:href="#vvv-2" transform="translate(540)"/><use xlink:href="#vvv-2" transform="translate(560)"/><use xlink:href="#vvv-2" transform="translate(580)"/><use xlink:href="#vvv-2" transform="translate(600)"/><use xlink:href="#vvv-2" transform="translate(620)"/><use xlink:href="#vvv-2" transform="translate(640)"/><use xlink:href="#vvv-2" transform="translate(660)"/><use xlink:href="#vvv-2" transform="translate(680)"/><use xlink:href="#vvv-2" transform="translate(700)"/><use xlink:href="#vvv-2" transform="translate(720)"/><use xlink:href="#vvv-2" transform="translate(740)"/><text x="376" y="15" text-anchor="middle" xml:space="preserve"><tspan>9</tspan></text></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>fifo_fill</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#vvv-2" transform="translate(0)"/><use xlink:href="#vvv-2" transform="translate(20)"/><use xlink:href="#vvv-2" transform="translate(40)"/><use xlink:href="#vvv-2" transform="translate(60)"/><use xlink:href="#vmv-2-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vmv-2-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vmv-2-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vmv-2-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vmv-2-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vvv-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vvv-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vmv-2-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vmv-3-4" transform="translate(400)"/><use xlink:href="#vvv-4" transform="translate(420)"/><use xlink:href="#vmv-4-5" transform="translate(440)"/><use xlink:href="#vvv-5" transform="translate(460)"/><use xlink:href="#vmv-5-2" transform="translate(480)"/><use xlink:href="#vvv-2" transform="translate(500)"/><use xlink:href="#vmv-2-3" transform="translate(520)"/><use xlink:href="#vvv-3" transform="translate(540)"/><use xlink:href="#vmv-3-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmv-4-5" transform="translate(600)"/><use xlink:href="#vvv-5" transform="translate(620)"/><use xlink:href="#vmv-5-2" transform="translate(640)"/><use xlink:href="#vvv-2" transform="translate(660)"/><use xlink:href="#vmx-2" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><text x="36" y="15" text-anchor="middle" xml:space="preserve"><tspan>4</tspan></text><text x="106" y="15" text-anchor="middle" xml:space="preserve"><tspan>5</tspan></text><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>6</tspan></text><text x="186" y="15" text-anchor="middle" xml:space="preserve"><tspan>7</tspan></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>8</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>9</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>8</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>7</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>6</tspan></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan>5</tspan></text><text x="546" y="15" text-anchor="middle" xml:space="preserve"><tspan>4</tspan></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan>3</tspan></text><text x="626" y="15" text-anchor="middle" xml:space="preserve"><tspan>2</tspan></text><text x="666" y="15" text-anchor="middle" xml:space="preserve"><tspan>1</tspan></text></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>r_busy</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#1m0" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>done_interrupt</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#0m1" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"/></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_AWVALID</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#0m1" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#1m0" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_AWLEN</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xmv-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vmx-2" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xxx" transform="translate(400)"/><use xlink:href="#xxx" transform="translate(420)"/><use xlink:href="#xxx" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>8</tspan></text></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"/></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WVALID</tspan></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#0m1" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#1m0" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavelane_13_0" transform="translate(0,395)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WDATA</tspan></text><g id="wavelane_draw_13_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xmv-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vmv-2-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vmv-3-4" transform="translate(400)"/><use xlink:href="#vvv-4" transform="translate(420)"/><use xlink:href="#vmv-4-5" transform="translate(440)"/><use xlink:href="#vvv-5" transform="translate(460)"/><use xlink:href="#vmv-5-2" transform="translate(480)"/><use xlink:href="#vvv-2" transform="translate(500)"/><use xlink:href="#vmv-2-3" transform="translate(520)"/><use xlink:href="#vvv-3" transform="translate(540)"/><use xlink:href="#vmv-3-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmv-4-5" transform="translate(600)"/><use xlink:href="#vvv-5" transform="translate(620)"/><use xlink:href="#vmv-5-2" transform="translate(640)"/><use xlink:href="#vvv-2" transform="translate(660)"/><use xlink:href="#vmx-2" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/></g></g><g id="wavelane_14_0" transform="translate(0,425)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WLAST</tspan></text><g id="wavelane_draw_14_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xm0" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#0m1" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#1mx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/></g></g><g id="wavelane_15_0" transform="translate(0,455)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_15_0" transform="translate(0, 0)"/></g><g id="wavelane_16_0" transform="translate(0,485)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_BVALID</tspan></text><g id="wavelane_draw_16_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#0m1" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#1m0" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/><g id="wavegap_13_0" transform="translate(0,395)"/><g id="wavegap_14_0" transform="translate(0,425)"/><g id="wavegap_15_0" transform="translate(0,455)"/><g id="wavegap_16_0" transform="translate(0,485)"/></g></g><g id="groups_0">g</g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axisafety.dia b/verilog/rtl/softshell/third_party/wb2axip/doc/axisafety.dia
new file mode 100644
index 0000000..717af79
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axisafety.dia
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axisafety.png b/verilog/rtl/softshell/third_party/wb2axip/doc/axisafety.png
new file mode 100644
index 0000000..412803c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axisafety.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axisafety2.dia b/verilog/rtl/softshell/third_party/wb2axip/doc/axisafety2.dia
new file mode 100644
index 0000000..f797442
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axisafety2.dia
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axisafety2.png b/verilog/rtl/softshell/third_party/wb2axip/doc/axisafety2.png
new file mode 100644
index 0000000..5eac358
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axisafety2.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axisafety2.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/axisafety2.svg
new file mode 100644
index 0000000..e8b6eb2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axisafety2.svg
@@ -0,0 +1,453 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1002pt" height="822pt" viewBox="0 0 1002 822" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 1.796875 6.359375 L 1.796875 -25.390625 L 19.796875 -25.390625 L 19.796875 6.359375 Z M 3.8125 4.359375 L 17.796875 4.359375 L 17.796875 -23.359375 L 3.8125 -23.359375 Z M 3.8125 4.359375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 19.265625 -25.390625 L 19.265625 -21.921875 C 17.921875 -22.566406 16.648438 -23.046875 15.453125 -23.359375 C 14.253906 -23.679688 13.097656 -23.84375 11.984375 -23.84375 C 10.054688 -23.84375 8.566406 -23.46875 7.515625 -22.71875 C 6.460938 -21.96875 5.9375 -20.898438 5.9375 -19.515625 C 5.9375 -18.347656 6.285156 -17.46875 6.984375 -16.875 C 7.679688 -16.289062 9.003906 -15.816406 10.953125 -15.453125 L 13.09375 -15.015625 C 15.738281 -14.503906 17.691406 -13.613281 18.953125 -12.34375 C 20.210938 -11.070312 20.84375 -9.375 20.84375 -7.25 C 20.84375 -4.695312 19.988281 -2.765625 18.28125 -1.453125 C 16.582031 -0.140625 14.085938 0.515625 10.796875 0.515625 C 9.554688 0.515625 8.234375 0.375 6.828125 0.09375 C 5.429688 -0.1875 3.984375 -0.601562 2.484375 -1.15625 L 2.484375 -4.8125 C 3.921875 -4.007812 5.332031 -3.398438 6.71875 -2.984375 C 8.101562 -2.578125 9.460938 -2.375 10.796875 -2.375 C 12.816406 -2.375 14.378906 -2.769531 15.484375 -3.5625 C 16.585938 -4.363281 17.140625 -5.503906 17.140625 -6.984375 C 17.140625 -8.265625 16.742188 -9.269531 15.953125 -10 C 15.160156 -10.726562 13.863281 -11.273438 12.0625 -11.640625 L 9.890625 -12.0625 C 7.242188 -12.582031 5.328125 -13.40625 4.140625 -14.53125 C 2.960938 -15.65625 2.375 -17.222656 2.375 -19.234375 C 2.375 -21.554688 3.191406 -23.382812 4.828125 -24.71875 C 6.460938 -26.050781 8.710938 -26.71875 11.578125 -26.71875 C 12.816406 -26.71875 14.070312 -26.601562 15.34375 -26.375 C 16.625 -26.15625 17.929688 -25.828125 19.265625 -25.390625 Z M 19.265625 -25.390625 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 6.59375 -25.28125 L 6.59375 -19.6875 L 13.25 -19.6875 L 13.25 -17.171875 L 6.59375 -17.171875 L 6.59375 -6.484375 C 6.59375 -4.878906 6.8125 -3.847656 7.25 -3.390625 C 7.6875 -2.929688 8.582031 -2.703125 9.9375 -2.703125 L 13.25 -2.703125 L 13.25 0 L 9.9375 0 C 7.4375 0 5.710938 -0.460938 4.765625 -1.390625 C 3.816406 -2.328125 3.34375 -4.023438 3.34375 -6.484375 L 3.34375 -17.171875 L 0.96875 -17.171875 L 0.96875 -19.6875 L 3.34375 -19.6875 L 3.34375 -25.28125 Z M 6.59375 -25.28125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 20.234375 -10.65625 L 20.234375 -9.078125 L 5.359375 -9.078125 C 5.503906 -6.847656 6.175781 -5.148438 7.375 -3.984375 C 8.570312 -2.816406 10.242188 -2.234375 12.390625 -2.234375 C 13.628906 -2.234375 14.832031 -2.382812 16 -2.6875 C 17.164062 -2.988281 18.328125 -3.445312 19.484375 -4.0625 L 19.484375 -1 C 18.316406 -0.507812 17.125 -0.132812 15.90625 0.125 C 14.6875 0.382812 13.453125 0.515625 12.203125 0.515625 C 9.054688 0.515625 6.566406 -0.394531 4.734375 -2.21875 C 2.898438 -4.050781 1.984375 -6.53125 1.984375 -9.65625 C 1.984375 -12.875 2.851562 -15.425781 4.59375 -17.3125 C 6.332031 -19.207031 8.679688 -20.15625 11.640625 -20.15625 C 14.285156 -20.15625 16.378906 -19.300781 17.921875 -17.59375 C 19.460938 -15.894531 20.234375 -13.582031 20.234375 -10.65625 Z M 17 -11.609375 C 16.976562 -13.367188 16.484375 -14.773438 15.515625 -15.828125 C 14.546875 -16.890625 13.265625 -17.421875 11.671875 -17.421875 C 9.867188 -17.421875 8.425781 -16.910156 7.34375 -15.890625 C 6.257812 -14.867188 5.632812 -13.429688 5.46875 -11.578125 Z M 17 -11.609375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 6.515625 -2.953125 L 6.515625 7.484375 L 3.265625 7.484375 L 3.265625 -19.6875 L 6.515625 -19.6875 L 6.515625 -16.703125 C 7.203125 -17.867188 8.0625 -18.734375 9.09375 -19.296875 C 10.132812 -19.867188 11.375 -20.15625 12.8125 -20.15625 C 15.207031 -20.15625 17.148438 -19.207031 18.640625 -17.3125 C 20.140625 -15.414062 20.890625 -12.921875 20.890625 -9.828125 C 20.890625 -6.734375 20.140625 -4.234375 18.640625 -2.328125 C 17.148438 -0.429688 15.207031 0.515625 12.8125 0.515625 C 11.375 0.515625 10.132812 0.226562 9.09375 -0.34375 C 8.0625 -0.914062 7.203125 -1.785156 6.515625 -2.953125 Z M 17.53125 -9.828125 C 17.53125 -12.203125 17.039062 -14.066406 16.0625 -15.421875 C 15.082031 -16.773438 13.738281 -17.453125 12.03125 -17.453125 C 10.3125 -17.453125 8.960938 -16.773438 7.984375 -15.421875 C 7.003906 -14.066406 6.515625 -12.203125 6.515625 -9.828125 C 6.515625 -7.453125 7.003906 -5.585938 7.984375 -4.234375 C 8.960938 -2.878906 10.3125 -2.203125 12.03125 -2.203125 C 13.738281 -2.203125 15.082031 -2.878906 16.0625 -4.234375 C 17.039062 -5.585938 17.53125 -7.453125 17.53125 -9.828125 Z M 17.53125 -9.828125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 15.9375 -19.109375 L 15.9375 -16.046875 C 15.03125 -16.515625 14.082031 -16.863281 13.09375 -17.09375 C 12.113281 -17.332031 11.09375 -17.453125 10.03125 -17.453125 C 8.425781 -17.453125 7.222656 -17.207031 6.421875 -16.71875 C 5.617188 -16.226562 5.21875 -15.488281 5.21875 -14.5 C 5.21875 -13.75 5.503906 -13.160156 6.078125 -12.734375 C 6.648438 -12.304688 7.804688 -11.898438 9.546875 -11.515625 L 10.65625 -11.265625 C 12.945312 -10.773438 14.578125 -10.082031 15.546875 -9.1875 C 16.515625 -8.289062 17 -7.039062 17 -5.4375 C 17 -3.601562 16.273438 -2.148438 14.828125 -1.078125 C 13.378906 -0.015625 11.390625 0.515625 8.859375 0.515625 C 7.804688 0.515625 6.707031 0.410156 5.5625 0.203125 C 4.414062 -0.00390625 3.210938 -0.3125 1.953125 -0.71875 L 1.953125 -4.0625 C 3.148438 -3.4375 4.328125 -2.96875 5.484375 -2.65625 C 6.640625 -2.351562 7.789062 -2.203125 8.9375 -2.203125 C 10.457031 -2.203125 11.625 -2.460938 12.4375 -2.984375 C 13.257812 -3.503906 13.671875 -4.238281 13.671875 -5.1875 C 13.671875 -6.0625 13.375 -6.734375 12.78125 -7.203125 C 12.195312 -7.671875 10.898438 -8.125 8.890625 -8.5625 L 7.765625 -8.828125 C 5.765625 -9.242188 4.316406 -9.890625 3.421875 -10.765625 C 2.535156 -11.640625 2.09375 -12.835938 2.09375 -14.359375 C 2.09375 -16.210938 2.75 -17.640625 4.0625 -18.640625 C 5.375 -19.648438 7.238281 -20.15625 9.65625 -20.15625 C 10.84375 -20.15625 11.960938 -20.066406 13.015625 -19.890625 C 14.078125 -19.722656 15.050781 -19.460938 15.9375 -19.109375 Z M 15.9375 -19.109375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d=""/>
+</symbol>
+<symbol overflow="visible" id="glyph0-7">
+<path style="stroke:none;" d="M 11.015625 -17.421875 C 9.285156 -17.421875 7.914062 -16.742188 6.90625 -15.390625 C 5.894531 -14.035156 5.390625 -12.179688 5.390625 -9.828125 C 5.390625 -7.472656 5.890625 -5.617188 6.890625 -4.265625 C 7.898438 -2.910156 9.273438 -2.234375 11.015625 -2.234375 C 12.742188 -2.234375 14.109375 -2.910156 15.109375 -4.265625 C 16.117188 -5.628906 16.625 -7.484375 16.625 -9.828125 C 16.625 -12.160156 16.117188 -14.007812 15.109375 -15.375 C 14.109375 -16.738281 12.742188 -17.421875 11.015625 -17.421875 Z M 11.015625 -20.15625 C 13.828125 -20.15625 16.035156 -19.238281 17.640625 -17.40625 C 19.253906 -15.582031 20.0625 -13.054688 20.0625 -9.828125 C 20.0625 -6.609375 19.253906 -4.078125 17.640625 -2.234375 C 16.035156 -0.398438 13.828125 0.515625 11.015625 0.515625 C 8.191406 0.515625 5.976562 -0.398438 4.375 -2.234375 C 2.78125 -4.078125 1.984375 -6.609375 1.984375 -9.828125 C 1.984375 -13.054688 2.78125 -15.582031 4.375 -17.40625 C 5.976562 -19.238281 8.191406 -20.15625 11.015625 -20.15625 Z M 11.015625 -20.15625 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-8">
+<path style="stroke:none;" d="M 1.078125 -19.6875 L 4.5 -19.6875 L 10.65625 -3.171875 L 16.8125 -19.6875 L 20.234375 -19.6875 L 12.84375 0 L 8.453125 0 Z M 1.078125 -19.6875 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-9">
+<path style="stroke:none;" d="M 14.796875 -16.671875 C 14.429688 -16.878906 14.035156 -17.03125 13.609375 -17.125 C 13.179688 -17.226562 12.710938 -17.28125 12.203125 -17.28125 C 10.367188 -17.28125 8.960938 -16.6875 7.984375 -15.5 C 7.003906 -14.3125 6.515625 -12.601562 6.515625 -10.375 L 6.515625 0 L 3.265625 0 L 3.265625 -19.6875 L 6.515625 -19.6875 L 6.515625 -16.625 C 7.203125 -17.820312 8.085938 -18.707031 9.171875 -19.28125 C 10.265625 -19.863281 11.59375 -20.15625 13.15625 -20.15625 C 13.375 -20.15625 13.617188 -20.140625 13.890625 -20.109375 C 14.160156 -20.085938 14.457031 -20.046875 14.78125 -19.984375 Z M 14.796875 -16.671875 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-10">
+<path style="stroke:none;" d="M 3.390625 -19.6875 L 6.625 -19.6875 L 6.625 0 L 3.390625 0 Z M 3.390625 -27.359375 L 6.625 -27.359375 L 6.625 -23.25 L 3.390625 -23.25 Z M 3.390625 -27.359375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-11">
+<path style="stroke:none;" d="M 13.359375 -27.359375 L 13.359375 -24.65625 L 10.265625 -24.65625 C 9.109375 -24.65625 8.300781 -24.421875 7.84375 -23.953125 C 7.394531 -23.484375 7.171875 -22.640625 7.171875 -21.421875 L 7.171875 -19.6875 L 12.5 -19.6875 L 12.5 -17.171875 L 7.171875 -17.171875 L 7.171875 0 L 3.921875 0 L 3.921875 -17.171875 L 0.828125 -17.171875 L 0.828125 -19.6875 L 3.921875 -19.6875 L 3.921875 -21.0625 C 3.921875 -23.25 4.429688 -24.84375 5.453125 -25.84375 C 6.472656 -26.851562 8.085938 -27.359375 10.296875 -27.359375 Z M 13.359375 -27.359375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-12">
+<path style="stroke:none;" d="M 11.578125 1.828125 C 10.671875 4.171875 9.78125 5.695312 8.90625 6.40625 C 8.039062 7.125 6.882812 7.484375 5.4375 7.484375 L 2.84375 7.484375 L 2.84375 4.78125 L 4.75 4.78125 C 5.632812 4.78125 6.320312 4.566406 6.8125 4.140625 C 7.3125 3.722656 7.859375 2.726562 8.453125 1.15625 L 9.03125 -0.3125 L 1.078125 -19.6875 L 4.5 -19.6875 L 10.65625 -4.296875 L 16.8125 -19.6875 L 20.234375 -19.6875 Z M 11.578125 1.828125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-13">
+<path style="stroke:none;" d="M 19.765625 -11.890625 L 19.765625 0 L 16.53125 0 L 16.53125 -11.78125 C 16.53125 -13.644531 16.164062 -15.035156 15.4375 -15.953125 C 14.707031 -16.878906 13.617188 -17.34375 12.171875 -17.34375 C 10.421875 -17.34375 9.039062 -16.785156 8.03125 -15.671875 C 7.019531 -14.566406 6.515625 -13.050781 6.515625 -11.125 L 6.515625 0 L 3.265625 0 L 3.265625 -27.359375 L 6.515625 -27.359375 L 6.515625 -16.625 C 7.296875 -17.8125 8.207031 -18.695312 9.25 -19.28125 C 10.300781 -19.863281 11.515625 -20.15625 12.890625 -20.15625 C 15.148438 -20.15625 16.859375 -19.457031 18.015625 -18.0625 C 19.179688 -16.664062 19.765625 -14.609375 19.765625 -11.890625 Z M 19.765625 -11.890625 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-14">
+<path style="stroke:none;" d="M 17.53125 -9.828125 C 17.53125 -12.203125 17.039062 -14.066406 16.0625 -15.421875 C 15.082031 -16.773438 13.738281 -17.453125 12.03125 -17.453125 C 10.3125 -17.453125 8.960938 -16.773438 7.984375 -15.421875 C 7.003906 -14.066406 6.515625 -12.203125 6.515625 -9.828125 C 6.515625 -7.453125 7.003906 -5.585938 7.984375 -4.234375 C 8.960938 -2.878906 10.3125 -2.203125 12.03125 -2.203125 C 13.738281 -2.203125 15.082031 -2.878906 16.0625 -4.234375 C 17.039062 -5.585938 17.53125 -7.453125 17.53125 -9.828125 Z M 6.515625 -16.703125 C 7.203125 -17.867188 8.0625 -18.734375 9.09375 -19.296875 C 10.132812 -19.867188 11.375 -20.15625 12.8125 -20.15625 C 15.207031 -20.15625 17.148438 -19.207031 18.640625 -17.3125 C 20.140625 -15.414062 20.890625 -12.921875 20.890625 -9.828125 C 20.890625 -6.734375 20.140625 -4.234375 18.640625 -2.328125 C 17.148438 -0.429688 15.207031 0.515625 12.8125 0.515625 C 11.375 0.515625 10.132812 0.226562 9.09375 -0.34375 C 8.0625 -0.914062 7.203125 -1.785156 6.515625 -2.953125 L 6.515625 0 L 3.265625 0 L 3.265625 -27.359375 L 6.515625 -27.359375 Z M 6.515625 -16.703125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-15">
+<path style="stroke:none;" d="M 3.0625 -7.765625 L 3.0625 -19.6875 L 6.296875 -19.6875 L 6.296875 -7.890625 C 6.296875 -6.023438 6.65625 -4.625 7.375 -3.6875 C 8.101562 -2.757812 9.195312 -2.296875 10.65625 -2.296875 C 12.394531 -2.296875 13.769531 -2.851562 14.78125 -3.96875 C 15.800781 -5.082031 16.3125 -6.601562 16.3125 -8.53125 L 16.3125 -19.6875 L 19.546875 -19.6875 L 19.546875 0 L 16.3125 0 L 16.3125 -3.03125 C 15.53125 -1.832031 14.617188 -0.941406 13.578125 -0.359375 C 12.546875 0.222656 11.34375 0.515625 9.96875 0.515625 C 7.707031 0.515625 5.988281 -0.1875 4.8125 -1.59375 C 3.644531 -3 3.0625 -5.054688 3.0625 -7.765625 Z M 11.203125 -20.15625 Z M 11.203125 -20.15625 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-16">
+<path style="stroke:none;" d="M 12.34375 -9.890625 C 9.726562 -9.890625 7.914062 -9.59375 6.90625 -9 C 5.894531 -8.40625 5.390625 -7.382812 5.390625 -5.9375 C 5.390625 -4.789062 5.769531 -3.878906 6.53125 -3.203125 C 7.289062 -2.535156 8.316406 -2.203125 9.609375 -2.203125 C 11.410156 -2.203125 12.851562 -2.835938 13.9375 -4.109375 C 15.019531 -5.378906 15.5625 -7.066406 15.5625 -9.171875 L 15.5625 -9.890625 Z M 18.796875 -11.234375 L 18.796875 0 L 15.5625 0 L 15.5625 -2.984375 C 14.820312 -1.796875 13.898438 -0.914062 12.796875 -0.34375 C 11.691406 0.226562 10.34375 0.515625 8.75 0.515625 C 6.738281 0.515625 5.132812 -0.0507812 3.9375 -1.1875 C 2.75 -2.320312 2.15625 -3.835938 2.15625 -5.734375 C 2.15625 -7.941406 2.894531 -9.609375 4.375 -10.734375 C 5.863281 -11.859375 8.078125 -12.421875 11.015625 -12.421875 L 15.5625 -12.421875 L 15.5625 -12.75 C 15.5625 -14.238281 15.070312 -15.390625 14.09375 -16.203125 C 13.113281 -17.015625 11.738281 -17.421875 9.96875 -17.421875 C 8.84375 -17.421875 7.742188 -17.285156 6.671875 -17.015625 C 5.609375 -16.742188 4.585938 -16.335938 3.609375 -15.796875 L 3.609375 -18.796875 C 4.785156 -19.253906 5.929688 -19.59375 7.046875 -19.8125 C 8.160156 -20.039062 9.242188 -20.15625 10.296875 -20.15625 C 13.148438 -20.15625 15.28125 -19.414062 16.6875 -17.9375 C 18.09375 -16.46875 18.796875 -14.234375 18.796875 -11.234375 Z M 18.796875 -11.234375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-17">
+<path style="stroke:none;" d="M 3.390625 -27.359375 L 6.625 -27.359375 L 6.625 0 L 3.390625 0 Z M 3.390625 -27.359375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-18">
+<path style="stroke:none;" d="M 4.21875 -4.46875 L 7.921875 -4.46875 L 7.921875 0 L 4.21875 0 Z M 4.21875 -18.609375 L 7.921875 -18.609375 L 7.921875 -14.15625 L 4.21875 -14.15625 Z M 4.21875 -18.609375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-19">
+<path style="stroke:none;" d="M 4.46875 -2.984375 L 10.265625 -2.984375 L 10.265625 -23.015625 L 3.953125 -21.75 L 3.953125 -24.984375 L 10.234375 -26.25 L 13.78125 -26.25 L 13.78125 -2.984375 L 19.578125 -2.984375 L 19.578125 0 L 4.46875 0 Z M 4.46875 -2.984375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-20">
+<path style="stroke:none;" d="M 3.84375 -4.46875 L 7.5625 -4.46875 L 7.5625 0 L 3.84375 0 Z M 3.84375 -4.46875 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-21">
+<path style="stroke:none;" d="M 12.3125 -22.75 L 7.484375 -9.6875 L 17.140625 -9.6875 Z M 10.296875 -26.25 L 14.328125 -26.25 L 24.328125 0 L 20.640625 0 L 18.25 -6.734375 L 6.421875 -6.734375 L 4.03125 0 L 0.28125 0 Z M 10.296875 -26.25 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-22">
+<path style="stroke:none;" d="M 18.71875 -15.90625 C 19.53125 -17.363281 20.5 -18.4375 21.625 -19.125 C 22.75 -19.8125 24.070312 -20.15625 25.59375 -20.15625 C 27.644531 -20.15625 29.226562 -19.4375 30.34375 -18 C 31.457031 -16.570312 32.015625 -14.535156 32.015625 -11.890625 L 32.015625 0 L 28.765625 0 L 28.765625 -11.78125 C 28.765625 -13.664062 28.425781 -15.0625 27.75 -15.96875 C 27.082031 -16.882812 26.066406 -17.34375 24.703125 -17.34375 C 23.023438 -17.34375 21.695312 -16.785156 20.71875 -15.671875 C 19.75 -14.566406 19.265625 -13.050781 19.265625 -11.125 L 19.265625 0 L 16.015625 0 L 16.015625 -11.78125 C 16.015625 -13.675781 15.679688 -15.078125 15.015625 -15.984375 C 14.347656 -16.890625 13.316406 -17.34375 11.921875 -17.34375 C 10.265625 -17.34375 8.945312 -16.785156 7.96875 -15.671875 C 7 -14.554688 6.515625 -13.039062 6.515625 -11.125 L 6.515625 0 L 3.265625 0 L 3.265625 -19.6875 L 6.515625 -19.6875 L 6.515625 -16.625 C 7.253906 -17.832031 8.140625 -18.722656 9.171875 -19.296875 C 10.203125 -19.867188 11.425781 -20.15625 12.84375 -20.15625 C 14.28125 -20.15625 15.5 -19.789062 16.5 -19.0625 C 17.5 -18.34375 18.238281 -17.289062 18.71875 -15.90625 Z M 18.71875 -15.90625 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-23">
+<path style="stroke:none;" d="M 19.765625 -11.890625 L 19.765625 0 L 16.53125 0 L 16.53125 -11.78125 C 16.53125 -13.644531 16.164062 -15.035156 15.4375 -15.953125 C 14.707031 -16.878906 13.617188 -17.34375 12.171875 -17.34375 C 10.421875 -17.34375 9.039062 -16.785156 8.03125 -15.671875 C 7.019531 -14.566406 6.515625 -13.050781 6.515625 -11.125 L 6.515625 0 L 3.265625 0 L 3.265625 -19.6875 L 6.515625 -19.6875 L 6.515625 -16.625 C 7.296875 -17.8125 8.207031 -18.695312 9.25 -19.28125 C 10.300781 -19.863281 11.515625 -20.15625 12.890625 -20.15625 C 15.148438 -20.15625 16.859375 -19.457031 18.015625 -18.0625 C 19.179688 -16.664062 19.765625 -14.609375 19.765625 -11.890625 Z M 19.765625 -11.890625 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-24">
+<path style="stroke:none;" d="M 7.078125 -23.328125 L 7.078125 -13.46875 L 11.546875 -13.46875 C 13.203125 -13.46875 14.476562 -13.894531 15.375 -14.75 C 16.28125 -15.601562 16.734375 -16.820312 16.734375 -18.40625 C 16.734375 -19.976562 16.28125 -21.191406 15.375 -22.046875 C 14.476562 -22.898438 13.203125 -23.328125 11.546875 -23.328125 Z M 3.53125 -26.25 L 11.546875 -26.25 C 14.492188 -26.25 16.71875 -25.582031 18.21875 -24.25 C 19.726562 -22.914062 20.484375 -20.96875 20.484375 -18.40625 C 20.484375 -15.8125 19.726562 -13.851562 18.21875 -12.53125 C 16.71875 -11.207031 14.492188 -10.546875 11.546875 -10.546875 L 7.078125 -10.546875 L 7.078125 0 L 3.53125 0 Z M 3.53125 -26.25 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-25">
+<path style="stroke:none;" d="M 16.34375 -16.703125 L 16.34375 -27.359375 L 19.578125 -27.359375 L 19.578125 0 L 16.34375 0 L 16.34375 -2.953125 C 15.664062 -1.785156 14.804688 -0.914062 13.765625 -0.34375 C 12.734375 0.226562 11.488281 0.515625 10.03125 0.515625 C 7.65625 0.515625 5.71875 -0.429688 4.21875 -2.328125 C 2.726562 -4.234375 1.984375 -6.734375 1.984375 -9.828125 C 1.984375 -12.921875 2.726562 -15.414062 4.21875 -17.3125 C 5.71875 -19.207031 7.65625 -20.15625 10.03125 -20.15625 C 11.488281 -20.15625 12.734375 -19.867188 13.765625 -19.296875 C 14.804688 -18.734375 15.664062 -17.867188 16.34375 -16.703125 Z M 5.328125 -9.828125 C 5.328125 -7.453125 5.816406 -5.585938 6.796875 -4.234375 C 7.773438 -2.878906 9.117188 -2.203125 10.828125 -2.203125 C 12.535156 -2.203125 13.878906 -2.878906 14.859375 -4.234375 C 15.847656 -5.585938 16.34375 -7.453125 16.34375 -9.828125 C 16.34375 -12.203125 15.847656 -14.066406 14.859375 -15.421875 C 13.878906 -16.773438 12.535156 -17.453125 10.828125 -17.453125 C 9.117188 -17.453125 7.773438 -16.773438 6.796875 -15.421875 C 5.816406 -14.066406 5.328125 -12.203125 5.328125 -9.828125 Z M 5.328125 -9.828125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-26">
+<path style="stroke:none;" d="M 17.5625 -18.9375 L 17.5625 -15.90625 C 16.644531 -16.414062 15.726562 -16.796875 14.8125 -17.046875 C 13.894531 -17.296875 12.96875 -17.421875 12.03125 -17.421875 C 9.925781 -17.421875 8.289062 -16.753906 7.125 -15.421875 C 5.96875 -14.097656 5.390625 -12.234375 5.390625 -9.828125 C 5.390625 -7.421875 5.96875 -5.550781 7.125 -4.21875 C 8.289062 -2.894531 9.925781 -2.234375 12.03125 -2.234375 C 12.96875 -2.234375 13.894531 -2.359375 14.8125 -2.609375 C 15.726562 -2.859375 16.644531 -3.238281 17.5625 -3.75 L 17.5625 -0.75 C 16.65625 -0.332031 15.71875 -0.0195312 14.75 0.1875 C 13.789062 0.40625 12.765625 0.515625 11.671875 0.515625 C 8.703125 0.515625 6.34375 -0.414062 4.59375 -2.28125 C 2.851562 -4.144531 1.984375 -6.660156 1.984375 -9.828125 C 1.984375 -13.035156 2.863281 -15.554688 4.625 -17.390625 C 6.394531 -19.234375 8.816406 -20.15625 11.890625 -20.15625 C 12.878906 -20.15625 13.847656 -20.050781 14.796875 -19.84375 C 15.742188 -19.644531 16.664062 -19.34375 17.5625 -18.9375 Z M 17.5625 -18.9375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-27">
+<path style="stroke:none;" d="M 6.90625 -2.984375 L 19.296875 -2.984375 L 19.296875 0 L 2.640625 0 L 2.640625 -2.984375 C 3.984375 -4.378906 5.816406 -6.25 8.140625 -8.59375 C 10.472656 -10.945312 11.9375 -12.46875 12.53125 -13.15625 C 13.664062 -14.425781 14.457031 -15.503906 14.90625 -16.390625 C 15.363281 -17.273438 15.59375 -18.144531 15.59375 -19 C 15.59375 -20.394531 15.101562 -21.53125 14.125 -22.40625 C 13.144531 -23.289062 11.867188 -23.734375 10.296875 -23.734375 C 9.179688 -23.734375 8.003906 -23.539062 6.765625 -23.15625 C 5.535156 -22.769531 4.21875 -22.179688 2.8125 -21.390625 L 2.8125 -24.984375 C 4.238281 -25.554688 5.570312 -25.988281 6.8125 -26.28125 C 8.0625 -26.570312 9.203125 -26.71875 10.234375 -26.71875 C 12.953125 -26.71875 15.117188 -26.035156 16.734375 -24.671875 C 18.347656 -23.316406 19.15625 -21.503906 19.15625 -19.234375 C 19.15625 -18.148438 18.953125 -17.125 18.546875 -16.15625 C 18.148438 -15.195312 17.414062 -14.0625 16.34375 -12.75 C 16.050781 -12.40625 15.117188 -11.421875 13.546875 -9.796875 C 11.984375 -8.171875 9.769531 -5.898438 6.90625 -2.984375 Z M 6.90625 -2.984375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-28">
+<path style="stroke:none;" d="M 16.34375 -10.078125 C 16.34375 -12.421875 15.859375 -14.234375 14.890625 -15.515625 C 13.929688 -16.804688 12.578125 -17.453125 10.828125 -17.453125 C 9.097656 -17.453125 7.75 -16.804688 6.78125 -15.515625 C 5.8125 -14.234375 5.328125 -12.421875 5.328125 -10.078125 C 5.328125 -7.742188 5.8125 -5.929688 6.78125 -4.640625 C 7.75 -3.347656 9.097656 -2.703125 10.828125 -2.703125 C 12.578125 -2.703125 13.929688 -3.347656 14.890625 -4.640625 C 15.859375 -5.929688 16.34375 -7.742188 16.34375 -10.078125 Z M 19.578125 -2.4375 C 19.578125 0.90625 18.832031 3.394531 17.34375 5.03125 C 15.863281 6.664062 13.585938 7.484375 10.515625 7.484375 C 9.378906 7.484375 8.304688 7.398438 7.296875 7.234375 C 6.285156 7.066406 5.304688 6.804688 4.359375 6.453125 L 4.359375 3.3125 C 5.304688 3.820312 6.242188 4.195312 7.171875 4.4375 C 8.097656 4.6875 9.039062 4.8125 10 4.8125 C 12.125 4.8125 13.710938 4.257812 14.765625 3.15625 C 15.816406 2.050781 16.34375 0.378906 16.34375 -1.859375 L 16.34375 -3.46875 C 15.675781 -2.300781 14.820312 -1.429688 13.78125 -0.859375 C 12.738281 -0.285156 11.488281 0 10.03125 0 C 7.625 0 5.679688 -0.914062 4.203125 -2.75 C 2.722656 -4.59375 1.984375 -7.035156 1.984375 -10.078125 C 1.984375 -13.117188 2.722656 -15.554688 4.203125 -17.390625 C 5.679688 -19.234375 7.625 -20.15625 10.03125 -20.15625 C 11.488281 -20.15625 12.738281 -19.867188 13.78125 -19.296875 C 14.820312 -18.722656 15.675781 -17.859375 16.34375 -16.703125 L 16.34375 -19.6875 L 19.578125 -19.6875 Z M 19.578125 -2.4375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-29">
+<path style="stroke:none;" d="M 3.53125 -26.25 L 7.078125 -26.25 L 7.078125 0 L 3.53125 0 Z M 3.53125 -26.25 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-30">
+<path style="stroke:none;" d="M 5.328125 -9.828125 C 5.328125 -7.453125 5.816406 -5.585938 6.796875 -4.234375 C 7.773438 -2.878906 9.117188 -2.203125 10.828125 -2.203125 C 12.535156 -2.203125 13.878906 -2.878906 14.859375 -4.234375 C 15.847656 -5.585938 16.34375 -7.453125 16.34375 -9.828125 C 16.34375 -12.203125 15.847656 -14.066406 14.859375 -15.421875 C 13.878906 -16.773438 12.535156 -17.453125 10.828125 -17.453125 C 9.117188 -17.453125 7.773438 -16.773438 6.796875 -15.421875 C 5.816406 -14.066406 5.328125 -12.203125 5.328125 -9.828125 Z M 16.34375 -2.953125 C 15.664062 -1.785156 14.804688 -0.914062 13.765625 -0.34375 C 12.734375 0.226562 11.488281 0.515625 10.03125 0.515625 C 7.65625 0.515625 5.71875 -0.429688 4.21875 -2.328125 C 2.726562 -4.234375 1.984375 -6.734375 1.984375 -9.828125 C 1.984375 -12.921875 2.726562 -15.414062 4.21875 -17.3125 C 5.71875 -19.207031 7.65625 -20.15625 10.03125 -20.15625 C 11.488281 -20.15625 12.734375 -19.867188 13.765625 -19.296875 C 14.804688 -18.734375 15.664062 -17.867188 16.34375 -16.703125 L 16.34375 -19.6875 L 19.578125 -19.6875 L 19.578125 7.484375 L 16.34375 7.484375 Z M 16.34375 -2.953125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-31">
+<path style="stroke:none;" d="M 5.4375 -4.46875 L 9 -4.46875 L 9 0 L 5.4375 0 Z M 5.4375 -26.25 L 9 -26.25 L 9 -14.734375 L 8.65625 -8.453125 L 5.796875 -8.453125 L 5.4375 -14.734375 Z M 5.4375 -26.25 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-32">
+<path style="stroke:none;" d="M -0.109375 -26.25 L 22.09375 -26.25 L 22.09375 -23.25 L 12.78125 -23.25 L 12.78125 0 L 9.21875 0 L 9.21875 -23.25 L -0.109375 -23.25 Z M -0.109375 -26.25 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-33">
+<path style="stroke:none;" d="M 2.265625 -26.25 L 6.078125 -26.25 L 12.609375 -16.484375 L 19.15625 -26.25 L 22.96875 -26.25 L 14.53125 -13.640625 L 23.53125 0 L 19.71875 0 L 12.34375 -11.15625 L 4.90625 0 L 1.078125 0 L 10.4375 -14.015625 Z M 2.265625 -26.25 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-34">
+<path style="stroke:none;" d="M 3.125 -26.25 L 6.703125 -26.25 L 6.703125 -10.296875 C 6.703125 -7.484375 7.207031 -5.457031 8.21875 -4.21875 C 9.238281 -2.988281 10.894531 -2.375 13.1875 -2.375 C 15.457031 -2.375 17.101562 -2.988281 18.125 -4.21875 C 19.144531 -5.457031 19.65625 -7.484375 19.65625 -10.296875 L 19.65625 -26.25 L 23.21875 -26.25 L 23.21875 -9.859375 C 23.21875 -6.441406 22.367188 -3.859375 20.671875 -2.109375 C 18.984375 -0.359375 16.488281 0.515625 13.1875 0.515625 C 9.863281 0.515625 7.351562 -0.359375 5.65625 -2.109375 C 3.96875 -3.859375 3.125 -6.441406 3.125 -9.859375 Z M 3.125 -26.25 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-35">
+<path style="stroke:none;" d="M 7.078125 -12.53125 L 7.078125 -2.921875 L 12.78125 -2.921875 C 14.6875 -2.921875 16.097656 -3.316406 17.015625 -4.109375 C 17.941406 -4.898438 18.40625 -6.109375 18.40625 -7.734375 C 18.40625 -9.378906 17.941406 -10.585938 17.015625 -11.359375 C 16.097656 -12.140625 14.6875 -12.53125 12.78125 -12.53125 Z M 7.078125 -23.328125 L 7.078125 -15.421875 L 12.34375 -15.421875 C 14.070312 -15.421875 15.359375 -15.742188 16.203125 -16.390625 C 17.054688 -17.046875 17.484375 -18.039062 17.484375 -19.375 C 17.484375 -20.695312 17.054688 -21.6875 16.203125 -22.34375 C 15.359375 -23 14.070312 -23.328125 12.34375 -23.328125 Z M 3.53125 -26.25 L 12.609375 -26.25 C 15.316406 -26.25 17.398438 -25.6875 18.859375 -24.5625 C 20.328125 -23.4375 21.0625 -21.835938 21.0625 -19.765625 C 21.0625 -18.148438 20.6875 -16.867188 19.9375 -15.921875 C 19.1875 -14.972656 18.082031 -14.382812 16.625 -14.15625 C 18.375 -13.78125 19.734375 -12.992188 20.703125 -11.796875 C 21.671875 -10.609375 22.15625 -9.125 22.15625 -7.34375 C 22.15625 -5 21.359375 -3.1875 19.765625 -1.90625 C 18.171875 -0.632812 15.898438 0 12.953125 0 L 3.53125 0 Z M 3.53125 -26.25 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-36">
+<path style="stroke:none;" d="M 3.53125 -26.25 L 18.609375 -26.25 L 18.609375 -23.25 L 7.078125 -23.25 L 7.078125 -15.515625 L 17.484375 -15.515625 L 17.484375 -12.53125 L 7.078125 -12.53125 L 7.078125 0 L 3.53125 0 Z M 3.53125 -26.25 "/>
+</symbol>
+</g>
+</defs>
+<g id="surface43475">
+<rect x="0" y="0" width="1002" height="822" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 1 -0.000000000745058 L 51 -0.000000000745058 L 51 41 L 1 41 Z M 1 -0.000000000745058 " transform="matrix(20,0,0,20,-19,1)"/>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-1" x="21" y="401.015462"/>
+  <use xlink:href="#glyph0-2" x="43.851563" y="401.015462"/>
+  <use xlink:href="#glyph0-3" x="57.966688" y="401.015462"/>
+  <use xlink:href="#glyph0-4" x="80.115126" y="401.015462"/>
+  <use xlink:href="#glyph0-5" x="102.966688" y="401.015462"/>
+  <use xlink:href="#glyph0-6" x="121.722656" y="401.015462"/>
+  <use xlink:href="#glyph0-2" x="133.16607" y="401.015462"/>
+  <use xlink:href="#glyph0-7" x="147.281196" y="401.015462"/>
+  <use xlink:href="#glyph0-6" x="169.306478" y="401.015462"/>
+  <use xlink:href="#glyph0-8" x="180.749891" y="401.015462"/>
+  <use xlink:href="#glyph0-3" x="202.054688" y="401.015462"/>
+  <use xlink:href="#glyph0-9" x="224.203125" y="401.015462"/>
+  <use xlink:href="#glyph0-10" x="239.004015" y="401.015462"/>
+  <use xlink:href="#glyph0-11" x="249.005914" y="401.015462"/>
+  <use xlink:href="#glyph0-12" x="261.047201" y="401.015462"/>
+  <use xlink:href="#glyph0-6" x="282.351997" y="401.015462"/>
+  <use xlink:href="#glyph0-2" x="293.79541" y="401.015462"/>
+  <use xlink:href="#glyph0-13" x="307.910536" y="401.015462"/>
+  <use xlink:href="#glyph0-3" x="330.726834" y="401.015462"/>
+  <use xlink:href="#glyph0-6" x="352.875271" y="401.015462"/>
+  <use xlink:href="#glyph0-14" x="364.318685" y="401.015462"/>
+  <use xlink:href="#glyph0-15" x="387.170247" y="401.015462"/>
+  <use xlink:href="#glyph0-5" x="409.986545" y="401.015462"/>
+  <use xlink:href="#glyph0-6" x="428.742513" y="401.015462"/>
+  <use xlink:href="#glyph0-11" x="440.185927" y="401.015462"/>
+  <use xlink:href="#glyph0-16" x="452.859809" y="401.015462"/>
+  <use xlink:href="#glyph0-15" x="474.920356" y="401.015462"/>
+  <use xlink:href="#glyph0-17" x="497.736654" y="401.015462"/>
+  <use xlink:href="#glyph0-2" x="507.738553" y="401.015462"/>
+  <use xlink:href="#glyph0-6" x="521.853678" y="401.015462"/>
+  <use xlink:href="#glyph0-10" x="533.297092" y="401.015462"/>
+  <use xlink:href="#glyph0-5" x="543.298991" y="401.015462"/>
+  <use xlink:href="#glyph0-7" x="562.054959" y="401.015462"/>
+  <use xlink:href="#glyph0-17" x="584.080241" y="401.015462"/>
+  <use xlink:href="#glyph0-16" x="594.08214" y="401.015462"/>
+  <use xlink:href="#glyph0-2" x="616.142687" y="401.015462"/>
+  <use xlink:href="#glyph0-7" x="630.257812" y="401.015462"/>
+  <use xlink:href="#glyph0-9" x="652.283095" y="401.015462"/>
+  <use xlink:href="#glyph0-18" x="666.451389" y="401.015462"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-19" x="21" y="491.327962"/>
+  <use xlink:href="#glyph0-20" x="43.904188" y="491.327962"/>
+  <use xlink:href="#glyph0-6" x="55.347602" y="491.327962"/>
+  <use xlink:href="#glyph0-21" x="66.791016" y="491.327962"/>
+  <use xlink:href="#glyph0-5" x="91.418023" y="491.327962"/>
+  <use xlink:href="#glyph0-5" x="110.173991" y="491.327962"/>
+  <use xlink:href="#glyph0-15" x="128.929959" y="491.327962"/>
+  <use xlink:href="#glyph0-22" x="151.746257" y="491.327962"/>
+  <use xlink:href="#glyph0-3" x="186.814616" y="491.327962"/>
+  <use xlink:href="#glyph0-6" x="208.963053" y="491.327962"/>
+  <use xlink:href="#glyph0-2" x="220.406467" y="491.327962"/>
+  <use xlink:href="#glyph0-13" x="234.521593" y="491.327962"/>
+  <use xlink:href="#glyph0-3" x="257.337891" y="491.327962"/>
+  <use xlink:href="#glyph0-6" x="279.486328" y="491.327962"/>
+  <use xlink:href="#glyph0-5" x="290.929742" y="491.327962"/>
+  <use xlink:href="#glyph0-17" x="309.68571" y="491.327962"/>
+  <use xlink:href="#glyph0-16" x="319.687609" y="491.327962"/>
+  <use xlink:href="#glyph0-8" x="341.748155" y="491.327962"/>
+  <use xlink:href="#glyph0-3" x="363.052951" y="491.327962"/>
+  <use xlink:href="#glyph0-6" x="385.201389" y="491.327962"/>
+  <use xlink:href="#glyph0-13" x="396.644803" y="491.327962"/>
+  <use xlink:href="#glyph0-16" x="419.4611" y="491.327962"/>
+  <use xlink:href="#glyph0-5" x="441.521647" y="491.327962"/>
+  <use xlink:href="#glyph0-6" x="460.277615" y="491.327962"/>
+  <use xlink:href="#glyph0-23" x="471.721029" y="491.327962"/>
+  <use xlink:href="#glyph0-7" x="494.537326" y="491.327962"/>
+  <use xlink:href="#glyph0-6" x="516.562609" y="491.327962"/>
+  <use xlink:href="#glyph0-11" x="528.006022" y="491.327962"/>
+  <use xlink:href="#glyph0-16" x="540.679905" y="491.327962"/>
+  <use xlink:href="#glyph0-15" x="562.740451" y="491.327962"/>
+  <use xlink:href="#glyph0-17" x="585.556749" y="491.327962"/>
+  <use xlink:href="#glyph0-2" x="595.558648" y="491.327962"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-6" x="21" y="536.480306"/>
+  <use xlink:href="#glyph0-6" x="32.443414" y="536.480306"/>
+  <use xlink:href="#glyph0-6" x="43.886827" y="536.480306"/>
+  <use xlink:href="#glyph0-6" x="55.330241" y="536.480306"/>
+  <use xlink:href="#glyph0-6" x="66.773655" y="536.480306"/>
+  <use xlink:href="#glyph0-24" x="78.217068" y="536.480306"/>
+  <use xlink:href="#glyph0-9" x="99.293457" y="536.480306"/>
+  <use xlink:href="#glyph0-7" x="113.303602" y="536.480306"/>
+  <use xlink:href="#glyph0-8" x="135.328885" y="536.480306"/>
+  <use xlink:href="#glyph0-3" x="156.633681" y="536.480306"/>
+  <use xlink:href="#glyph0-6" x="178.782118" y="536.480306"/>
+  <use xlink:href="#glyph0-23" x="190.225532" y="536.480306"/>
+  <use xlink:href="#glyph0-7" x="213.041829" y="536.480306"/>
+  <use xlink:href="#glyph0-6" x="235.067112" y="536.480306"/>
+  <use xlink:href="#glyph0-11" x="246.510525" y="536.480306"/>
+  <use xlink:href="#glyph0-16" x="259.184408" y="536.480306"/>
+  <use xlink:href="#glyph0-15" x="281.244954" y="536.480306"/>
+  <use xlink:href="#glyph0-17" x="304.061252" y="536.480306"/>
+  <use xlink:href="#glyph0-2" x="314.063151" y="536.480306"/>
+  <use xlink:href="#glyph0-5" x="328.178277" y="536.480306"/>
+  <use xlink:href="#glyph0-6" x="346.934245" y="536.480306"/>
+  <use xlink:href="#glyph0-16" x="358.377658" y="536.480306"/>
+  <use xlink:href="#glyph0-9" x="380.438205" y="536.480306"/>
+  <use xlink:href="#glyph0-3" x="394.448351" y="536.480306"/>
+  <use xlink:href="#glyph0-6" x="416.596788" y="536.480306"/>
+  <use xlink:href="#glyph0-3" x="428.040202" y="536.480306"/>
+  <use xlink:href="#glyph0-8" x="450.188639" y="536.480306"/>
+  <use xlink:href="#glyph0-3" x="471.493435" y="536.480306"/>
+  <use xlink:href="#glyph0-9" x="493.641873" y="536.480306"/>
+  <use xlink:href="#glyph0-6" x="508.442763" y="536.480306"/>
+  <use xlink:href="#glyph0-25" x="519.886176" y="536.480306"/>
+  <use xlink:href="#glyph0-3" x="542.737739" y="536.480306"/>
+  <use xlink:href="#glyph0-2" x="564.886176" y="536.480306"/>
+  <use xlink:href="#glyph0-3" x="579.001302" y="536.480306"/>
+  <use xlink:href="#glyph0-26" x="601.14974" y="536.480306"/>
+  <use xlink:href="#glyph0-2" x="620.942763" y="536.480306"/>
+  <use xlink:href="#glyph0-3" x="635.057888" y="536.480306"/>
+  <use xlink:href="#glyph0-25" x="657.206326" y="536.480306"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-27" x="21" y="626.792806"/>
+  <use xlink:href="#glyph0-20" x="43.904188" y="626.792806"/>
+  <use xlink:href="#glyph0-6" x="55.347602" y="626.792806"/>
+  <use xlink:href="#glyph0-21" x="66.791016" y="626.792806"/>
+  <use xlink:href="#glyph0-5" x="91.418023" y="626.792806"/>
+  <use xlink:href="#glyph0-5" x="110.173991" y="626.792806"/>
+  <use xlink:href="#glyph0-15" x="128.929959" y="626.792806"/>
+  <use xlink:href="#glyph0-22" x="151.746257" y="626.792806"/>
+  <use xlink:href="#glyph0-3" x="186.814616" y="626.792806"/>
+  <use xlink:href="#glyph0-6" x="208.963053" y="626.792806"/>
+  <use xlink:href="#glyph0-23" x="220.406467" y="626.792806"/>
+  <use xlink:href="#glyph0-7" x="243.222765" y="626.792806"/>
+  <use xlink:href="#glyph0-2" x="265.248047" y="626.792806"/>
+  <use xlink:href="#glyph0-13" x="279.363173" y="626.792806"/>
+  <use xlink:href="#glyph0-10" x="302.17947" y="626.792806"/>
+  <use xlink:href="#glyph0-23" x="312.181369" y="626.792806"/>
+  <use xlink:href="#glyph0-28" x="334.997667" y="626.792806"/>
+  <use xlink:href="#glyph0-6" x="357.84923" y="626.792806"/>
+  <use xlink:href="#glyph0-7" x="369.292643" y="626.792806"/>
+  <use xlink:href="#glyph0-11" x="391.317925" y="626.792806"/>
+  <use xlink:href="#glyph0-6" x="403.991808" y="626.792806"/>
+  <use xlink:href="#glyph0-2" x="415.435221" y="626.792806"/>
+  <use xlink:href="#glyph0-13" x="429.550347" y="626.792806"/>
+  <use xlink:href="#glyph0-3" x="452.366645" y="626.792806"/>
+  <use xlink:href="#glyph0-6" x="474.515082" y="626.792806"/>
+  <use xlink:href="#glyph0-5" x="485.958496" y="626.792806"/>
+  <use xlink:href="#glyph0-17" x="504.714464" y="626.792806"/>
+  <use xlink:href="#glyph0-16" x="514.716363" y="626.792806"/>
+  <use xlink:href="#glyph0-8" x="536.77691" y="626.792806"/>
+  <use xlink:href="#glyph0-3" x="558.081706" y="626.792806"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-6" x="21" y="671.949056"/>
+  <use xlink:href="#glyph0-6" x="32.443414" y="671.949056"/>
+  <use xlink:href="#glyph0-6" x="43.886827" y="671.949056"/>
+  <use xlink:href="#glyph0-6" x="55.330241" y="671.949056"/>
+  <use xlink:href="#glyph0-24" x="66.773655" y="671.949056"/>
+  <use xlink:href="#glyph0-9" x="87.850043" y="671.949056"/>
+  <use xlink:href="#glyph0-7" x="101.860189" y="671.949056"/>
+  <use xlink:href="#glyph0-8" x="123.885471" y="671.949056"/>
+  <use xlink:href="#glyph0-3" x="145.190267" y="671.949056"/>
+  <use xlink:href="#glyph0-6" x="167.338704" y="671.949056"/>
+  <use xlink:href="#glyph0-2" x="178.782118" y="671.949056"/>
+  <use xlink:href="#glyph0-13" x="192.897244" y="671.949056"/>
+  <use xlink:href="#glyph0-3" x="215.713542" y="671.949056"/>
+  <use xlink:href="#glyph0-6" x="237.861979" y="671.949056"/>
+  <use xlink:href="#glyph0-22" x="249.305393" y="671.949056"/>
+  <use xlink:href="#glyph0-16" x="284.373752" y="671.949056"/>
+  <use xlink:href="#glyph0-5" x="306.434299" y="671.949056"/>
+  <use xlink:href="#glyph0-2" x="325.190267" y="671.949056"/>
+  <use xlink:href="#glyph0-3" x="339.305393" y="671.949056"/>
+  <use xlink:href="#glyph0-9" x="361.45383" y="671.949056"/>
+  <use xlink:href="#glyph0-6" x="376.25472" y="671.949056"/>
+  <use xlink:href="#glyph0-10" x="387.698134" y="671.949056"/>
+  <use xlink:href="#glyph0-23" x="397.700033" y="671.949056"/>
+  <use xlink:href="#glyph0-2" x="420.51633" y="671.949056"/>
+  <use xlink:href="#glyph0-3" x="434.631456" y="671.949056"/>
+  <use xlink:href="#glyph0-9" x="456.779894" y="671.949056"/>
+  <use xlink:href="#glyph0-11" x="471.580783" y="671.949056"/>
+  <use xlink:href="#glyph0-16" x="484.254666" y="671.949056"/>
+  <use xlink:href="#glyph0-26" x="506.315213" y="671.949056"/>
+  <use xlink:href="#glyph0-3" x="526.108236" y="671.949056"/>
+  <use xlink:href="#glyph0-6" x="548.256673" y="671.949056"/>
+  <use xlink:href="#glyph0-4" x="559.700087" y="671.949056"/>
+  <use xlink:href="#glyph0-16" x="582.551649" y="671.949056"/>
+  <use xlink:href="#glyph0-5" x="604.612196" y="671.949056"/>
+  <use xlink:href="#glyph0-5" x="623.368164" y="671.949056"/>
+  <use xlink:href="#glyph0-3" x="642.124132" y="671.949056"/>
+  <use xlink:href="#glyph0-5" x="664.272569" y="671.949056"/>
+  <use xlink:href="#glyph0-6" x="683.028537" y="671.949056"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-6" x="21" y="717.105306"/>
+  <use xlink:href="#glyph0-6" x="32.443414" y="717.105306"/>
+  <use xlink:href="#glyph0-6" x="43.886827" y="717.105306"/>
+  <use xlink:href="#glyph0-6" x="55.330241" y="717.105306"/>
+  <use xlink:href="#glyph0-16" x="66.773655" y="717.105306"/>
+  <use xlink:href="#glyph0-17" x="88.834201" y="717.105306"/>
+  <use xlink:href="#glyph0-17" x="98.8361" y="717.105306"/>
+  <use xlink:href="#glyph0-6" x="108.837999" y="717.105306"/>
+  <use xlink:href="#glyph0-11" x="120.281413" y="717.105306"/>
+  <use xlink:href="#glyph0-7" x="132.955295" y="717.105306"/>
+  <use xlink:href="#glyph0-9" x="154.980577" y="717.105306"/>
+  <use xlink:href="#glyph0-22" x="169.148872" y="717.105306"/>
+  <use xlink:href="#glyph0-16" x="204.217231" y="717.105306"/>
+  <use xlink:href="#glyph0-17" x="226.277778" y="717.105306"/>
+  <use xlink:href="#glyph0-6" x="236.279677" y="717.105306"/>
+  <use xlink:href="#glyph0-10" x="247.72309" y="717.105306"/>
+  <use xlink:href="#glyph0-23" x="257.724989" y="717.105306"/>
+  <use xlink:href="#glyph0-2" x="280.541287" y="717.105306"/>
+  <use xlink:href="#glyph0-3" x="294.656413" y="717.105306"/>
+  <use xlink:href="#glyph0-9" x="316.80485" y="717.105306"/>
+  <use xlink:href="#glyph0-11" x="331.60574" y="717.105306"/>
+  <use xlink:href="#glyph0-16" x="344.279622" y="717.105306"/>
+  <use xlink:href="#glyph0-26" x="366.340169" y="717.105306"/>
+  <use xlink:href="#glyph0-3" x="386.133192" y="717.105306"/>
+  <use xlink:href="#glyph0-6" x="408.28163" y="717.105306"/>
+  <use xlink:href="#glyph0-4" x="419.725043" y="717.105306"/>
+  <use xlink:href="#glyph0-9" x="442.576606" y="717.105306"/>
+  <use xlink:href="#glyph0-7" x="456.586751" y="717.105306"/>
+  <use xlink:href="#glyph0-4" x="478.612033" y="717.105306"/>
+  <use xlink:href="#glyph0-3" x="501.463596" y="717.105306"/>
+  <use xlink:href="#glyph0-9" x="523.612033" y="717.105306"/>
+  <use xlink:href="#glyph0-2" x="538.412923" y="717.105306"/>
+  <use xlink:href="#glyph0-10" x="552.528049" y="717.105306"/>
+  <use xlink:href="#glyph0-3" x="562.529948" y="717.105306"/>
+  <use xlink:href="#glyph0-5" x="584.678385" y="717.105306"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-29" x="21" y="807.4139"/>
+  <use xlink:href="#glyph0-23" x="31.617133" y="807.4139"/>
+  <use xlink:href="#glyph0-25" x="54.433431" y="807.4139"/>
+  <use xlink:href="#glyph0-15" x="77.284993" y="807.4139"/>
+  <use xlink:href="#glyph0-26" x="100.101291" y="807.4139"/>
+  <use xlink:href="#glyph0-2" x="119.894314" y="807.4139"/>
+  <use xlink:href="#glyph0-10" x="134.00944" y="807.4139"/>
+  <use xlink:href="#glyph0-7" x="144.011339" y="807.4139"/>
+  <use xlink:href="#glyph0-23" x="166.036621" y="807.4139"/>
+  <use xlink:href="#glyph0-6" x="188.852919" y="807.4139"/>
+  <use xlink:href="#glyph0-10" x="200.296332" y="807.4139"/>
+  <use xlink:href="#glyph0-5" x="210.298231" y="807.4139"/>
+  <use xlink:href="#glyph0-6" x="229.054199" y="807.4139"/>
+  <use xlink:href="#glyph0-9" x="240.497613" y="807.4139"/>
+  <use xlink:href="#glyph0-3" x="254.507758" y="807.4139"/>
+  <use xlink:href="#glyph0-30" x="276.656196" y="807.4139"/>
+  <use xlink:href="#glyph0-15" x="299.507758" y="807.4139"/>
+  <use xlink:href="#glyph0-10" x="322.324056" y="807.4139"/>
+  <use xlink:href="#glyph0-9" x="332.325955" y="807.4139"/>
+  <use xlink:href="#glyph0-3" x="346.3361" y="807.4139"/>
+  <use xlink:href="#glyph0-25" x="368.484538" y="807.4139"/>
+  <use xlink:href="#glyph0-31" x="391.3361" y="807.4139"/>
+</g>
+<path style="fill-rule:evenodd;fill:rgb(0%,50.196081%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 7 7.5 L 11.5 7.5 L 11.5 6 L 16 9 L 11.5 12 L 11.5 10.5 L 7 10.5 Z M 7 7.5 " transform="matrix(20,0,0,20,-19,1)"/>
+<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 7 7.5 L 11.5 7.5 L 11.5 6 L 16 9 L 11.5 12 L 11.5 10.5 L 7 10.5 Z M 7 7.5 " transform="matrix(20,0,0,20,-19,1)"/>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-32" x="19.242188" y="48.359212"/>
+  <use xlink:href="#glyph0-9" x="35.941678" y="48.359212"/>
+  <use xlink:href="#glyph0-15" x="50.742567" y="48.359212"/>
+  <use xlink:href="#glyph0-5" x="73.558865" y="48.359212"/>
+  <use xlink:href="#glyph0-2" x="92.314833" y="48.359212"/>
+  <use xlink:href="#glyph0-3" x="106.429959" y="48.359212"/>
+  <use xlink:href="#glyph0-25" x="128.578396" y="48.359212"/>
+  <use xlink:href="#glyph0-6" x="151.429959" y="48.359212"/>
+  <use xlink:href="#glyph0-21" x="162.873372" y="48.359212"/>
+  <use xlink:href="#glyph0-33" x="187.50038" y="48.359212"/>
+  <use xlink:href="#glyph0-29" x="212.162381" y="48.359212"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-22" x="57.542969" y="93.515462"/>
+  <use xlink:href="#glyph0-16" x="92.611328" y="93.515462"/>
+  <use xlink:href="#glyph0-5" x="114.671875" y="93.515462"/>
+  <use xlink:href="#glyph0-2" x="133.427843" y="93.515462"/>
+  <use xlink:href="#glyph0-3" x="147.542969" y="93.515462"/>
+  <use xlink:href="#glyph0-9" x="169.691406" y="93.515462"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-10" x="40.726562" y="138.671712"/>
+  <use xlink:href="#glyph0-23" x="50.728461" y="138.671712"/>
+  <use xlink:href="#glyph0-2" x="73.544759" y="138.671712"/>
+  <use xlink:href="#glyph0-3" x="87.659885" y="138.671712"/>
+  <use xlink:href="#glyph0-9" x="109.808322" y="138.671712"/>
+  <use xlink:href="#glyph0-11" x="124.609212" y="138.671712"/>
+  <use xlink:href="#glyph0-16" x="137.283095" y="138.671712"/>
+  <use xlink:href="#glyph0-26" x="159.343641" y="138.671712"/>
+  <use xlink:href="#glyph0-3" x="179.136664" y="138.671712"/>
+</g>
+<path style="fill-rule:evenodd;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 28 7.5 L 33 7.5 L 33 6 L 38 9 L 33 12 L 33 10.5 L 28 10.5 Z M 28 7.5 " transform="matrix(20,0,0,20,-19,1)"/>
+<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 28 7.5 L 33 7.5 L 33 6 L 38 9 L 33 12 L 33 10.5 L 28 10.5 Z M 28 7.5 " transform="matrix(20,0,0,20,-19,1)"/>
+<path style="fill-rule:evenodd;fill:rgb(100%,100%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 38 3 L 50 3 L 50 15 L 38 15 Z M 38 3 " transform="matrix(20,0,0,20,-19,1)"/>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-34" x="771.625" y="170.937337"/>
+  <use xlink:href="#glyph0-23" x="797.974555" y="170.937337"/>
+  <use xlink:href="#glyph0-2" x="820.790853" y="170.937337"/>
+  <use xlink:href="#glyph0-9" x="834.905979" y="170.937337"/>
+  <use xlink:href="#glyph0-15" x="849.706868" y="170.937337"/>
+  <use xlink:href="#glyph0-5" x="872.523166" y="170.937337"/>
+  <use xlink:href="#glyph0-2" x="891.279134" y="170.937337"/>
+  <use xlink:href="#glyph0-3" x="905.39426" y="170.937337"/>
+  <use xlink:href="#glyph0-25" x="927.542697" y="170.937337"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-21" x="778.207031" y="216.093587"/>
+  <use xlink:href="#glyph0-33" x="802.834039" y="216.093587"/>
+  <use xlink:href="#glyph0-29" x="827.496039" y="216.093587"/>
+  <use xlink:href="#glyph0-6" x="838.113173" y="216.093587"/>
+  <use xlink:href="#glyph0-5" x="849.556586" y="216.093587"/>
+  <use xlink:href="#glyph0-17" x="868.312554" y="216.093587"/>
+  <use xlink:href="#glyph0-16" x="878.314453" y="216.093587"/>
+  <use xlink:href="#glyph0-8" x="900.375" y="216.093587"/>
+  <use xlink:href="#glyph0-3" x="921.679796" y="216.093587"/>
+</g>
+<path style="fill-rule:evenodd;fill:rgb(100%,100%,81.176472%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 22 3 L 28 3 L 28 15 L 22 15 Z M 22 3 " transform="matrix(20,0,0,20,-19,1)"/>
+<path style="fill-rule:evenodd;fill:rgb(56.470591%,93.333334%,56.470591%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 16 3 L 22 3 L 22 15 L 16 15 Z M 16 3 " transform="matrix(20,0,0,20,-19,1)"/>
+<path style="fill:none;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 16 3 L 28 3 L 28 15 L 16 15 Z M 16 3 " transform="matrix(20,0,0,20,-19,1)"/>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-35" x="338.949219" y="170.937337"/>
+  <use xlink:href="#glyph0-15" x="363.646484" y="170.937337"/>
+  <use xlink:href="#glyph0-5" x="386.462782" y="170.937337"/>
+  <use xlink:href="#glyph0-6" x="405.21875" y="170.937337"/>
+  <use xlink:href="#glyph0-36" x="416.662164" y="170.937337"/>
+  <use xlink:href="#glyph0-16" x="434.064507" y="170.937337"/>
+  <use xlink:href="#glyph0-15" x="456.125054" y="170.937337"/>
+  <use xlink:href="#glyph0-17" x="478.941352" y="170.937337"/>
+  <use xlink:href="#glyph0-2" x="488.943251" y="170.937337"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-29" x="353.8125" y="216.093587"/>
+  <use xlink:href="#glyph0-5" x="364.429633" y="216.093587"/>
+  <use xlink:href="#glyph0-7" x="383.185601" y="216.093587"/>
+  <use xlink:href="#glyph0-17" x="405.210883" y="216.093587"/>
+  <use xlink:href="#glyph0-16" x="415.212782" y="216.093587"/>
+  <use xlink:href="#glyph0-2" x="437.273329" y="216.093587"/>
+  <use xlink:href="#glyph0-7" x="451.388455" y="216.093587"/>
+  <use xlink:href="#glyph0-9" x="473.413737" y="216.093587"/>
+</g>
+</g>
+</svg>
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axixbar.dia b/verilog/rtl/softshell/third_party/wb2axip/doc/axixbar.dia
new file mode 100644
index 0000000..8ff7a66
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axixbar.dia
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axixbar.png b/verilog/rtl/softshell/third_party/wb2axip/doc/axixbar.png
new file mode 100644
index 0000000..3d25d54
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axixbar.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/axixbarx2-latency.png b/verilog/rtl/softshell/third_party/wb2axip/doc/axixbarx2-latency.png
new file mode 100644
index 0000000..ea5eedf
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/axixbarx2-latency.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/busprops.pdf b/verilog/rtl/softshell/third_party/wb2axip/doc/busprops.pdf
new file mode 100644
index 0000000..c325ada
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/busprops.pdf
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/demo2019.pdf b/verilog/rtl/softshell/third_party/wb2axip/doc/demo2019.pdf
new file mode 100644
index 0000000..3e861d9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/demo2019.pdf
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-bad-wstrb.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-bad-wstrb.json
new file mode 100644
index 0000000..5e337a3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-bad-wstrb.json
@@ -0,0 +1,16 @@
+{signal: [
+  {name: 'clk',     wave: 'P...'},
+  {name: 'rst',     wave: '01..'},
+  {},
+  {name: 'wb_cyc',   wave: '0.1.'},
+  {name: 'wb_stb',   wave: '0.10'},
+  {name: 'wb_we',    wave: 'x.1x'},
+  {name: 'wb_adr[31:0]',   wave: 'x.3x', data: ['h..3']},
+  {name: 'wb_sel[3:0]',   wave: 'x.3x', data: ['1']},
+  {name: 'wb_stall', wave: 'x.0x'},
+  {},
+  {name: 'axi_avalid', wave: '0..1'},
+  {name: 'axi_awaddr[31:0]', wave: 'x..3', data: ['h..3']},
+  {name: 'axi_wvalid', wave: '0..1'},
+  {name: 'axi_wstrb[3:0]',  wave: 'x..3', data: ['1']}
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-bad-wstrb.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-bad-wstrb.png
new file mode 100644
index 0000000..d080070
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-bad-wstrb.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-bad-wstrb.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-bad-wstrb.svg
new file mode 100644
index 0000000..2d41e35
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-bad-wstrb.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="420" width="320" viewBox="0 0 320 420" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(140.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,420" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_1_0" d="m 40,0 0,420" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_2_0" d="m 80,0 0,420" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_3_0" d="m 120,0 0,420" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_4_0" d="m 160,0 0,420" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>clk</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#Pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#Pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#Pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#Pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>rst</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"/></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>wb_cyc</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>wb_stb</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1m0" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>wb_we</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xm1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1mx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>wb_adr[31:0]</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-3" transform="translate(80)"/><use xlink:href="#vvv-3" transform="translate(100)"/><use xlink:href="#vmx-3" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><text x="106" y="15" text-anchor="middle" xml:space="preserve"><tspan>h..3</tspan></text></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>wb_sel[3:0]</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-3" transform="translate(80)"/><use xlink:href="#vvv-3" transform="translate(100)"/><use xlink:href="#vmx-3" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><text x="106" y="15" text-anchor="middle" xml:space="preserve"><tspan>1</tspan></text></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>wb_stall</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xm0" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0mx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"/></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>axi_avalid</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0m1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>axi_awaddr[31:0]</tspan></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xmv-3" transform="translate(120)"/><use xlink:href="#vvv-3" transform="translate(140)"/><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>h..3</tspan></text></g></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>axi_wvalid</tspan></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0m1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/></g></g><g id="wavelane_13_0" transform="translate(0,395)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>axi_wstrb[3:0]</tspan></text><g id="wavelane_draw_13_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xmv-3" transform="translate(120)"/><use xlink:href="#vvv-3" transform="translate(140)"/><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>1</tspan></text></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/><g id="wavegap_13_0" transform="translate(0,395)"/></g></g><g id="groups_0">g</g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-fault-isolator.dia b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-fault-isolator.dia
new file mode 100644
index 0000000..702c2f7
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-fault-isolator.dia
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-gpio-reads.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-gpio-reads.json
new file mode 100644
index 0000000..2007065
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-gpio-reads.json
@@ -0,0 +1,9 @@
+{signal: [
+  {name: 'S_AXI_ACLK',   wave: 'p..............'},
+  {name: 'S_AXI_ARESETN',wave: '0.1............'},
+  {},
+  {name: 'S_AXI_ARVALID',wave: '0..1....x1....x'},
+  {name: 'S_AXI_ARREADY',wave: '0......10....10'},
+  {},
+  {name: 'S_AXI_RVALID', wave: '0.......10....1'},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-gpio-reads.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-gpio-reads.png
new file mode 100644
index 0000000..8b98908
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-gpio-reads.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-gpio-writes.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-gpio-writes.json
new file mode 100644
index 0000000..f59ee8f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-gpio-writes.json
@@ -0,0 +1,14 @@
+{signal: [
+  {name: 'S_AXI_ACLK',   wave: 'p....................'},
+  {name: 'S_AXI_ARESETN',wave: '0.1..................'},
+  {},
+  {name: 'S_AXI_AWVALID',wave: '0..1................x'},
+  {name: 'S_AXI_AWREADY',wave: '0......10....10....10', data: ['A','B','C','D','E','F','G','H']},
+  {},
+  {name: 'S_AXI_WVALID', wave: '0..1................x'},
+  {name: 'S_AXI_WREADY', wave: '0......10....10....10', data: ['A','B','C','D','E','F','G','H']},
+  {name: 'S_AXI_WDATA',  wave: 'x..0....3.....4.....x'},
+  {},
+  {name: 'S_AXI_BVALID', wave: '0......10.....10....1'},
+  {name: 'o_gpio',       wave: 'x.....0.....3......4.'}
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-gpio-writes.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-gpio-writes.png
new file mode 100644
index 0000000..8aa8d6c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-gpio-writes.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-gpio-writes.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-gpio-writes.svg
new file mode 100644
index 0000000..33df9ac
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-gpio-writes.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="360" width="1020" viewBox="0 0 1020 360" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_1_0" d="m 40,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_2_0" d="m 80,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_3_0" d="m 120,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_4_0" d="m 160,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_5_0" d="m 200,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_6_0" d="m 240,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_7_0" d="m 280,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_8_0" d="m 320,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_9_0" d="m 360,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_10_0" d="m 400,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_11_0" d="m 440,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_12_0" d="m 480,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_13_0" d="m 520,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_14_0" d="m 560,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_15_0" d="m 600,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_16_0" d="m 640,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_17_0" d="m 680,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_18_0" d="m 720,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_19_0" d="m 760,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_20_0" d="m 800,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_21_0" d="m 840,0 0,360" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/><use xlink:href="#pclk" transform="translate(200)"/><use xlink:href="#nclk" transform="translate(220)"/><use xlink:href="#pclk" transform="translate(240)"/><use xlink:href="#nclk" transform="translate(260)"/><use xlink:href="#pclk" transform="translate(280)"/><use xlink:href="#nclk" transform="translate(300)"/><use xlink:href="#pclk" transform="translate(320)"/><use xlink:href="#nclk" transform="translate(340)"/><use xlink:href="#pclk" transform="translate(360)"/><use xlink:href="#nclk" transform="translate(380)"/><use xlink:href="#pclk" transform="translate(400)"/><use xlink:href="#nclk" transform="translate(420)"/><use xlink:href="#pclk" transform="translate(440)"/><use xlink:href="#nclk" transform="translate(460)"/><use xlink:href="#pclk" transform="translate(480)"/><use xlink:href="#nclk" transform="translate(500)"/><use xlink:href="#pclk" transform="translate(520)"/><use xlink:href="#nclk" transform="translate(540)"/><use xlink:href="#pclk" transform="translate(560)"/><use xlink:href="#nclk" transform="translate(580)"/><use xlink:href="#pclk" transform="translate(600)"/><use xlink:href="#nclk" transform="translate(620)"/><use xlink:href="#pclk" transform="translate(640)"/><use xlink:href="#nclk" transform="translate(660)"/><use xlink:href="#pclk" transform="translate(680)"/><use xlink:href="#nclk" transform="translate(700)"/><use xlink:href="#pclk" transform="translate(720)"/><use xlink:href="#nclk" transform="translate(740)"/><use xlink:href="#pclk" transform="translate(760)"/><use xlink:href="#nclk" transform="translate(780)"/><use xlink:href="#pclk" transform="translate(800)"/><use xlink:href="#nclk" transform="translate(820)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#111" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"/></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWVALID</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0m1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#1mx" transform="translate(800)"/><use xlink:href="#xxx" transform="translate(820)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWREADY</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#0m1" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#1m0" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#0m1" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#1m0" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#0m1" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#1m0" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"/></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WVALID</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0m1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#1mx" transform="translate(800)"/><use xlink:href="#xxx" transform="translate(820)"/></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WREADY</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#0m1" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#1m0" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#0m1" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#1m0" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#0m1" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#1m0" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WDATA</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xm0" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#0mv-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vvv-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vvv-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vvv-3" transform="translate(440)"/><use xlink:href="#vvv-3" transform="translate(460)"/><use xlink:href="#vvv-3" transform="translate(480)"/><use xlink:href="#vvv-3" transform="translate(500)"/><use xlink:href="#vvv-3" transform="translate(520)"/><use xlink:href="#vvv-3" transform="translate(540)"/><use xlink:href="#vmv-3-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vvv-4" transform="translate(600)"/><use xlink:href="#vvv-4" transform="translate(620)"/><use xlink:href="#vvv-4" transform="translate(640)"/><use xlink:href="#vvv-4" transform="translate(660)"/><use xlink:href="#vvv-4" transform="translate(680)"/><use xlink:href="#vvv-4" transform="translate(700)"/><use xlink:href="#vvv-4" transform="translate(720)"/><use xlink:href="#vvv-4" transform="translate(740)"/><use xlink:href="#vvv-4" transform="translate(760)"/><use xlink:href="#vvv-4" transform="translate(780)"/><use xlink:href="#vmx-4" transform="translate(800)"/><use xlink:href="#xxx" transform="translate(820)"/></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"/></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_BVALID</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#0m1" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#1m0" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#0m1" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#1m0" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#0m1" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>o_gpio</tspan></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xm0" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#0mv-3" transform="translate(480)"/><use xlink:href="#vvv-3" transform="translate(500)"/><use xlink:href="#vvv-3" transform="translate(520)"/><use xlink:href="#vvv-3" transform="translate(540)"/><use xlink:href="#vvv-3" transform="translate(560)"/><use xlink:href="#vvv-3" transform="translate(580)"/><use xlink:href="#vvv-3" transform="translate(600)"/><use xlink:href="#vvv-3" transform="translate(620)"/><use xlink:href="#vvv-3" transform="translate(640)"/><use xlink:href="#vvv-3" transform="translate(660)"/><use xlink:href="#vvv-3" transform="translate(680)"/><use xlink:href="#vvv-3" transform="translate(700)"/><use xlink:href="#vvv-3" transform="translate(720)"/><use xlink:href="#vvv-3" transform="translate(740)"/><use xlink:href="#vmv-3-4" transform="translate(760)"/><use xlink:href="#vvv-4" transform="translate(780)"/><use xlink:href="#vvv-4" transform="translate(800)"/><use xlink:href="#vvv-4" transform="translate(820)"/></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/></g></g><g id="groups_0">g</g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-handshake-ref.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-handshake-ref.png
new file mode 100644
index 0000000..36dcde2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-handshake-ref.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-in-everything.dia b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-in-everything.dia
new file mode 100644
index 0000000..a6b7c3f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-in-everything.dia
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-in-everything.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-in-everything.svg
new file mode 100644
index 0000000..db2ece3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-in-everything.svg
@@ -0,0 +1,437 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="843pt" height="543pt" viewBox="0 0 843 543" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 1.796875 6.390625 L 1.796875 -25.46875 L 19.859375 -25.46875 L 19.859375 6.390625 Z M 3.828125 4.375 L 17.84375 4.375 L 17.84375 -23.4375 L 3.828125 -23.4375 Z M 3.828125 4.375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 23.265625 -24.3125 L 23.265625 -20.546875 C 22.066406 -21.660156 20.785156 -22.492188 19.421875 -23.046875 C 18.066406 -23.609375 16.625 -23.890625 15.09375 -23.890625 C 12.082031 -23.890625 9.773438 -22.96875 8.171875 -21.125 C 6.578125 -19.28125 5.78125 -16.617188 5.78125 -13.140625 C 5.78125 -9.671875 6.578125 -7.015625 8.171875 -5.171875 C 9.773438 -3.335938 12.082031 -2.421875 15.09375 -2.421875 C 16.625 -2.421875 18.066406 -2.695312 19.421875 -3.25 C 20.785156 -3.800781 22.066406 -4.632812 23.265625 -5.75 L 23.265625 -2.03125 C 22.015625 -1.1875 20.691406 -0.550781 19.296875 -0.125 C 17.910156 0.300781 16.441406 0.515625 14.890625 0.515625 C 10.898438 0.515625 7.757812 -0.703125 5.46875 -3.140625 C 3.175781 -5.585938 2.03125 -8.921875 2.03125 -13.140625 C 2.03125 -17.367188 3.175781 -20.703125 5.46875 -23.140625 C 7.757812 -25.585938 10.898438 -26.8125 14.890625 -26.8125 C 16.460938 -26.8125 17.945312 -26.601562 19.34375 -26.1875 C 20.738281 -25.769531 22.046875 -25.144531 23.265625 -24.3125 Z M 23.265625 -24.3125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 7.109375 -23.40625 L 7.109375 -13.515625 L 11.59375 -13.515625 C 13.25 -13.515625 14.53125 -13.941406 15.4375 -14.796875 C 16.34375 -15.660156 16.796875 -16.882812 16.796875 -18.46875 C 16.796875 -20.039062 16.34375 -21.253906 15.4375 -22.109375 C 14.53125 -22.972656 13.25 -23.40625 11.59375 -23.40625 Z M 3.546875 -26.328125 L 11.59375 -26.328125 C 14.539062 -26.328125 16.769531 -25.660156 18.28125 -24.328125 C 19.789062 -22.992188 20.546875 -21.039062 20.546875 -18.46875 C 20.546875 -15.863281 19.789062 -13.894531 18.28125 -12.5625 C 16.769531 -11.238281 14.539062 -10.578125 11.59375 -10.578125 L 7.109375 -10.578125 L 7.109375 0 L 3.546875 0 Z M 3.546875 -26.328125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 3.140625 -26.328125 L 6.71875 -26.328125 L 6.71875 -10.34375 C 6.71875 -7.519531 7.226562 -5.484375 8.25 -4.234375 C 9.28125 -2.992188 10.941406 -2.375 13.234375 -2.375 C 15.515625 -2.375 17.164062 -2.992188 18.1875 -4.234375 C 19.207031 -5.484375 19.71875 -7.519531 19.71875 -10.34375 L 19.71875 -26.328125 L 23.296875 -26.328125 L 23.296875 -9.890625 C 23.296875 -6.460938 22.445312 -3.867188 20.75 -2.109375 C 19.050781 -0.359375 16.546875 0.515625 13.234375 0.515625 C 9.898438 0.515625 7.382812 -0.359375 5.6875 -2.109375 C 3.988281 -3.867188 3.140625 -6.460938 3.140625 -9.890625 Z M 3.140625 -26.328125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 12.34375 -22.828125 L 7.515625 -9.71875 L 17.203125 -9.71875 Z M 10.34375 -26.328125 L 14.375 -26.328125 L 24.40625 0 L 20.703125 0 L 18.3125 -6.75 L 6.4375 -6.75 L 4.046875 0 L 0.28125 0 Z M 10.34375 -26.328125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 2.28125 -26.328125 L 6.109375 -26.328125 L 12.640625 -16.546875 L 19.234375 -26.328125 L 23.046875 -26.328125 L 14.59375 -13.6875 L 23.625 0 L 19.796875 0 L 12.375 -11.203125 L 4.921875 0 L 1.078125 0 L 10.484375 -14.0625 Z M 2.28125 -26.328125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 3.546875 -26.328125 L 7.109375 -26.328125 L 7.109375 0 L 3.546875 0 Z M 3.546875 -26.328125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-7">
+<path style="stroke:none;" d=""/>
+</symbol>
+<symbol overflow="visible" id="glyph0-8">
+<path style="stroke:none;" d="M 19.828125 -11.921875 L 19.828125 0 L 16.578125 0 L 16.578125 -11.8125 C 16.578125 -13.6875 16.210938 -15.085938 15.484375 -16.015625 C 14.753906 -16.941406 13.660156 -17.40625 12.203125 -17.40625 C 10.453125 -17.40625 9.070312 -16.847656 8.0625 -15.734375 C 7.050781 -14.617188 6.546875 -13.097656 6.546875 -11.171875 L 6.546875 0 L 3.28125 0 L 3.28125 -19.75 L 6.546875 -19.75 L 6.546875 -16.6875 C 7.316406 -17.875 8.226562 -18.757812 9.28125 -19.34375 C 10.332031 -19.9375 11.546875 -20.234375 12.921875 -20.234375 C 15.191406 -20.234375 16.910156 -19.53125 18.078125 -18.125 C 19.242188 -16.71875 19.828125 -14.648438 19.828125 -11.921875 Z M 19.828125 -11.921875 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-9">
+<path style="stroke:none;" d="M 6.609375 -25.359375 L 6.609375 -19.75 L 13.296875 -19.75 L 13.296875 -17.234375 L 6.609375 -17.234375 L 6.609375 -6.515625 C 6.609375 -4.898438 6.828125 -3.863281 7.265625 -3.40625 C 7.710938 -2.945312 8.613281 -2.71875 9.96875 -2.71875 L 13.296875 -2.71875 L 13.296875 0 L 9.96875 0 C 7.457031 0 5.722656 -0.460938 4.765625 -1.390625 C 3.816406 -2.328125 3.34375 -4.035156 3.34375 -6.515625 L 3.34375 -17.234375 L 0.96875 -17.234375 L 0.96875 -19.75 L 3.34375 -19.75 L 3.34375 -25.359375 Z M 6.609375 -25.359375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-10">
+<path style="stroke:none;" d="M 20.296875 -10.6875 L 20.296875 -9.109375 L 5.375 -9.109375 C 5.519531 -6.867188 6.191406 -5.160156 7.390625 -3.984375 C 8.597656 -2.816406 10.28125 -2.234375 12.4375 -2.234375 C 13.6875 -2.234375 14.894531 -2.382812 16.0625 -2.6875 C 17.226562 -3 18.390625 -3.460938 19.546875 -4.078125 L 19.546875 -1 C 18.378906 -0.507812 17.179688 -0.132812 15.953125 0.125 C 14.734375 0.382812 13.492188 0.515625 12.234375 0.515625 C 9.085938 0.515625 6.59375 -0.398438 4.75 -2.234375 C 2.914062 -4.066406 2 -6.550781 2 -9.6875 C 2 -12.914062 2.867188 -15.476562 4.609375 -17.375 C 6.359375 -19.28125 8.710938 -20.234375 11.671875 -20.234375 C 14.328125 -20.234375 16.425781 -19.375 17.96875 -17.65625 C 19.519531 -15.945312 20.296875 -13.625 20.296875 -10.6875 Z M 17.0625 -11.640625 C 17.03125 -13.421875 16.53125 -14.835938 15.5625 -15.890625 C 14.59375 -16.953125 13.3125 -17.484375 11.71875 -17.484375 C 9.90625 -17.484375 8.453125 -16.96875 7.359375 -15.9375 C 6.273438 -14.914062 5.648438 -13.476562 5.484375 -11.625 Z M 17.0625 -11.640625 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-11">
+<path style="stroke:none;" d="M 14.859375 -16.71875 C 14.492188 -16.9375 14.09375 -17.09375 13.65625 -17.1875 C 13.226562 -17.289062 12.753906 -17.34375 12.234375 -17.34375 C 10.398438 -17.34375 8.992188 -16.742188 8.015625 -15.546875 C 7.035156 -14.359375 6.546875 -12.644531 6.546875 -10.40625 L 6.546875 0 L 3.28125 0 L 3.28125 -19.75 L 6.546875 -19.75 L 6.546875 -16.6875 C 7.222656 -17.882812 8.109375 -18.773438 9.203125 -19.359375 C 10.296875 -19.941406 11.625 -20.234375 13.1875 -20.234375 C 13.414062 -20.234375 13.664062 -20.21875 13.9375 -20.1875 C 14.207031 -20.15625 14.503906 -20.113281 14.828125 -20.0625 Z M 14.859375 -16.71875 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-12">
+<path style="stroke:none;" d="M 17.625 -19 L 17.625 -15.96875 C 16.707031 -16.46875 15.785156 -16.84375 14.859375 -17.09375 C 13.929688 -17.351562 13 -17.484375 12.0625 -17.484375 C 9.957031 -17.484375 8.320312 -16.8125 7.15625 -15.46875 C 6 -14.132812 5.421875 -12.265625 5.421875 -9.859375 C 5.421875 -7.453125 6 -5.578125 7.15625 -4.234375 C 8.320312 -2.898438 9.957031 -2.234375 12.0625 -2.234375 C 13 -2.234375 13.929688 -2.359375 14.859375 -2.609375 C 15.785156 -2.867188 16.707031 -3.25 17.625 -3.75 L 17.625 -0.765625 C 16.71875 -0.335938 15.78125 -0.0195312 14.8125 0.1875 C 13.84375 0.40625 12.8125 0.515625 11.71875 0.515625 C 8.738281 0.515625 6.375 -0.414062 4.625 -2.28125 C 2.875 -4.15625 2 -6.679688 2 -9.859375 C 2 -13.078125 2.878906 -15.609375 4.640625 -17.453125 C 6.410156 -19.304688 8.835938 -20.234375 11.921875 -20.234375 C 12.921875 -20.234375 13.894531 -20.128906 14.84375 -19.921875 C 15.800781 -19.710938 16.726562 -19.40625 17.625 -19 Z M 17.625 -19 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-13">
+<path style="stroke:none;" d="M 11.0625 -17.484375 C 9.320312 -17.484375 7.945312 -16.800781 6.9375 -15.4375 C 5.925781 -14.082031 5.421875 -12.222656 5.421875 -9.859375 C 5.421875 -7.492188 5.921875 -5.628906 6.921875 -4.265625 C 7.929688 -2.910156 9.3125 -2.234375 11.0625 -2.234375 C 12.789062 -2.234375 14.160156 -2.914062 15.171875 -4.28125 C 16.179688 -5.644531 16.6875 -7.503906 16.6875 -9.859375 C 16.6875 -12.203125 16.179688 -14.054688 15.171875 -15.421875 C 14.160156 -16.796875 12.789062 -17.484375 11.0625 -17.484375 Z M 11.0625 -20.234375 C 13.882812 -20.234375 16.097656 -19.316406 17.703125 -17.484375 C 19.316406 -15.648438 20.125 -13.109375 20.125 -9.859375 C 20.125 -6.628906 19.316406 -4.09375 17.703125 -2.25 C 16.097656 -0.40625 13.882812 0.515625 11.0625 0.515625 C 8.226562 0.515625 6.007812 -0.40625 4.40625 -2.25 C 2.800781 -4.09375 2 -6.628906 2 -9.859375 C 2 -13.109375 2.800781 -15.648438 4.40625 -17.484375 C 6.007812 -19.316406 8.226562 -20.234375 11.0625 -20.234375 Z M 11.0625 -20.234375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-14">
+<path style="stroke:none;" d="M 3.546875 -26.328125 L 8.859375 -26.328125 L 15.578125 -8.40625 L 22.328125 -26.328125 L 27.640625 -26.328125 L 27.640625 0 L 24.171875 0 L 24.171875 -23.125 L 17.375 -5.0625 L 13.796875 -5.0625 L 7 -23.125 L 7 0 L 3.546875 0 Z M 3.546875 -26.328125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-15">
+<path style="stroke:none;" d="M 3.546875 -26.328125 L 20.203125 -26.328125 L 20.203125 -23.34375 L 7.109375 -23.34375 L 7.109375 -15.546875 L 19.65625 -15.546875 L 19.65625 -12.546875 L 7.109375 -12.546875 L 7.109375 -3 L 20.515625 -3 L 20.515625 0 L 3.546875 0 Z M 3.546875 -26.328125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-16">
+<path style="stroke:none;" d="M 14.234375 -23.921875 C 11.648438 -23.921875 9.59375 -22.957031 8.0625 -21.03125 C 6.539062 -19.101562 5.78125 -16.472656 5.78125 -13.140625 C 5.78125 -9.828125 6.539062 -7.203125 8.0625 -5.265625 C 9.59375 -3.335938 11.648438 -2.375 14.234375 -2.375 C 16.816406 -2.375 18.863281 -3.335938 20.375 -5.265625 C 21.894531 -7.203125 22.65625 -9.828125 22.65625 -13.140625 C 22.65625 -16.472656 21.894531 -19.101562 20.375 -21.03125 C 18.863281 -22.957031 16.816406 -23.921875 14.234375 -23.921875 Z M 14.234375 -26.8125 C 17.929688 -26.8125 20.882812 -25.570312 23.09375 -23.09375 C 25.300781 -20.625 26.40625 -17.304688 26.40625 -13.140625 C 26.40625 -8.992188 25.300781 -5.679688 23.09375 -3.203125 C 20.882812 -0.722656 17.929688 0.515625 14.234375 0.515625 C 10.523438 0.515625 7.5625 -0.71875 5.34375 -3.1875 C 3.132812 -5.65625 2.03125 -8.972656 2.03125 -13.140625 C 2.03125 -17.304688 3.132812 -20.625 5.34375 -23.09375 C 7.5625 -25.570312 10.523438 -26.8125 14.234375 -26.8125 Z M 14.234375 -26.8125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-17">
+<path style="stroke:none;" d="M 16.03125 -12.34375 C 16.800781 -12.082031 17.546875 -11.53125 18.265625 -10.6875 C 18.984375 -9.84375 19.707031 -8.679688 20.4375 -7.203125 L 24.0625 0 L 20.234375 0 L 16.859375 -6.75 C 15.992188 -8.519531 15.148438 -9.691406 14.328125 -10.265625 C 13.515625 -10.835938 12.398438 -11.125 10.984375 -11.125 L 7.109375 -11.125 L 7.109375 0 L 3.546875 0 L 3.546875 -26.328125 L 11.59375 -26.328125 C 14.601562 -26.328125 16.847656 -25.695312 18.328125 -24.4375 C 19.804688 -23.1875 20.546875 -21.289062 20.546875 -18.75 C 20.546875 -17.09375 20.160156 -15.71875 19.390625 -14.625 C 18.617188 -13.53125 17.5 -12.769531 16.03125 -12.34375 Z M 7.109375 -23.40625 L 7.109375 -14.0625 L 11.59375 -14.0625 C 13.3125 -14.0625 14.609375 -14.457031 15.484375 -15.25 C 16.359375 -16.039062 16.796875 -17.207031 16.796875 -18.75 C 16.796875 -20.289062 16.359375 -21.453125 15.484375 -22.234375 C 14.609375 -23.015625 13.3125 -23.40625 11.59375 -23.40625 Z M 7.109375 -23.40625 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-18">
+<path style="stroke:none;" d="M -0.078125 -26.328125 L 3.75 -26.328125 L 11.0625 -15.5 L 18.3125 -26.328125 L 22.140625 -26.328125 L 12.828125 -12.546875 L 12.828125 0 L 9.25 0 L 9.25 -12.546875 Z M -0.078125 -26.328125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-19">
+<path style="stroke:none;" d="M 16 -19.171875 L 16 -16.109375 C 15.082031 -16.578125 14.128906 -16.925781 13.140625 -17.15625 C 12.148438 -17.394531 11.128906 -17.515625 10.078125 -17.515625 C 8.460938 -17.515625 7.25 -17.265625 6.4375 -16.765625 C 5.632812 -16.273438 5.234375 -15.535156 5.234375 -14.546875 C 5.234375 -13.796875 5.519531 -13.207031 6.09375 -12.78125 C 6.675781 -12.351562 7.835938 -11.941406 9.578125 -11.546875 L 10.6875 -11.3125 C 12.988281 -10.8125 14.625 -10.109375 15.59375 -9.203125 C 16.570312 -8.304688 17.0625 -7.054688 17.0625 -5.453125 C 17.0625 -3.617188 16.332031 -2.164062 14.875 -1.09375 C 13.425781 -0.0195312 11.429688 0.515625 8.890625 0.515625 C 7.828125 0.515625 6.722656 0.410156 5.578125 0.203125 C 4.429688 -0.00390625 3.222656 -0.3125 1.953125 -0.71875 L 1.953125 -4.078125 C 3.148438 -3.453125 4.332031 -2.984375 5.5 -2.671875 C 6.664062 -2.359375 7.816406 -2.203125 8.953125 -2.203125 C 10.484375 -2.203125 11.660156 -2.460938 12.484375 -2.984375 C 13.304688 -3.515625 13.71875 -4.253906 13.71875 -5.203125 C 13.71875 -6.085938 13.421875 -6.765625 12.828125 -7.234375 C 12.234375 -7.703125 10.929688 -8.15625 8.921875 -8.59375 L 7.796875 -8.859375 C 5.785156 -9.273438 4.332031 -9.921875 3.4375 -10.796875 C 2.539062 -11.679688 2.09375 -12.882812 2.09375 -14.40625 C 2.09375 -16.269531 2.75 -17.707031 4.0625 -18.71875 C 5.382812 -19.726562 7.257812 -20.234375 9.6875 -20.234375 C 10.882812 -20.234375 12.007812 -20.144531 13.0625 -19.96875 C 14.125 -19.789062 15.101562 -19.523438 16 -19.171875 Z M 16 -19.171875 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-20">
+<path style="stroke:none;" d="M 7.109375 -23.40625 L 7.109375 -2.921875 L 11.40625 -2.921875 C 15.039062 -2.921875 17.703125 -3.742188 19.390625 -5.390625 C 21.078125 -7.035156 21.921875 -9.632812 21.921875 -13.1875 C 21.921875 -16.71875 21.078125 -19.300781 19.390625 -20.9375 C 17.703125 -22.582031 15.039062 -23.40625 11.40625 -23.40625 Z M 3.546875 -26.328125 L 10.859375 -26.328125 C 15.960938 -26.328125 19.707031 -25.265625 22.09375 -23.140625 C 24.488281 -21.023438 25.6875 -17.707031 25.6875 -13.1875 C 25.6875 -8.65625 24.484375 -5.320312 22.078125 -3.1875 C 19.679688 -1.0625 15.941406 0 10.859375 0 L 3.546875 0 Z M 3.546875 -26.328125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-21">
+<path style="stroke:none;" d="M 3.40625 -19.75 L 6.65625 -19.75 L 6.65625 0 L 3.40625 0 Z M 3.40625 -27.453125 L 6.65625 -27.453125 L 6.65625 -23.34375 L 3.40625 -23.34375 Z M 3.40625 -27.453125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-22">
+<path style="stroke:none;" d="M 16.40625 -10.109375 C 16.40625 -12.460938 15.921875 -14.285156 14.953125 -15.578125 C 13.984375 -16.867188 12.617188 -17.515625 10.859375 -17.515625 C 9.117188 -17.515625 7.765625 -16.867188 6.796875 -15.578125 C 5.828125 -14.285156 5.34375 -12.460938 5.34375 -10.109375 C 5.34375 -7.765625 5.828125 -5.945312 6.796875 -4.65625 C 7.765625 -3.363281 9.117188 -2.71875 10.859375 -2.71875 C 12.617188 -2.71875 13.984375 -3.363281 14.953125 -4.65625 C 15.921875 -5.945312 16.40625 -7.765625 16.40625 -10.109375 Z M 19.65625 -2.453125 C 19.65625 0.910156 18.90625 3.410156 17.40625 5.046875 C 15.914062 6.691406 13.628906 7.515625 10.546875 7.515625 C 9.410156 7.515625 8.332031 7.425781 7.3125 7.25 C 6.300781 7.082031 5.320312 6.820312 4.375 6.46875 L 4.375 3.3125 C 5.320312 3.832031 6.257812 4.210938 7.1875 4.453125 C 8.125 4.703125 9.070312 4.828125 10.03125 4.828125 C 12.164062 4.828125 13.757812 4.269531 14.8125 3.15625 C 15.875 2.050781 16.40625 0.375 16.40625 -1.875 L 16.40625 -3.46875 C 15.738281 -2.3125 14.878906 -1.441406 13.828125 -0.859375 C 12.785156 -0.285156 11.535156 0 10.078125 0 C 7.648438 0 5.695312 -0.921875 4.21875 -2.765625 C 2.738281 -4.609375 2 -7.054688 2 -10.109375 C 2 -13.160156 2.738281 -15.609375 4.21875 -17.453125 C 5.695312 -19.304688 7.648438 -20.234375 10.078125 -20.234375 C 11.535156 -20.234375 12.785156 -19.941406 13.828125 -19.359375 C 14.878906 -18.785156 15.738281 -17.914062 16.40625 -16.75 L 16.40625 -19.75 L 19.65625 -19.75 Z M 19.65625 -2.453125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 1.34375 4.78125 L 1.34375 -19.109375 L 14.890625 -19.109375 L 14.890625 4.78125 Z M 2.875 3.28125 L 13.390625 3.28125 L 13.390625 -17.578125 L 2.875 -17.578125 Z M 2.875 3.28125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 9.265625 -17.125 L 5.640625 -7.296875 L 12.90625 -7.296875 Z M 7.75 -19.75 L 10.78125 -19.75 L 18.3125 0 L 15.53125 0 L 13.734375 -5.0625 L 4.828125 -5.0625 L 3.03125 0 L 0.21875 0 Z M 7.75 -19.75 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-2">
+<path style="stroke:none;" d="M 12.03125 -9.265625 C 12.601562 -9.066406 13.160156 -8.648438 13.703125 -8.015625 C 14.242188 -7.378906 14.785156 -6.503906 15.328125 -5.390625 L 18.046875 0 L 15.171875 0 L 12.640625 -5.0625 C 11.992188 -6.382812 11.363281 -7.257812 10.75 -7.6875 C 10.132812 -8.125 9.296875 -8.34375 8.234375 -8.34375 L 5.328125 -8.34375 L 5.328125 0 L 2.65625 0 L 2.65625 -19.75 L 8.6875 -19.75 C 10.945312 -19.75 12.628906 -19.273438 13.734375 -18.328125 C 14.847656 -17.390625 15.40625 -15.96875 15.40625 -14.0625 C 15.40625 -12.820312 15.113281 -11.789062 14.53125 -10.96875 C 13.957031 -10.144531 13.125 -9.578125 12.03125 -9.265625 Z M 5.328125 -17.5625 L 5.328125 -10.546875 L 8.6875 -10.546875 C 9.976562 -10.546875 10.953125 -10.84375 11.609375 -11.4375 C 12.265625 -12.03125 12.59375 -12.90625 12.59375 -14.0625 C 12.59375 -15.21875 12.265625 -16.085938 11.609375 -16.671875 C 10.953125 -17.265625 9.976562 -17.5625 8.6875 -17.5625 Z M 5.328125 -17.5625 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-3">
+<path style="stroke:none;" d="M 2.65625 -19.75 L 6.640625 -19.75 L 11.6875 -6.3125 L 16.75 -19.75 L 20.734375 -19.75 L 20.734375 0 L 18.125 0 L 18.125 -17.34375 L 13.03125 -3.796875 L 10.34375 -3.796875 L 5.25 -17.34375 L 5.25 0 L 2.65625 0 Z M 2.65625 -19.75 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-4">
+<path style="stroke:none;" d="M 3.171875 -3.359375 L 5.96875 -3.359375 L 5.96875 -1.078125 L 3.796875 3.15625 L 2.09375 3.15625 L 3.171875 -1.078125 Z M 3.171875 -3.359375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-5">
+<path style="stroke:none;" d=""/>
+</symbol>
+<symbol overflow="visible" id="glyph1-6">
+<path style="stroke:none;" d="M 2.546875 -14.8125 L 4.984375 -14.8125 L 4.984375 0 L 2.546875 0 Z M 2.546875 -20.578125 L 4.984375 -20.578125 L 4.984375 -17.5 L 2.546875 -17.5 Z M 2.546875 -20.578125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-7">
+<path style="stroke:none;" d="M 13.21875 -14.25 L 13.21875 -11.96875 C 12.53125 -12.351562 11.835938 -12.640625 11.140625 -12.828125 C 10.453125 -13.015625 9.753906 -13.109375 9.046875 -13.109375 C 7.472656 -13.109375 6.25 -12.609375 5.375 -11.609375 C 4.5 -10.609375 4.0625 -9.203125 4.0625 -7.390625 C 4.0625 -5.585938 4.5 -4.1875 5.375 -3.1875 C 6.25 -2.1875 7.472656 -1.6875 9.046875 -1.6875 C 9.753906 -1.6875 10.453125 -1.78125 11.140625 -1.96875 C 11.835938 -2.15625 12.53125 -2.4375 13.21875 -2.8125 L 13.21875 -0.5625 C 12.539062 -0.25 11.835938 -0.015625 11.109375 0.140625 C 10.378906 0.304688 9.601562 0.390625 8.78125 0.390625 C 6.550781 0.390625 4.78125 -0.3125 3.46875 -1.71875 C 2.15625 -3.125 1.5 -5.015625 1.5 -7.390625 C 1.5 -9.804688 2.160156 -11.707031 3.484375 -13.09375 C 4.816406 -14.476562 6.632812 -15.171875 8.9375 -15.171875 C 9.6875 -15.171875 10.414062 -15.09375 11.125 -14.9375 C 11.84375 -14.789062 12.539062 -14.5625 13.21875 -14.25 Z M 13.21875 -14.25 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-8">
+<path style="stroke:none;" d="M 11.140625 -12.546875 C 10.867188 -12.703125 10.570312 -12.816406 10.25 -12.890625 C 9.925781 -12.960938 9.570312 -13 9.1875 -13 C 7.8125 -13 6.753906 -12.550781 6.015625 -11.65625 C 5.273438 -10.757812 4.90625 -9.476562 4.90625 -7.8125 L 4.90625 0 L 2.453125 0 L 2.453125 -14.8125 L 4.90625 -14.8125 L 4.90625 -12.515625 C 5.414062 -13.410156 6.082031 -14.078125 6.90625 -14.515625 C 7.726562 -14.953125 8.722656 -15.171875 9.890625 -15.171875 C 10.054688 -15.171875 10.238281 -15.160156 10.4375 -15.140625 C 10.644531 -15.117188 10.875 -15.085938 11.125 -15.046875 Z M 11.140625 -12.546875 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-9">
+<path style="stroke:none;" d="M 8.296875 -13.109375 C 6.992188 -13.109375 5.960938 -12.597656 5.203125 -11.578125 C 4.441406 -10.554688 4.0625 -9.160156 4.0625 -7.390625 C 4.0625 -5.617188 4.4375 -4.222656 5.1875 -3.203125 C 5.945312 -2.191406 6.984375 -1.6875 8.296875 -1.6875 C 9.585938 -1.6875 10.613281 -2.195312 11.375 -3.21875 C 12.132812 -4.238281 12.515625 -5.628906 12.515625 -7.390625 C 12.515625 -9.148438 12.132812 -10.539062 11.375 -11.5625 C 10.613281 -12.59375 9.585938 -13.109375 8.296875 -13.109375 Z M 8.296875 -15.171875 C 10.410156 -15.171875 12.070312 -14.484375 13.28125 -13.109375 C 14.488281 -11.734375 15.09375 -9.828125 15.09375 -7.390625 C 15.09375 -4.960938 14.488281 -3.054688 13.28125 -1.671875 C 12.070312 -0.296875 10.410156 0.390625 8.296875 0.390625 C 6.171875 0.390625 4.503906 -0.296875 3.296875 -1.671875 C 2.097656 -3.054688 1.5 -4.960938 1.5 -7.390625 C 1.5 -9.828125 2.097656 -11.734375 3.296875 -13.109375 C 4.503906 -14.484375 6.171875 -15.171875 8.296875 -15.171875 Z M 8.296875 -15.171875 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-10">
+<path style="stroke:none;" d="M 5.328125 -9.4375 L 5.328125 -2.203125 L 9.625 -2.203125 C 11.0625 -2.203125 12.125 -2.5 12.8125 -3.09375 C 13.5 -3.6875 13.84375 -4.597656 13.84375 -5.828125 C 13.84375 -7.054688 13.5 -7.960938 12.8125 -8.546875 C 12.125 -9.140625 11.0625 -9.4375 9.625 -9.4375 Z M 5.328125 -17.5625 L 5.328125 -11.609375 L 9.28125 -11.609375 C 10.59375 -11.609375 11.566406 -11.851562 12.203125 -12.34375 C 12.835938 -12.832031 13.15625 -13.578125 13.15625 -14.578125 C 13.15625 -15.578125 12.835938 -16.320312 12.203125 -16.8125 C 11.566406 -17.3125 10.59375 -17.5625 9.28125 -17.5625 Z M 2.65625 -19.75 L 9.484375 -19.75 C 11.523438 -19.75 13.09375 -19.328125 14.1875 -18.484375 C 15.289062 -17.640625 15.84375 -16.4375 15.84375 -14.875 C 15.84375 -13.664062 15.5625 -12.703125 15 -11.984375 C 14.4375 -11.273438 13.609375 -10.832031 12.515625 -10.65625 C 13.828125 -10.363281 14.847656 -9.769531 15.578125 -8.875 C 16.304688 -7.988281 16.671875 -6.875 16.671875 -5.53125 C 16.671875 -3.769531 16.070312 -2.40625 14.875 -1.4375 C 13.675781 -0.476562 11.96875 0 9.75 0 L 2.65625 0 Z M 2.65625 -19.75 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-11">
+<path style="stroke:none;" d="M 2.546875 -20.578125 L 4.984375 -20.578125 L 4.984375 0 L 2.546875 0 Z M 2.546875 -20.578125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-12">
+<path style="stroke:none;" d="M 9.28125 -7.453125 C 7.320312 -7.453125 5.960938 -7.222656 5.203125 -6.765625 C 4.441406 -6.316406 4.0625 -5.550781 4.0625 -4.46875 C 4.0625 -3.601562 4.34375 -2.914062 4.90625 -2.40625 C 5.476562 -1.90625 6.253906 -1.65625 7.234375 -1.65625 C 8.585938 -1.65625 9.671875 -2.132812 10.484375 -3.09375 C 11.296875 -4.050781 11.703125 -5.320312 11.703125 -6.90625 L 11.703125 -7.453125 Z M 14.140625 -8.453125 L 14.140625 0 L 11.703125 0 L 11.703125 -2.25 C 11.148438 -1.351562 10.457031 -0.6875 9.625 -0.25 C 8.800781 0.175781 7.789062 0.390625 6.59375 0.390625 C 5.070312 0.390625 3.863281 -0.0351562 2.96875 -0.890625 C 2.070312 -1.742188 1.625 -2.882812 1.625 -4.3125 C 1.625 -5.976562 2.179688 -7.234375 3.296875 -8.078125 C 4.410156 -8.929688 6.078125 -9.359375 8.296875 -9.359375 L 11.703125 -9.359375 L 11.703125 -9.59375 C 11.703125 -10.707031 11.332031 -11.570312 10.59375 -12.1875 C 9.863281 -12.800781 8.832031 -13.109375 7.5 -13.109375 C 6.65625 -13.109375 5.832031 -13.003906 5.03125 -12.796875 C 4.226562 -12.597656 3.457031 -12.296875 2.71875 -11.890625 L 2.71875 -14.140625 C 3.601562 -14.484375 4.460938 -14.738281 5.296875 -14.90625 C 6.140625 -15.082031 6.957031 -15.171875 7.75 -15.171875 C 9.894531 -15.171875 11.492188 -14.613281 12.546875 -13.5 C 13.609375 -12.394531 14.140625 -10.710938 14.140625 -8.453125 Z M 14.140625 -8.453125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-13">
+<path style="stroke:none;" d="M 1.5 -14.8125 L 13.0625 -14.8125 L 13.0625 -12.59375 L 3.90625 -1.9375 L 13.0625 -1.9375 L 13.0625 0 L 1.171875 0 L 1.171875 -2.21875 L 10.3125 -12.875 L 1.5 -12.875 Z M 1.5 -14.8125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-14">
+<path style="stroke:none;" d="M 15.234375 -8.015625 L 15.234375 -6.828125 L 4.03125 -6.828125 C 4.132812 -5.148438 4.640625 -3.875 5.546875 -3 C 6.453125 -2.125 7.710938 -1.6875 9.328125 -1.6875 C 10.265625 -1.6875 11.171875 -1.800781 12.046875 -2.03125 C 12.921875 -2.257812 13.789062 -2.601562 14.65625 -3.0625 L 14.65625 -0.75 C 13.78125 -0.382812 12.882812 -0.101562 11.96875 0.09375 C 11.050781 0.289062 10.125 0.390625 9.1875 0.390625 C 6.820312 0.390625 4.945312 -0.296875 3.5625 -1.671875 C 2.1875 -3.054688 1.5 -4.921875 1.5 -7.265625 C 1.5 -9.691406 2.148438 -11.613281 3.453125 -13.03125 C 4.765625 -14.457031 6.535156 -15.171875 8.765625 -15.171875 C 10.753906 -15.171875 12.328125 -14.53125 13.484375 -13.25 C 14.648438 -11.96875 15.234375 -10.222656 15.234375 -8.015625 Z M 12.796875 -8.734375 C 12.773438 -10.066406 12.398438 -11.128906 11.671875 -11.921875 C 10.941406 -12.710938 9.976562 -13.109375 8.78125 -13.109375 C 7.425781 -13.109375 6.335938 -12.722656 5.515625 -11.953125 C 4.703125 -11.191406 4.234375 -10.113281 4.109375 -8.71875 Z M 12.796875 -8.734375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-15">
+<path style="stroke:none;" d="M 4.96875 -19.03125 L 4.96875 -14.8125 L 9.96875 -14.8125 L 9.96875 -12.921875 L 4.96875 -12.921875 L 4.96875 -4.875 C 4.96875 -3.664062 5.128906 -2.890625 5.453125 -2.546875 C 5.785156 -2.203125 6.457031 -2.03125 7.46875 -2.03125 L 9.96875 -2.03125 L 9.96875 0 L 7.46875 0 C 5.59375 0 4.296875 -0.347656 3.578125 -1.046875 C 2.867188 -1.753906 2.515625 -3.03125 2.515625 -4.875 L 2.515625 -12.921875 L 0.734375 -12.921875 L 0.734375 -14.8125 L 2.515625 -14.8125 L 2.515625 -19.03125 Z M 4.96875 -19.03125 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-16">
+<path style="stroke:none;" d="M 14.875 -8.9375 L 14.875 0 L 12.4375 0 L 12.4375 -8.859375 C 12.4375 -10.265625 12.160156 -11.316406 11.609375 -12.015625 C 11.066406 -12.710938 10.25 -13.0625 9.15625 -13.0625 C 7.84375 -13.0625 6.804688 -12.640625 6.046875 -11.796875 C 5.285156 -10.960938 4.90625 -9.820312 4.90625 -8.375 L 4.90625 0 L 2.453125 0 L 2.453125 -20.578125 L 4.90625 -20.578125 L 4.90625 -12.515625 C 5.488281 -13.398438 6.175781 -14.0625 6.96875 -14.5 C 7.757812 -14.945312 8.671875 -15.171875 9.703125 -15.171875 C 11.398438 -15.171875 12.6875 -14.644531 13.5625 -13.59375 C 14.4375 -12.539062 14.875 -10.988281 14.875 -8.9375 Z M 14.875 -8.9375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-17">
+<path style="stroke:none;" d="M 1.703125 -19.75 L 4.578125 -19.75 L 9.484375 -12.40625 L 14.421875 -19.75 L 17.296875 -19.75 L 10.9375 -10.265625 L 17.71875 0 L 14.84375 0 L 9.28125 -8.40625 L 3.6875 0 L 0.8125 0 L 7.859375 -10.546875 Z M 1.703125 -19.75 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-18">
+<path style="stroke:none;" d="M 2.65625 -19.75 L 5.328125 -19.75 L 5.328125 0 L 2.65625 0 Z M 2.65625 -19.75 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-19">
+<path style="stroke:none;" d="M 14.875 -8.9375 L 14.875 0 L 12.4375 0 L 12.4375 -8.859375 C 12.4375 -10.265625 12.160156 -11.316406 11.609375 -12.015625 C 11.066406 -12.710938 10.25 -13.0625 9.15625 -13.0625 C 7.84375 -13.0625 6.804688 -12.640625 6.046875 -11.796875 C 5.285156 -10.960938 4.90625 -9.820312 4.90625 -8.375 L 4.90625 0 L 2.453125 0 L 2.453125 -14.8125 L 4.90625 -14.8125 L 4.90625 -12.515625 C 5.488281 -13.398438 6.175781 -14.0625 6.96875 -14.5 C 7.757812 -14.945312 8.671875 -15.171875 9.703125 -15.171875 C 11.398438 -15.171875 12.6875 -14.644531 13.5625 -13.59375 C 14.4375 -12.539062 14.875 -10.988281 14.875 -8.9375 Z M 14.875 -8.9375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-20">
+<path style="stroke:none;" d="M 12 -14.375 L 12 -12.078125 C 11.3125 -12.429688 10.597656 -12.695312 9.859375 -12.875 C 9.117188 -13.050781 8.347656 -13.140625 7.546875 -13.140625 C 6.335938 -13.140625 5.429688 -12.953125 4.828125 -12.578125 C 4.222656 -12.210938 3.921875 -11.660156 3.921875 -10.921875 C 3.921875 -10.347656 4.132812 -9.898438 4.5625 -9.578125 C 5 -9.265625 5.875 -8.960938 7.1875 -8.671875 L 8.015625 -8.484375 C 9.742188 -8.109375 10.972656 -7.582031 11.703125 -6.90625 C 12.429688 -6.238281 12.796875 -5.300781 12.796875 -4.09375 C 12.796875 -2.71875 12.25 -1.625 11.15625 -0.8125 C 10.070312 -0.0078125 8.578125 0.390625 6.671875 0.390625 C 5.878906 0.390625 5.050781 0.3125 4.1875 0.15625 C 3.320312 0 2.414062 -0.234375 1.46875 -0.546875 L 1.46875 -3.0625 C 2.363281 -2.59375 3.25 -2.238281 4.125 -2 C 5 -1.769531 5.863281 -1.65625 6.71875 -1.65625 C 7.863281 -1.65625 8.742188 -1.847656 9.359375 -2.234375 C 9.984375 -2.628906 10.296875 -3.1875 10.296875 -3.90625 C 10.296875 -4.5625 10.070312 -5.066406 9.625 -5.421875 C 9.175781 -5.773438 8.195312 -6.113281 6.6875 -6.4375 L 5.84375 -6.640625 C 4.332031 -6.960938 3.242188 -7.453125 2.578125 -8.109375 C 1.910156 -8.765625 1.578125 -9.664062 1.578125 -10.8125 C 1.578125 -12.207031 2.066406 -13.28125 3.046875 -14.03125 C 4.035156 -14.789062 5.441406 -15.171875 7.265625 -15.171875 C 8.160156 -15.171875 9.003906 -15.101562 9.796875 -14.96875 C 10.597656 -14.84375 11.332031 -14.644531 12 -14.375 Z M 12 -14.375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-21">
+<path style="stroke:none;" d="M 2.296875 -5.84375 L 2.296875 -14.8125 L 4.734375 -14.8125 L 4.734375 -5.9375 C 4.734375 -4.539062 5.003906 -3.488281 5.546875 -2.78125 C 6.097656 -2.082031 6.921875 -1.734375 8.015625 -1.734375 C 9.328125 -1.734375 10.363281 -2.148438 11.125 -2.984375 C 11.894531 -3.828125 12.28125 -4.972656 12.28125 -6.421875 L 12.28125 -14.8125 L 14.71875 -14.8125 L 14.71875 0 L 12.28125 0 L 12.28125 -2.28125 C 11.6875 -1.375 11 -0.703125 10.21875 -0.265625 C 9.4375 0.171875 8.53125 0.390625 7.5 0.390625 C 5.800781 0.390625 4.507812 -0.140625 3.625 -1.203125 C 2.738281 -2.265625 2.296875 -3.8125 2.296875 -5.84375 Z M 8.421875 -15.171875 Z M 8.421875 -15.171875 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-22">
+<path style="stroke:none;" d="M 2.65625 -19.75 L 14.015625 -19.75 L 14.015625 -17.5 L 5.328125 -17.5 L 5.328125 -11.6875 L 13.15625 -11.6875 L 13.15625 -9.4375 L 5.328125 -9.4375 L 5.328125 0 L 2.65625 0 Z M 2.65625 -19.75 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-23">
+<path style="stroke:none;" d="M 2.65625 -19.75 L 5.328125 -19.75 L 5.328125 -2.25 L 14.953125 -2.25 L 14.953125 0 L 2.65625 0 Z M 2.65625 -19.75 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-24">
+<path style="stroke:none;" d="M 12.296875 -12.5625 L 12.296875 -20.578125 L 14.734375 -20.578125 L 14.734375 0 L 12.296875 0 L 12.296875 -2.21875 C 11.785156 -1.34375 11.140625 -0.6875 10.359375 -0.25 C 9.578125 0.175781 8.640625 0.390625 7.546875 0.390625 C 5.765625 0.390625 4.3125 -0.320312 3.1875 -1.75 C 2.0625 -3.1875 1.5 -5.066406 1.5 -7.390625 C 1.5 -9.722656 2.0625 -11.601562 3.1875 -13.03125 C 4.3125 -14.457031 5.765625 -15.171875 7.546875 -15.171875 C 8.640625 -15.171875 9.578125 -14.957031 10.359375 -14.53125 C 11.140625 -14.101562 11.785156 -13.445312 12.296875 -12.5625 Z M 4.015625 -7.390625 C 4.015625 -5.597656 4.378906 -4.191406 5.109375 -3.171875 C 5.847656 -2.160156 6.863281 -1.65625 8.15625 -1.65625 C 9.4375 -1.65625 10.445312 -2.160156 11.1875 -3.171875 C 11.925781 -4.191406 12.296875 -5.597656 12.296875 -7.390625 C 12.296875 -9.179688 11.925781 -10.585938 11.1875 -11.609375 C 10.445312 -12.628906 9.4375 -13.140625 8.15625 -13.140625 C 6.863281 -13.140625 5.847656 -12.628906 5.109375 -11.609375 C 4.378906 -10.585938 4.015625 -9.179688 4.015625 -7.390625 Z M 4.015625 -7.390625 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-25">
+<path style="stroke:none;" d="M 6.875 -19.75 L 9.125 -19.75 L 2.25 2.515625 L 0 2.515625 Z M 6.875 -19.75 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-26">
+<path style="stroke:none;" d="M 14.5 -19.109375 L 14.5 -16.5 C 13.488281 -16.976562 12.53125 -17.335938 11.625 -17.578125 C 10.726562 -17.816406 9.859375 -17.9375 9.015625 -17.9375 C 7.566406 -17.9375 6.445312 -17.65625 5.65625 -17.09375 C 4.863281 -16.53125 4.46875 -15.726562 4.46875 -14.6875 C 4.46875 -13.8125 4.726562 -13.148438 5.25 -12.703125 C 5.78125 -12.253906 6.773438 -11.894531 8.234375 -11.625 L 9.859375 -11.296875 C 11.847656 -10.921875 13.316406 -10.253906 14.265625 -9.296875 C 15.210938 -8.335938 15.6875 -7.054688 15.6875 -5.453125 C 15.6875 -3.535156 15.046875 -2.082031 13.765625 -1.09375 C 12.484375 -0.101562 10.601562 0.390625 8.125 0.390625 C 7.1875 0.390625 6.191406 0.28125 5.140625 0.0625 C 4.085938 -0.144531 2.992188 -0.457031 1.859375 -0.875 L 1.859375 -3.625 C 2.953125 -3.019531 4.015625 -2.5625 5.046875 -2.25 C 6.085938 -1.9375 7.113281 -1.78125 8.125 -1.78125 C 9.644531 -1.78125 10.820312 -2.078125 11.65625 -2.671875 C 12.488281 -3.273438 12.90625 -4.132812 12.90625 -5.25 C 12.90625 -6.21875 12.601562 -6.972656 12 -7.515625 C 11.40625 -8.066406 10.429688 -8.484375 9.078125 -8.765625 L 7.453125 -9.078125 C 5.453125 -9.472656 4.003906 -10.09375 3.109375 -10.9375 C 2.222656 -11.78125 1.78125 -12.957031 1.78125 -14.46875 C 1.78125 -16.21875 2.394531 -17.59375 3.625 -18.59375 C 4.863281 -19.601562 6.5625 -20.109375 8.71875 -20.109375 C 9.644531 -20.109375 10.585938 -20.023438 11.546875 -19.859375 C 12.503906 -19.691406 13.488281 -19.441406 14.5 -19.109375 Z M 14.5 -19.109375 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-27">
+<path style="stroke:none;" d="M 2.359375 -19.75 L 5.046875 -19.75 L 5.046875 -7.75 C 5.046875 -5.632812 5.425781 -4.109375 6.1875 -3.171875 C 6.957031 -2.242188 8.203125 -1.78125 9.921875 -1.78125 C 11.628906 -1.78125 12.867188 -2.242188 13.640625 -3.171875 C 14.410156 -4.109375 14.796875 -5.632812 14.796875 -7.75 L 14.796875 -19.75 L 17.46875 -19.75 L 17.46875 -7.421875 C 17.46875 -4.847656 16.832031 -2.898438 15.5625 -1.578125 C 14.289062 -0.265625 12.410156 0.390625 9.921875 0.390625 C 7.421875 0.390625 5.535156 -0.265625 4.265625 -1.578125 C 2.992188 -2.898438 2.359375 -4.847656 2.359375 -7.421875 Z M 2.359375 -19.75 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-28">
+<path style="stroke:none;" d="M 5.328125 -17.5625 L 5.328125 -10.140625 L 8.6875 -10.140625 C 9.9375 -10.140625 10.898438 -10.457031 11.578125 -11.09375 C 12.253906 -11.738281 12.59375 -12.65625 12.59375 -13.84375 C 12.59375 -15.03125 12.253906 -15.945312 11.578125 -16.59375 C 10.898438 -17.238281 9.9375 -17.5625 8.6875 -17.5625 Z M 2.65625 -19.75 L 8.6875 -19.75 C 10.90625 -19.75 12.578125 -19.25 13.703125 -18.25 C 14.835938 -17.25 15.40625 -15.78125 15.40625 -13.84375 C 15.40625 -11.894531 14.835938 -10.421875 13.703125 -9.421875 C 12.578125 -8.429688 10.90625 -7.9375 8.6875 -7.9375 L 5.328125 -7.9375 L 5.328125 0 L 2.65625 0 Z M 2.65625 -19.75 "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-29">
+<path style="stroke:none;" d="M 0.8125 -14.8125 L 3.390625 -14.8125 L 8.015625 -2.375 L 12.640625 -14.8125 L 15.234375 -14.8125 L 9.671875 0 L 6.359375 0 Z M 0.8125 -14.8125 "/>
+</symbol>
+</g>
+</defs>
+<g id="surface66555">
+<rect x="0" y="0" width="843" height="543" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill-rule:evenodd;fill:rgb(75.294119%,94.117647%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 7 14 L 49 14 L 49 20 L 7 20 Z M 7 14 " transform="matrix(20,0,0,20,-138,-38)"/>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,60.000002%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 8 14 L 20 14 L 20 16 L 8 16 Z M 8 14 " transform="matrix(20,0,0,20,-138,-38)"/>
+<path style="fill-rule:evenodd;fill:rgb(100%,90.980393%,67.843139%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 8 2 L 34 2 L 34 7 L 8 7 Z M 8 2 " transform="matrix(20,0,0,20,-138,-38)"/>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-1" x="245.28125" y="52.015462"/>
+  <use xlink:href="#glyph0-2" x="270.504503" y="52.015462"/>
+  <use xlink:href="#glyph0-3" x="292.288357" y="52.015462"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph1-1" x="125.066406" y="91.386393"/>
+  <use xlink:href="#glyph1-2" x="143.600206" y="91.386393"/>
+  <use xlink:href="#glyph1-3" x="162.424805" y="91.386393"/>
+  <use xlink:href="#glyph1-4" x="185.800184" y="91.386393"/>
+  <use xlink:href="#glyph1-5" x="194.412109" y="91.386393"/>
+  <use xlink:href="#glyph1-3" x="203.024034" y="91.386393"/>
+  <use xlink:href="#glyph1-6" x="226.399414" y="91.386393"/>
+  <use xlink:href="#glyph1-7" x="233.926541" y="91.386393"/>
+  <use xlink:href="#glyph1-8" x="248.822374" y="91.386393"/>
+  <use xlink:href="#glyph1-9" x="259.365723" y="91.386393"/>
+  <use xlink:href="#glyph1-10" x="275.941515" y="91.386393"/>
+  <use xlink:href="#glyph1-11" x="294.528212" y="91.386393"/>
+  <use xlink:href="#glyph1-12" x="302.055339" y="91.386393"/>
+  <use xlink:href="#glyph1-13" x="318.657715" y="91.386393"/>
+  <use xlink:href="#glyph1-14" x="332.878906" y="91.386393"/>
+  <use xlink:href="#glyph1-4" x="349.547201" y="91.386393"/>
+  <use xlink:href="#glyph1-5" x="358.159125" y="91.386393"/>
+  <use xlink:href="#glyph1-9" x="366.77105" y="91.386393"/>
+  <use xlink:href="#glyph1-15" x="383.346842" y="91.386393"/>
+  <use xlink:href="#glyph1-16" x="393.969672" y="91.386393"/>
+  <use xlink:href="#glyph1-14" x="411.140896" y="91.386393"/>
+  <use xlink:href="#glyph1-8" x="427.809191" y="91.386393"/>
+</g>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,60.000002%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 8 7 L 20 7 L 20 11 L 8 11 Z M 8 7 " transform="matrix(20,0,0,20,-138,-38)"/>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,60.000002%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 22 7 L 34 7 L 34 11 L 22 11 Z M 22 7 " transform="matrix(20,0,0,20,-138,-38)"/>
+<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
+  <use xlink:href="#glyph1-1" x="42.664062" y="134.452799"/>
+  <use xlink:href="#glyph1-17" x="61.197862" y="134.452799"/>
+  <use xlink:href="#glyph1-18" x="79.757975" y="134.452799"/>
+  <use xlink:href="#glyph1-5" x="87.748155" y="134.452799"/>
+  <use xlink:href="#glyph1-18" x="96.36008" y="134.452799"/>
+  <use xlink:href="#glyph1-19" x="104.35026" y="134.452799"/>
+  <use xlink:href="#glyph1-20" x="121.521484" y="134.452799"/>
+  <use xlink:href="#glyph1-15" x="135.63661" y="134.452799"/>
+  <use xlink:href="#glyph1-8" x="146.25944" y="134.452799"/>
+  <use xlink:href="#glyph1-21" x="157.39822" y="134.452799"/>
+  <use xlink:href="#glyph1-7" x="174.569444" y="134.452799"/>
+  <use xlink:href="#glyph1-15" x="189.465278" y="134.452799"/>
+  <use xlink:href="#glyph1-6" x="200.088108" y="134.452799"/>
+  <use xlink:href="#glyph1-9" x="207.615234" y="134.452799"/>
+  <use xlink:href="#glyph1-19" x="224.191026" y="134.452799"/>
+</g>
+<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
+  <use xlink:href="#glyph1-22" x="105.28125" y="168.319987"/>
+  <use xlink:href="#glyph1-14" x="119.383355" y="168.319987"/>
+  <use xlink:href="#glyph1-15" x="136.051649" y="168.319987"/>
+  <use xlink:href="#glyph1-7" x="146.674479" y="168.319987"/>
+  <use xlink:href="#glyph1-16" x="161.570312" y="168.319987"/>
+</g>
+<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
+  <use xlink:href="#glyph1-1" x="358.09375" y="134.452799"/>
+  <use xlink:href="#glyph1-17" x="376.62755" y="134.452799"/>
+  <use xlink:href="#glyph1-18" x="395.187663" y="134.452799"/>
+  <use xlink:href="#glyph1-5" x="403.177843" y="134.452799"/>
+  <use xlink:href="#glyph1-23" x="411.789768" y="134.452799"/>
+  <use xlink:href="#glyph1-9" x="426.407552" y="134.452799"/>
+  <use xlink:href="#glyph1-12" x="442.983344" y="134.452799"/>
+  <use xlink:href="#glyph1-24" x="459.58572" y="134.452799"/>
+  <use xlink:href="#glyph1-25" x="476.783257" y="134.452799"/>
+</g>
+<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
+  <use xlink:href="#glyph1-26" x="354.324219" y="168.319987"/>
+  <use xlink:href="#glyph1-15" x="371.521756" y="168.319987"/>
+  <use xlink:href="#glyph1-9" x="382.144586" y="168.319987"/>
+  <use xlink:href="#glyph1-8" x="398.720378" y="168.319987"/>
+  <use xlink:href="#glyph1-14" x="409.263726" y="168.319987"/>
+  <use xlink:href="#glyph1-5" x="425.93202" y="168.319987"/>
+  <use xlink:href="#glyph1-27" x="434.543945" y="168.319987"/>
+  <use xlink:href="#glyph1-19" x="454.374132" y="168.319987"/>
+  <use xlink:href="#glyph1-6" x="471.545356" y="168.319987"/>
+  <use xlink:href="#glyph1-15" x="479.072483" y="168.319987"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-4" x="272.214844" y="314.515462"/>
+  <use xlink:href="#glyph0-5" x="296.926758" y="314.515462"/>
+  <use xlink:href="#glyph0-6" x="321.673937" y="314.515462"/>
+  <use xlink:href="#glyph0-7" x="332.327691" y="314.515462"/>
+  <use xlink:href="#glyph0-6" x="343.810438" y="314.515462"/>
+  <use xlink:href="#glyph0-8" x="354.464193" y="314.515462"/>
+  <use xlink:href="#glyph0-9" x="377.359158" y="314.515462"/>
+  <use xlink:href="#glyph0-10" x="391.523112" y="314.515462"/>
+  <use xlink:href="#glyph0-11" x="413.747776" y="314.515462"/>
+  <use xlink:href="#glyph0-12" x="427.805935" y="314.515462"/>
+  <use xlink:href="#glyph0-13" x="447.667046" y="314.515462"/>
+  <use xlink:href="#glyph0-8" x="469.768283" y="314.515462"/>
+  <use xlink:href="#glyph0-8" x="492.663249" y="314.515462"/>
+  <use xlink:href="#glyph0-10" x="515.558214" y="314.515462"/>
+  <use xlink:href="#glyph0-12" x="537.782878" y="314.515462"/>
+  <use xlink:href="#glyph0-9" x="557.643989" y="314.515462"/>
+</g>
+<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
+  <use xlink:href="#glyph1-1" x="37.742188" y="271.386393"/>
+  <use xlink:href="#glyph1-17" x="56.275987" y="271.386393"/>
+  <use xlink:href="#glyph1-18" x="74.8361" y="271.386393"/>
+  <use xlink:href="#glyph1-5" x="82.82628" y="271.386393"/>
+  <use xlink:href="#glyph1-3" x="91.438205" y="271.386393"/>
+  <use xlink:href="#glyph1-12" x="114.813585" y="271.386393"/>
+  <use xlink:href="#glyph1-20" x="131.415961" y="271.386393"/>
+  <use xlink:href="#glyph1-15" x="145.531087" y="271.386393"/>
+  <use xlink:href="#glyph1-14" x="156.153917" y="271.386393"/>
+  <use xlink:href="#glyph1-8" x="172.822211" y="271.386393"/>
+  <use xlink:href="#glyph1-5" x="183.960992" y="271.386393"/>
+  <use xlink:href="#glyph1-28" x="192.572917" y="271.386393"/>
+  <use xlink:href="#glyph1-9" x="207.944824" y="271.386393"/>
+  <use xlink:href="#glyph1-8" x="224.520616" y="271.386393"/>
+  <use xlink:href="#glyph1-15" x="235.659397" y="271.386393"/>
+</g>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,60.000002%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 22 14 L 34 14 L 34 16 L 22 16 Z M 22 14 " transform="matrix(20,0,0,20,-138,-38)"/>
+<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
+  <use xlink:href="#glyph1-1" x="317.742188" y="271.386393"/>
+  <use xlink:href="#glyph1-17" x="336.275987" y="271.386393"/>
+  <use xlink:href="#glyph1-18" x="354.8361" y="271.386393"/>
+  <use xlink:href="#glyph1-5" x="362.82628" y="271.386393"/>
+  <use xlink:href="#glyph1-3" x="371.438205" y="271.386393"/>
+  <use xlink:href="#glyph1-12" x="394.813585" y="271.386393"/>
+  <use xlink:href="#glyph1-20" x="411.415961" y="271.386393"/>
+  <use xlink:href="#glyph1-15" x="425.531087" y="271.386393"/>
+  <use xlink:href="#glyph1-14" x="436.153917" y="271.386393"/>
+  <use xlink:href="#glyph1-8" x="452.822211" y="271.386393"/>
+  <use xlink:href="#glyph1-5" x="463.960992" y="271.386393"/>
+  <use xlink:href="#glyph1-28" x="472.572917" y="271.386393"/>
+  <use xlink:href="#glyph1-9" x="487.944824" y="271.386393"/>
+  <use xlink:href="#glyph1-8" x="504.520616" y="271.386393"/>
+  <use xlink:href="#glyph1-15" x="515.659397" y="271.386393"/>
+</g>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,60.000002%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 36 14 L 48 14 L 48 16 L 36 16 Z M 36 14 " transform="matrix(20,0,0,20,-138,-38)"/>
+<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
+  <use xlink:href="#glyph1-1" x="597.742188" y="271.386393"/>
+  <use xlink:href="#glyph1-17" x="616.275987" y="271.386393"/>
+  <use xlink:href="#glyph1-18" x="634.8361" y="271.386393"/>
+  <use xlink:href="#glyph1-5" x="642.82628" y="271.386393"/>
+  <use xlink:href="#glyph1-3" x="651.438205" y="271.386393"/>
+  <use xlink:href="#glyph1-12" x="674.813585" y="271.386393"/>
+  <use xlink:href="#glyph1-20" x="691.415961" y="271.386393"/>
+  <use xlink:href="#glyph1-15" x="705.531087" y="271.386393"/>
+  <use xlink:href="#glyph1-14" x="716.153917" y="271.386393"/>
+  <use xlink:href="#glyph1-8" x="732.822211" y="271.386393"/>
+  <use xlink:href="#glyph1-5" x="743.960992" y="271.386393"/>
+  <use xlink:href="#glyph1-28" x="752.572917" y="271.386393"/>
+  <use xlink:href="#glyph1-9" x="767.944824" y="271.386393"/>
+  <use xlink:href="#glyph1-8" x="784.520616" y="271.386393"/>
+  <use xlink:href="#glyph1-15" x="795.659397" y="271.386393"/>
+</g>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,60.000002%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 8 18 L 20 18 L 20 20 L 8 20 Z M 8 18 " transform="matrix(20,0,0,20,-138,-38)"/>
+<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
+  <use xlink:href="#glyph1-1" x="46.980469" y="351.386393"/>
+  <use xlink:href="#glyph1-17" x="65.514269" y="351.386393"/>
+  <use xlink:href="#glyph1-18" x="84.074382" y="351.386393"/>
+  <use xlink:href="#glyph1-5" x="92.064562" y="351.386393"/>
+  <use xlink:href="#glyph1-26" x="100.676487" y="351.386393"/>
+  <use xlink:href="#glyph1-11" x="117.874023" y="351.386393"/>
+  <use xlink:href="#glyph1-12" x="125.40115" y="351.386393"/>
+  <use xlink:href="#glyph1-29" x="142.003526" y="351.386393"/>
+  <use xlink:href="#glyph1-14" x="158.037055" y="351.386393"/>
+  <use xlink:href="#glyph1-5" x="174.705349" y="351.386393"/>
+  <use xlink:href="#glyph1-28" x="183.317274" y="351.386393"/>
+  <use xlink:href="#glyph1-9" x="198.689182" y="351.386393"/>
+  <use xlink:href="#glyph1-8" x="215.264974" y="351.386393"/>
+  <use xlink:href="#glyph1-15" x="226.403754" y="351.386393"/>
+</g>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,60.000002%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 22 18 L 34 18 L 34 20 L 22 20 Z M 22 18 " transform="matrix(20,0,0,20,-138,-38)"/>
+<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
+  <use xlink:href="#glyph1-1" x="326.980469" y="351.386393"/>
+  <use xlink:href="#glyph1-17" x="345.514269" y="351.386393"/>
+  <use xlink:href="#glyph1-18" x="364.074382" y="351.386393"/>
+  <use xlink:href="#glyph1-5" x="372.064562" y="351.386393"/>
+  <use xlink:href="#glyph1-26" x="380.676487" y="351.386393"/>
+  <use xlink:href="#glyph1-11" x="397.874023" y="351.386393"/>
+  <use xlink:href="#glyph1-12" x="405.40115" y="351.386393"/>
+  <use xlink:href="#glyph1-29" x="422.003526" y="351.386393"/>
+  <use xlink:href="#glyph1-14" x="438.037055" y="351.386393"/>
+  <use xlink:href="#glyph1-5" x="454.705349" y="351.386393"/>
+  <use xlink:href="#glyph1-28" x="463.317274" y="351.386393"/>
+  <use xlink:href="#glyph1-9" x="478.689182" y="351.386393"/>
+  <use xlink:href="#glyph1-8" x="495.264974" y="351.386393"/>
+  <use xlink:href="#glyph1-15" x="506.403754" y="351.386393"/>
+</g>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,60.000002%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 36 18 L 48 18 L 48 20 L 36 20 Z M 36 18 " transform="matrix(20,0,0,20,-138,-38)"/>
+<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
+  <use xlink:href="#glyph1-1" x="606.980469" y="351.386393"/>
+  <use xlink:href="#glyph1-17" x="625.514269" y="351.386393"/>
+  <use xlink:href="#glyph1-18" x="644.074382" y="351.386393"/>
+  <use xlink:href="#glyph1-5" x="652.064562" y="351.386393"/>
+  <use xlink:href="#glyph1-26" x="660.676487" y="351.386393"/>
+  <use xlink:href="#glyph1-11" x="677.874023" y="351.386393"/>
+  <use xlink:href="#glyph1-12" x="685.40115" y="351.386393"/>
+  <use xlink:href="#glyph1-29" x="702.003526" y="351.386393"/>
+  <use xlink:href="#glyph1-14" x="718.037055" y="351.386393"/>
+  <use xlink:href="#glyph1-5" x="734.705349" y="351.386393"/>
+  <use xlink:href="#glyph1-28" x="743.317274" y="351.386393"/>
+  <use xlink:href="#glyph1-9" x="758.689182" y="351.386393"/>
+  <use xlink:href="#glyph1-8" x="775.264974" y="351.386393"/>
+  <use xlink:href="#glyph1-15" x="786.403754" y="351.386393"/>
+</g>
+<path style="fill-rule:evenodd;fill:rgb(90.196079%,90.196079%,90.196079%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 8 25 L 20 25 L 20 29 L 8 29 Z M 8 25 " transform="matrix(20,0,0,20,-138,-38)"/>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-14" x="62.78125" y="514.515462"/>
+  <use xlink:href="#glyph0-15" x="93.948785" y="514.515462"/>
+  <use xlink:href="#glyph0-14" x="116.77322" y="514.515462"/>
+  <use xlink:href="#glyph0-16" x="147.940755" y="514.515462"/>
+  <use xlink:href="#glyph0-17" x="176.374186" y="514.515462"/>
+  <use xlink:href="#glyph0-18" x="199.163357" y="514.515462"/>
+</g>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,60.000002%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 8 23 L 20 23 L 20 25 L 8 25 Z M 8 23 " transform="matrix(20,0,0,20,-138,-38)"/>
+<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
+  <use xlink:href="#glyph1-1" x="119.460938" y="451.386393"/>
+  <use xlink:href="#glyph1-17" x="137.994737" y="451.386393"/>
+  <use xlink:href="#glyph1-18" x="156.55485" y="451.386393"/>
+</g>
+<path style="fill-rule:evenodd;fill:rgb(100%,75.294119%,79.607844%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 22 25 L 34 25 L 34 29 L 22 29 Z M 22 25 " transform="matrix(20,0,0,20,-138,-38)"/>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-3" x="312.742188" y="514.515462"/>
+  <use xlink:href="#glyph0-19" x="339.182617" y="514.515462"/>
+  <use xlink:href="#glyph0-10" x="358.003147" y="514.515462"/>
+  <use xlink:href="#glyph0-11" x="380.22781" y="514.515462"/>
+  <use xlink:href="#glyph0-7" x="395.079698" y="514.515462"/>
+  <use xlink:href="#glyph0-20" x="406.562446" y="514.515462"/>
+  <use xlink:href="#glyph0-10" x="434.378743" y="514.515462"/>
+  <use xlink:href="#glyph0-19" x="456.603407" y="514.515462"/>
+  <use xlink:href="#glyph0-21" x="475.423937" y="514.515462"/>
+  <use xlink:href="#glyph0-22" x="485.460286" y="514.515462"/>
+  <use xlink:href="#glyph0-8" x="508.390516" y="514.515462"/>
+</g>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,60.000002%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 22 23 L 34 23 L 34 25 L 22 25 Z M 22 23 " transform="matrix(20,0,0,20,-138,-38)"/>
+<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
+  <use xlink:href="#glyph1-1" x="399.460938" y="451.386393"/>
+  <use xlink:href="#glyph1-17" x="417.994737" y="451.386393"/>
+  <use xlink:href="#glyph1-18" x="436.55485" y="451.386393"/>
+</g>
+<path style="fill-rule:evenodd;fill:rgb(100%,75.294119%,79.607844%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 36 2 L 48 2 L 48 9 L 36 9 Z M 36 2 " transform="matrix(20,0,0,20,-138,-38)"/>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-3" x="592.742188" y="72.015462"/>
+  <use xlink:href="#glyph0-19" x="619.182617" y="72.015462"/>
+  <use xlink:href="#glyph0-10" x="638.003147" y="72.015462"/>
+  <use xlink:href="#glyph0-11" x="660.22781" y="72.015462"/>
+  <use xlink:href="#glyph0-7" x="675.079698" y="72.015462"/>
+  <use xlink:href="#glyph0-20" x="686.562446" y="72.015462"/>
+  <use xlink:href="#glyph0-10" x="714.378743" y="72.015462"/>
+  <use xlink:href="#glyph0-19" x="736.603407" y="72.015462"/>
+  <use xlink:href="#glyph0-21" x="755.423937" y="72.015462"/>
+  <use xlink:href="#glyph0-22" x="765.460286" y="72.015462"/>
+  <use xlink:href="#glyph0-8" x="788.390516" y="72.015462"/>
+</g>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,60.000002%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 36 9 L 48 9 L 48 11 L 36 11 Z M 36 9 " transform="matrix(20,0,0,20,-138,-38)"/>
+<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
+  <use xlink:href="#glyph1-1" x="679.460938" y="171.386393"/>
+  <use xlink:href="#glyph1-17" x="697.994737" y="171.386393"/>
+  <use xlink:href="#glyph1-18" x="716.55485" y="171.386393"/>
+</g>
+<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 14 11 L 14 13.513281 " transform="matrix(20,0,0,20,-138,-38)"/>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 14 13.888281 L 13.75 13.388281 L 14 13.513281 L 14.25 13.388281 Z M 14 13.888281 " transform="matrix(20,0,0,20,-138,-38)"/>
+<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 28 11 L 28 13.513281 " transform="matrix(20,0,0,20,-138,-38)"/>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 28 13.888281 L 27.75 13.388281 L 28 13.513281 L 28.25 13.388281 Z M 28 13.888281 " transform="matrix(20,0,0,20,-138,-38)"/>
+<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 42 11 L 42 13.513281 " transform="matrix(20,0,0,20,-138,-38)"/>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 42 13.888281 L 41.75 13.388281 L 42 13.513281 L 42.25 13.388281 Z M 42 13.888281 " transform="matrix(20,0,0,20,-138,-38)"/>
+<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 28 20 L 28 22.513281 " transform="matrix(20,0,0,20,-138,-38)"/>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 28 22.888281 L 27.75 22.388281 L 28 22.513281 L 28.25 22.388281 Z M 28 22.888281 " transform="matrix(20,0,0,20,-138,-38)"/>
+<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 14 20 L 14 22.513281 " transform="matrix(20,0,0,20,-138,-38)"/>
+<path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 14 22.888281 L 13.75 22.388281 L 14 22.513281 L 14.25 22.388281 Z M 14 22.888281 " transform="matrix(20,0,0,20,-138,-38)"/>
+</g>
+</svg>
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-in-everything.tex b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-in-everything.tex
new file mode 100644
index 0000000..72e9316
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-in-everything.tex
@@ -0,0 +1,54 @@
+%% Creator: Inkscape inkscape 0.91, www.inkscape.org
+%% PDF/EPS/PS + LaTeX output extension by Johan Engelen, 2010
+%% Accompanies image file 'axi-in-everything.eps' (pdf, eps, ps)
+%%
+%% To include the image in your LaTeX document, write
+%%   \input{<filename>.pdf_tex}
+%%  instead of
+%%   \includegraphics{<filename>.pdf}
+%% To scale the image, write
+%%   \def\svgwidth{<desired width>}
+%%   \input{<filename>.pdf_tex}
+%%  instead of
+%%   \includegraphics[width=<desired width>]{<filename>.pdf}
+%%
+%% Images with a different path to the parent latex file can
+%% be accessed with the `import' package (which may need to be
+%% installed) using
+%%   \usepackage{import}
+%% in the preamble, and then including the image with
+%%   \import{<path to file>}{<filename>.pdf_tex}
+%% Alternatively, one can specify
+%%   \graphicspath{{<path to file>/}}
+%% 
+%% For more information, please see info/svg-inkscape on CTAN:
+%%   http://tug.ctan.org/tex-archive/info/svg-inkscape
+%%
+\begingroup%
+  \makeatletter%
+  \providecommand\color[2][]{%
+    \errmessage{(Inkscape) Color is used for the text in Inkscape, but the package 'color.sty' is not loaded}%
+    \renewcommand\color[2][]{}%
+  }%
+  \providecommand\transparent[1]{%
+    \errmessage{(Inkscape) Transparency is used (non-zero) for the text in Inkscape, but the package 'transparent.sty' is not loaded}%
+    \renewcommand\transparent[1]{}%
+  }%
+  \providecommand\rotatebox[2]{#2}%
+  \ifx\svgwidth\undefined%
+    \setlength{\unitlength}{843.00000001bp}%
+    \ifx\svgscale\undefined%
+      \relax%
+    \else%
+      \setlength{\unitlength}{\unitlength * \real{\svgscale}}%
+    \fi%
+  \else%
+    \setlength{\unitlength}{\svgwidth}%
+  \fi%
+  \global\let\svgwidth\undefined%
+  \global\let\svgscale\undefined%
+  \makeatother%
+  \begin{picture}(1,0.64412811)%
+    \put(0,0){\includegraphics[width=\unitlength]{../gfx/axi-in-everything.eps}}%
+  \end{picture}%
+\endgroup%
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-intel-bvalid-code.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-intel-bvalid-code.png
new file mode 100644
index 0000000..cec7599
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-intel-bvalid-code.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-intel-bvalid.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-intel-bvalid.png
new file mode 100644
index 0000000..446082c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-intel-bvalid.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-intel-wlast-code.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-intel-wlast-code.png
new file mode 100644
index 0000000..229dd40
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-intel-wlast-code.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-intel-wlast.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-intel-wlast.png
new file mode 100644
index 0000000..5f60ec9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-intel-wlast.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-intel-wready.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-intel-wready.png
new file mode 100644
index 0000000..8f0adb9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-intel-wready.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-last-err.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-last-err.json
new file mode 100644
index 0000000..faa5981
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-last-err.json
@@ -0,0 +1,12 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'P....'},
+  {name: 'S_AXI_ARESETN', wave: '01...'},
+  {name: 'S_AXI_ARVALID', wave: '0.10.'},
+  {name: 'S_AXI_ARREADY', wave: '0.10.'},
+  {name: 'S_AXI_ARLEN',   wave: 'x.2x.', data: ['255']},
+  {},
+  {name: 'S_AXI_RVALID',  wave: '0..10'},
+  {name: 'S_AXI_RREADY',  wave: 'x..1x'},
+  {name: 'S_AXI_RLAST',   wave: 'x..1x'},
+  {name: 'S_AXI_RRESP',   wave: 'x..2x', data: ['2b1x']},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-last-err.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-last-err.png
new file mode 100644
index 0000000..8e7f70f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-last-err.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-last-err.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-last-err.svg
new file mode 100644
index 0000000..f2a593e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-last-err.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="300" viewBox="0 0 380 300" width="380" overflow="hidden"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill: rgb(0, 65, 196);" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill: rgb(0, 65, 196);" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,300" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_1_0" d="m 40,0 0,300" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_2_0" d="m 80,0 0,300" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_3_0" d="m 120,0 0,300" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_4_0" d="m 160,0 0,300" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_5_0" d="m 200,0 0,300" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#Pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#Pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#Pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#Pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#Pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARVALID</tspan></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/></g></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARREADY</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARLEN</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#xmv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#vmx-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><text x="106" y="15" text-anchor="middle" xml:space="preserve"><tspan>255</tspan></text></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"/></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RVALID</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RREADY</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#xm1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#1mx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RLAST</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#xm1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#1mx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RRESP</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#xmv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#vmx-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>2b1x</tspan></text></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/></g></g><g id="groups_0"><g/></g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-bkram-pg78-page46.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-bkram-pg78-page46.png
new file mode 100644
index 0000000..503991f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-bkram-pg78-page46.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-1.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-1.png
new file mode 100644
index 0000000..13f1b03
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-1.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-2big.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-2big.png
new file mode 100644
index 0000000..63cd200
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-2big.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-3lil.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-3lil.png
new file mode 100644
index 0000000..56c7323
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-3lil.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-4lanes.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-4lanes.png
new file mode 100644
index 0000000..520d750
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-4lanes.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-5bloc.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-5bloc.png
new file mode 100644
index 0000000..0d23ff7
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-5bloc.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-6wstrb.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-6wstrb.png
new file mode 100644
index 0000000..65dacb5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-narrow-burst-spec-6wstrb.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-not-simple.dia b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-not-simple.dia
new file mode 100644
index 0000000..e991812
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-not-simple.dia
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-not-simple.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-not-simple.png
new file mode 100644
index 0000000..15d9137
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-not-simple.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-perf-mon.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-perf-mon.png
new file mode 100644
index 0000000..41fec29
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-perf-mon.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-read-fault.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-read-fault.png
new file mode 100644
index 0000000..4f44d46
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-read-fault.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-safety-valid.dia b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-safety-valid.dia
new file mode 100644
index 0000000..5ccd441
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-safety-valid.dia
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-spec-registered.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-spec-registered.png
new file mode 100644
index 0000000..8e67281
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-spec-registered.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-wdata.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-wdata.json
new file mode 100644
index 0000000..7332fc6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-wdata.json
@@ -0,0 +1,12 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'P.....'},
+  {name: 'S_AXI_ARESETN', wave: '01....'},
+  {},
+  {name: 'M_AXI_AWVALID', wave: '0..10.'},
+  {name: 'M_AXI_AWREADY', wave: '0.1.0.'},
+  {name: 'M_AXI_AWLEN',   wave: 'x.2.x.', data: ['0']},
+  {},
+  {name: 'M_AXI_WVALID',  wave: '0..1..'},
+  {name: 'M_AXI_WREADY',  wave: '01.0..'},
+  {name: 'M_AXI_WDATA',   wave: 'x..34.', data: ['D1','D2 ?']}
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-wdata.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-wdata.png
new file mode 100644
index 0000000..5cd1681
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-wdata.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-wdata.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-wdata.svg
new file mode 100644
index 0000000..3bfe6c8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-wdata.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="300" width="420" viewBox="0 0 420 300" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,300" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_1_0" d="m 40,0 0,300" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_2_0" d="m 80,0 0,300" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_3_0" d="m 120,0 0,300" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_4_0" d="m 160,0 0,300" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_5_0" d="m 200,0 0,300" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_6_0" d="m 240,0 0,300" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#Pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#Pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#Pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#Pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#Pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/><use xlink:href="#Pclk" transform="translate(200)"/><use xlink:href="#nclk" transform="translate(220)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"/></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_AWVALID</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0m1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#1m0" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_AWREADY</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#1m0" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_AWLEN</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vvv-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vmx-2" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><text x="126" y="15" text-anchor="middle" xml:space="preserve"><tspan>0</tspan></text></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"/></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_WVALID</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0m1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_WREADY</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1m0" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_WDATA</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xmv-3" transform="translate(120)"/><use xlink:href="#vvv-3" transform="translate(140)"/><use xlink:href="#vmv-3-4" transform="translate(160)"/><use xlink:href="#vvv-4" transform="translate(180)"/><use xlink:href="#vvv-4" transform="translate(200)"/><use xlink:href="#vvv-4" transform="translate(220)"/><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>D1</tspan></text><text x="206" y="15" text-anchor="middle" xml:space="preserve"><tspan>D2 ?</tspan></text></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/></g></g><g id="groups_0">g</g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-write-demo.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-write-demo.png
new file mode 100644
index 0000000..6d608b4
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-write-demo.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-write-example.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-write-example.png
new file mode 100644
index 0000000..5ddf625
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi-write-example.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-burst.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-burst.json
new file mode 100644
index 0000000..435efe8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-burst.json
@@ -0,0 +1,20 @@
+{signal: [
+  {name: 'S_AXI_ACLK',   wave: 'P..................'},
+  {name: 'S_AXI_ARESETN',wave: '01.................'},
+  {},
+  {name: 'S_AXI_AWVALID',wave: '0.10..10..10.......'},
+  {name: 'S_AXI_AWID',   wave: 'xx2x..3x..4x.......'},
+  {name: 'S_AXI_AWADDR', wave: 'xx2x..3x..4x.......'},
+  {name: 'S_AXI_WVALID', wave: '0..1...........0...'},
+  {name: 'S_AXI_WDATA',  wave: 'x..222233334444x...', data: ['A','B','C','D','E','F','G','H','I','J','K','L']},
+  {name: 'S_AXI_WLAST',  wave: 'x..0..20..30..4x...', data: ['A','B','C','D','E','F','G','H','I','J','K','L']},
+  {},
+  {name: 'M_AXIL_AWVALID',wave:'0..1...........0...'},
+  {name: 'M_AXIL_AWADDR', wave:'x..222233334444x...', data: ['A','B','C','D','E','F','G','H','I','J','K','L']},
+  {name: 'M_AXIL_WVALID', wave:'0..1...........0...'},
+  {name: 'M_AXIL_WDATA',  wave:'x..222233334444x...', data: ['A','B','C','D','E','F','G','H','I','J','K','L']},
+  {},
+  {name: 'M_AXIL_BVALID', wave:'0...2...3...4...0..'},
+  {},
+  {name: 'S_AXI_BVALID', wave: '0.......20..30..40.'},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-burst.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-burst.png
new file mode 100644
index 0000000..6bca0e2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-burst.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-burst.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-burst.svg
new file mode 100644
index 0000000..0a0a048
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-burst.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="480" width="940" viewBox="0 0 940 480" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_1_0" d="m 40,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_2_0" d="m 80,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_3_0" d="m 120,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_4_0" d="m 160,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_5_0" d="m 200,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_6_0" d="m 240,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_7_0" d="m 280,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_8_0" d="m 320,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_9_0" d="m 360,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_10_0" d="m 400,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_11_0" d="m 440,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_12_0" d="m 480,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_13_0" d="m 520,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_14_0" d="m 560,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_15_0" d="m 600,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_16_0" d="m 640,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_17_0" d="m 680,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_18_0" d="m 720,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_19_0" d="m 760,0 0,480" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#Pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#Pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#Pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#Pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#Pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/><use xlink:href="#Pclk" transform="translate(200)"/><use xlink:href="#nclk" transform="translate(220)"/><use xlink:href="#Pclk" transform="translate(240)"/><use xlink:href="#nclk" transform="translate(260)"/><use xlink:href="#Pclk" transform="translate(280)"/><use xlink:href="#nclk" transform="translate(300)"/><use xlink:href="#Pclk" transform="translate(320)"/><use xlink:href="#nclk" transform="translate(340)"/><use xlink:href="#Pclk" transform="translate(360)"/><use xlink:href="#nclk" transform="translate(380)"/><use xlink:href="#Pclk" transform="translate(400)"/><use xlink:href="#nclk" transform="translate(420)"/><use xlink:href="#Pclk" transform="translate(440)"/><use xlink:href="#nclk" transform="translate(460)"/><use xlink:href="#Pclk" transform="translate(480)"/><use xlink:href="#nclk" transform="translate(500)"/><use xlink:href="#Pclk" transform="translate(520)"/><use xlink:href="#nclk" transform="translate(540)"/><use xlink:href="#Pclk" transform="translate(560)"/><use xlink:href="#nclk" transform="translate(580)"/><use xlink:href="#Pclk" transform="translate(600)"/><use xlink:href="#nclk" transform="translate(620)"/><use xlink:href="#Pclk" transform="translate(640)"/><use xlink:href="#nclk" transform="translate(660)"/><use xlink:href="#Pclk" transform="translate(680)"/><use xlink:href="#nclk" transform="translate(700)"/><use xlink:href="#Pclk" transform="translate(720)"/><use xlink:href="#nclk" transform="translate(740)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"/></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARVALID</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1m0" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0m1" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#1m0" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#0m1" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#1m0" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARID</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xmx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vmx-2" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xmv-3" transform="translate(240)"/><use xlink:href="#vvv-3" transform="translate(260)"/><use xlink:href="#vmx-3" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xmv-4" transform="translate(400)"/><use xlink:href="#vvv-4" transform="translate(420)"/><use xlink:href="#vmx-4" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARADDR</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xmx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vmx-2" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xmv-3" transform="translate(240)"/><use xlink:href="#vvv-3" transform="translate(260)"/><use xlink:href="#vmx-3" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xmv-4" transform="translate(400)"/><use xlink:href="#vvv-4" transform="translate(420)"/><use xlink:href="#vmx-4" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"/></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIL_ARVALID</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0m1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#1m0" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIL_ARADDR</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xmv-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vmv-2-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vmv-2-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vmv-2-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vmv-2-3" transform="translate(280)"/><use xlink:href="#vvv-3" transform="translate(300)"/><use xlink:href="#vmv-3-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vmv-3-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vmv-3-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmv-3-4" transform="translate(440)"/><use xlink:href="#vvv-4" transform="translate(460)"/><use xlink:href="#vmv-4-4" transform="translate(480)"/><use xlink:href="#vvv-4" transform="translate(500)"/><use xlink:href="#vmv-4-4" transform="translate(520)"/><use xlink:href="#vvv-4" transform="translate(540)"/><use xlink:href="#vmv-4-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmx-4" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>A</tspan></text><text x="186" y="15" text-anchor="middle" xml:space="preserve"><tspan>B</tspan></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>C</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>D</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>E</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>F</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>G</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>H</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>I</tspan></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan>J</tspan></text><text x="546" y="15" text-anchor="middle" xml:space="preserve"><tspan>K</tspan></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan>L</tspan></text></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"/></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIL_RVALID</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#0m1" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#1m0" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIL_RDATA</tspan></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xmv-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vmv-2-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vmv-2-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vmv-2-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vmv-2-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vmv-3-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vmv-3-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmv-3-3" transform="translate(440)"/><use xlink:href="#vvv-3" transform="translate(460)"/><use xlink:href="#vmv-3-4" transform="translate(480)"/><use xlink:href="#vvv-4" transform="translate(500)"/><use xlink:href="#vmv-4-4" transform="translate(520)"/><use xlink:href="#vvv-4" transform="translate(540)"/><use xlink:href="#vmv-4-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmv-4-4" transform="translate(600)"/><use xlink:href="#vvv-4" transform="translate(620)"/><use xlink:href="#vmx-4" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><text x="186" y="15" text-anchor="middle" xml:space="preserve"><tspan>A</tspan></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>B</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>C</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>D</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>E</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>F</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>G</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>H</tspan></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan>I</tspan></text><text x="546" y="15" text-anchor="middle" xml:space="preserve"><tspan>J</tspan></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan>K</tspan></text><text x="626" y="15" text-anchor="middle" xml:space="preserve"><tspan>L</tspan></text></g></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"/></g><g id="wavelane_13_0" transform="translate(0,395)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RVALID</tspan></text><g id="wavelane_draw_13_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#0m1" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#1m0" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavelane_14_0" transform="translate(0,425)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RDATA</tspan></text><g id="wavelane_draw_14_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xmv-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vmv-2-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vmv-2-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vmv-2-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vmv-2-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vmv-3-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmv-3-3" transform="translate(440)"/><use xlink:href="#vvv-3" transform="translate(460)"/><use xlink:href="#vmv-3-3" transform="translate(480)"/><use xlink:href="#vvv-3" transform="translate(500)"/><use xlink:href="#vmv-3-4" transform="translate(520)"/><use xlink:href="#vvv-4" transform="translate(540)"/><use xlink:href="#vmv-4-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmv-4-4" transform="translate(600)"/><use xlink:href="#vvv-4" transform="translate(620)"/><use xlink:href="#vmv-4-4" transform="translate(640)"/><use xlink:href="#vvv-4" transform="translate(660)"/><use xlink:href="#vmx-4" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>A</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>B</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>C</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>D</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>E</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>F</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>G</tspan></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan>H</tspan></text><text x="546" y="15" text-anchor="middle" xml:space="preserve"><tspan>I</tspan></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan>J</tspan></text><text x="626" y="15" text-anchor="middle" xml:space="preserve"><tspan>K</tspan></text><text x="666" y="15" text-anchor="middle" xml:space="preserve"><tspan>L</tspan></text></g></g><g id="wavelane_15_0" transform="translate(0,455)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RLAST</tspan></text><g id="wavelane_draw_15_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xm0" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#0m1" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#1m0" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#0m1" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#1m0" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#0m1" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#1m0" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/><g id="wavegap_13_0" transform="translate(0,395)"/><g id="wavegap_14_0" transform="translate(0,425)"/><g id="wavegap_15_0" transform="translate(0,455)"/></g></g><g id="groups_0">g</g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-single.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-single.json
new file mode 100644
index 0000000..435efe8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-single.json
@@ -0,0 +1,20 @@
+{signal: [
+  {name: 'S_AXI_ACLK',   wave: 'P..................'},
+  {name: 'S_AXI_ARESETN',wave: '01.................'},
+  {},
+  {name: 'S_AXI_AWVALID',wave: '0.10..10..10.......'},
+  {name: 'S_AXI_AWID',   wave: 'xx2x..3x..4x.......'},
+  {name: 'S_AXI_AWADDR', wave: 'xx2x..3x..4x.......'},
+  {name: 'S_AXI_WVALID', wave: '0..1...........0...'},
+  {name: 'S_AXI_WDATA',  wave: 'x..222233334444x...', data: ['A','B','C','D','E','F','G','H','I','J','K','L']},
+  {name: 'S_AXI_WLAST',  wave: 'x..0..20..30..4x...', data: ['A','B','C','D','E','F','G','H','I','J','K','L']},
+  {},
+  {name: 'M_AXIL_AWVALID',wave:'0..1...........0...'},
+  {name: 'M_AXIL_AWADDR', wave:'x..222233334444x...', data: ['A','B','C','D','E','F','G','H','I','J','K','L']},
+  {name: 'M_AXIL_WVALID', wave:'0..1...........0...'},
+  {name: 'M_AXIL_WDATA',  wave:'x..222233334444x...', data: ['A','B','C','D','E','F','G','H','I','J','K','L']},
+  {},
+  {name: 'M_AXIL_BVALID', wave:'0...2...3...4...0..'},
+  {},
+  {name: 'S_AXI_BVALID', wave: '0.......20..30..40.'},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-single.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-single.png
new file mode 100644
index 0000000..a45edf3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-single.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-single.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-single.svg
new file mode 100644
index 0000000..899798a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-read-single.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="450" width="740" viewBox="0 0 740 450" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,450" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_1_0" d="m 40,0 0,450" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_2_0" d="m 80,0 0,450" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_3_0" d="m 120,0 0,450" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_4_0" d="m 160,0 0,450" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_5_0" d="m 200,0 0,450" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_6_0" d="m 240,0 0,450" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_7_0" d="m 280,0 0,450" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_8_0" d="m 320,0 0,450" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_9_0" d="m 360,0 0,450" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_10_0" d="m 400,0 0,450" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_11_0" d="m 440,0 0,450" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_12_0" d="m 480,0 0,450" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_13_0" d="m 520,0 0,450" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_14_0" d="m 560,0 0,450" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#Pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#Pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#Pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#Pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#Pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/><use xlink:href="#Pclk" transform="translate(200)"/><use xlink:href="#nclk" transform="translate(220)"/><use xlink:href="#Pclk" transform="translate(240)"/><use xlink:href="#nclk" transform="translate(260)"/><use xlink:href="#Pclk" transform="translate(280)"/><use xlink:href="#nclk" transform="translate(300)"/><use xlink:href="#Pclk" transform="translate(320)"/><use xlink:href="#nclk" transform="translate(340)"/><use xlink:href="#Pclk" transform="translate(360)"/><use xlink:href="#nclk" transform="translate(380)"/><use xlink:href="#Pclk" transform="translate(400)"/><use xlink:href="#nclk" transform="translate(420)"/><use xlink:href="#Pclk" transform="translate(440)"/><use xlink:href="#nclk" transform="translate(460)"/><use xlink:href="#Pclk" transform="translate(480)"/><use xlink:href="#nclk" transform="translate(500)"/><use xlink:href="#Pclk" transform="translate(520)"/><use xlink:href="#nclk" transform="translate(540)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"/></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARVALID</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#1m0" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARADDR</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xmx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vmv-2-3" transform="translate(120)"/><use xlink:href="#vvv-3" transform="translate(140)"/><use xlink:href="#vmv-3-4" transform="translate(160)"/><use xlink:href="#vvv-4" transform="translate(180)"/><use xlink:href="#vmv-4-5" transform="translate(200)"/><use xlink:href="#vvv-5" transform="translate(220)"/><use xlink:href="#vmv-5-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vmv-2-3" transform="translate(280)"/><use xlink:href="#vvv-3" transform="translate(300)"/><use xlink:href="#vmv-3-4" transform="translate(320)"/><use xlink:href="#vvv-4" transform="translate(340)"/><use xlink:href="#vmx-4" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xxx" transform="translate(400)"/><use xlink:href="#xxx" transform="translate(420)"/><use xlink:href="#xxx" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><text x="106" y="15" text-anchor="middle" xml:space="preserve"><tspan>A</tspan></text><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>B</tspan></text><text x="186" y="15" text-anchor="middle" xml:space="preserve"><tspan>C</tspan></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>D</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>E</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>F</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>G</tspan></text></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"/></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIL_ARVALID</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0m1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#1m0" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIL_ARADDR</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xmv-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vmv-2-3" transform="translate(160)"/><use xlink:href="#vvv-3" transform="translate(180)"/><use xlink:href="#vmv-3-4" transform="translate(200)"/><use xlink:href="#vvv-4" transform="translate(220)"/><use xlink:href="#vmv-4-5" transform="translate(240)"/><use xlink:href="#vvv-5" transform="translate(260)"/><use xlink:href="#vmv-5-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vmv-2-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vmv-3-4" transform="translate(360)"/><use xlink:href="#vvv-4" transform="translate(380)"/><use xlink:href="#vmx-4" transform="translate(400)"/><use xlink:href="#xxx" transform="translate(420)"/><use xlink:href="#xxx" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>A</tspan></text><text x="186" y="15" text-anchor="middle" xml:space="preserve"><tspan>B</tspan></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>C</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>D</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>E</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>F</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>G</tspan></text></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"/></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIL_RVALID</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#0m1" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#1m0" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/></g></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIL_RDATA</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xmv-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vmv-2-3" transform="translate(200)"/><use xlink:href="#vvv-3" transform="translate(220)"/><use xlink:href="#vmv-3-4" transform="translate(240)"/><use xlink:href="#vvv-4" transform="translate(260)"/><use xlink:href="#vmv-4-5" transform="translate(280)"/><use xlink:href="#vvv-5" transform="translate(300)"/><use xlink:href="#vmv-5-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vmv-2-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vmv-3-4" transform="translate(400)"/><use xlink:href="#vvv-4" transform="translate(420)"/><use xlink:href="#vmx-4" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><text x="186" y="15" text-anchor="middle" xml:space="preserve"><tspan>A</tspan></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>B</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>C</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>D</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>E</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>F</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>G</tspan></text></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"/></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RVALID</tspan></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#0m1" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#1m0" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/></g></g><g id="wavelane_13_0" transform="translate(0,395)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RDATA</tspan></text><g id="wavelane_draw_13_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xmv-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vmv-2-3" transform="translate(240)"/><use xlink:href="#vvv-3" transform="translate(260)"/><use xlink:href="#vmv-3-4" transform="translate(280)"/><use xlink:href="#vvv-4" transform="translate(300)"/><use xlink:href="#vmv-4-5" transform="translate(320)"/><use xlink:href="#vvv-5" transform="translate(340)"/><use xlink:href="#vmv-5-2" transform="translate(360)"/><use xlink:href="#vvv-2" transform="translate(380)"/><use xlink:href="#vmv-2-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmv-3-4" transform="translate(440)"/><use xlink:href="#vvv-4" transform="translate(460)"/><use xlink:href="#vmx-4" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>A</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>B</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>C</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>D</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>E</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>F</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>G</tspan></text></g></g><g id="wavelane_14_0" transform="translate(0,425)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RLAST</tspan></text><g id="wavelane_draw_14_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xm1" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#1m0" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/><g id="wavegap_13_0" transform="translate(0,395)"/><g id="wavegap_14_0" transform="translate(0,425)"/></g></g><g id="groups_0">g</g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-write-burst.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-write-burst.json
new file mode 100644
index 0000000..435efe8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-write-burst.json
@@ -0,0 +1,20 @@
+{signal: [
+  {name: 'S_AXI_ACLK',   wave: 'P..................'},
+  {name: 'S_AXI_ARESETN',wave: '01.................'},
+  {},
+  {name: 'S_AXI_AWVALID',wave: '0.10..10..10.......'},
+  {name: 'S_AXI_AWID',   wave: 'xx2x..3x..4x.......'},
+  {name: 'S_AXI_AWADDR', wave: 'xx2x..3x..4x.......'},
+  {name: 'S_AXI_WVALID', wave: '0..1...........0...'},
+  {name: 'S_AXI_WDATA',  wave: 'x..222233334444x...', data: ['A','B','C','D','E','F','G','H','I','J','K','L']},
+  {name: 'S_AXI_WLAST',  wave: 'x..0..20..30..4x...', data: ['A','B','C','D','E','F','G','H','I','J','K','L']},
+  {},
+  {name: 'M_AXIL_AWVALID',wave:'0..1...........0...'},
+  {name: 'M_AXIL_AWADDR', wave:'x..222233334444x...', data: ['A','B','C','D','E','F','G','H','I','J','K','L']},
+  {name: 'M_AXIL_WVALID', wave:'0..1...........0...'},
+  {name: 'M_AXIL_WDATA',  wave:'x..222233334444x...', data: ['A','B','C','D','E','F','G','H','I','J','K','L']},
+  {},
+  {name: 'M_AXIL_BVALID', wave:'0...2...3...4...0..'},
+  {},
+  {name: 'S_AXI_BVALID', wave: '0.......20..30..40.'},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-write-burst.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-write-burst.png
new file mode 100644
index 0000000..b4044a9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-write-burst.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-write-burst.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-write-burst.svg
new file mode 100644
index 0000000..00b6c2b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi2axil-write-burst.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="540" width="940" viewBox="0 0 940 540" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_1_0" d="m 40,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_2_0" d="m 80,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_3_0" d="m 120,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_4_0" d="m 160,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_5_0" d="m 200,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_6_0" d="m 240,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_7_0" d="m 280,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_8_0" d="m 320,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_9_0" d="m 360,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_10_0" d="m 400,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_11_0" d="m 440,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_12_0" d="m 480,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_13_0" d="m 520,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_14_0" d="m 560,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_15_0" d="m 600,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_16_0" d="m 640,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_17_0" d="m 680,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_18_0" d="m 720,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_19_0" d="m 760,0 0,540" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#Pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#Pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#Pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#Pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#Pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/><use xlink:href="#Pclk" transform="translate(200)"/><use xlink:href="#nclk" transform="translate(220)"/><use xlink:href="#Pclk" transform="translate(240)"/><use xlink:href="#nclk" transform="translate(260)"/><use xlink:href="#Pclk" transform="translate(280)"/><use xlink:href="#nclk" transform="translate(300)"/><use xlink:href="#Pclk" transform="translate(320)"/><use xlink:href="#nclk" transform="translate(340)"/><use xlink:href="#Pclk" transform="translate(360)"/><use xlink:href="#nclk" transform="translate(380)"/><use xlink:href="#Pclk" transform="translate(400)"/><use xlink:href="#nclk" transform="translate(420)"/><use xlink:href="#Pclk" transform="translate(440)"/><use xlink:href="#nclk" transform="translate(460)"/><use xlink:href="#Pclk" transform="translate(480)"/><use xlink:href="#nclk" transform="translate(500)"/><use xlink:href="#Pclk" transform="translate(520)"/><use xlink:href="#nclk" transform="translate(540)"/><use xlink:href="#Pclk" transform="translate(560)"/><use xlink:href="#nclk" transform="translate(580)"/><use xlink:href="#Pclk" transform="translate(600)"/><use xlink:href="#nclk" transform="translate(620)"/><use xlink:href="#Pclk" transform="translate(640)"/><use xlink:href="#nclk" transform="translate(660)"/><use xlink:href="#Pclk" transform="translate(680)"/><use xlink:href="#nclk" transform="translate(700)"/><use xlink:href="#Pclk" transform="translate(720)"/><use xlink:href="#nclk" transform="translate(740)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"/></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWVALID</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1m0" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0m1" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#1m0" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#0m1" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#1m0" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWID</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xmx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vmx-2" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xmv-3" transform="translate(240)"/><use xlink:href="#vvv-3" transform="translate(260)"/><use xlink:href="#vmx-3" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xmv-4" transform="translate(400)"/><use xlink:href="#vvv-4" transform="translate(420)"/><use xlink:href="#vmx-4" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWADDR</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xmx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vmx-2" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xmv-3" transform="translate(240)"/><use xlink:href="#vvv-3" transform="translate(260)"/><use xlink:href="#vmx-3" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xmv-4" transform="translate(400)"/><use xlink:href="#vvv-4" transform="translate(420)"/><use xlink:href="#vmx-4" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WVALID</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0m1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#1m0" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WDATA</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xmv-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vmv-2-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vmv-2-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vmv-2-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vmv-2-3" transform="translate(280)"/><use xlink:href="#vvv-3" transform="translate(300)"/><use xlink:href="#vmv-3-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vmv-3-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vmv-3-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmv-3-4" transform="translate(440)"/><use xlink:href="#vvv-4" transform="translate(460)"/><use xlink:href="#vmv-4-4" transform="translate(480)"/><use xlink:href="#vvv-4" transform="translate(500)"/><use xlink:href="#vmv-4-4" transform="translate(520)"/><use xlink:href="#vvv-4" transform="translate(540)"/><use xlink:href="#vmv-4-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmx-4" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>A</tspan></text><text x="186" y="15" text-anchor="middle" xml:space="preserve"><tspan>B</tspan></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>C</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>D</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>E</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>F</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>G</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>H</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>I</tspan></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan>J</tspan></text><text x="546" y="15" text-anchor="middle" xml:space="preserve"><tspan>K</tspan></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan>L</tspan></text></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WLAST</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xm0" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0mv-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vm0-2" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#0mv-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vm0-3" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#0mv-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmx-4" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>A</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>B</tspan></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan>C</tspan></text></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"/></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIL_AWVALID</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0m1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#1m0" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIL_AWADDR</tspan></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xmv-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vmv-2-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vmv-2-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vmv-2-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vmv-2-3" transform="translate(280)"/><use xlink:href="#vvv-3" transform="translate(300)"/><use xlink:href="#vmv-3-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vmv-3-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vmv-3-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmv-3-4" transform="translate(440)"/><use xlink:href="#vvv-4" transform="translate(460)"/><use xlink:href="#vmv-4-4" transform="translate(480)"/><use xlink:href="#vvv-4" transform="translate(500)"/><use xlink:href="#vmv-4-4" transform="translate(520)"/><use xlink:href="#vvv-4" transform="translate(540)"/><use xlink:href="#vmv-4-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmx-4" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>A</tspan></text><text x="186" y="15" text-anchor="middle" xml:space="preserve"><tspan>B</tspan></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>C</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>D</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>E</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>F</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>G</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>H</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>I</tspan></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan>J</tspan></text><text x="546" y="15" text-anchor="middle" xml:space="preserve"><tspan>K</tspan></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan>L</tspan></text></g></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIL_WVALID</tspan></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0m1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#1m0" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavelane_13_0" transform="translate(0,395)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIL_WDATA</tspan></text><g id="wavelane_draw_13_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xmv-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vmv-2-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vmv-2-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vmv-2-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vmv-2-3" transform="translate(280)"/><use xlink:href="#vvv-3" transform="translate(300)"/><use xlink:href="#vmv-3-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vmv-3-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vmv-3-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmv-3-4" transform="translate(440)"/><use xlink:href="#vvv-4" transform="translate(460)"/><use xlink:href="#vmv-4-4" transform="translate(480)"/><use xlink:href="#vvv-4" transform="translate(500)"/><use xlink:href="#vmv-4-4" transform="translate(520)"/><use xlink:href="#vvv-4" transform="translate(540)"/><use xlink:href="#vmv-4-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmx-4" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>A</tspan></text><text x="186" y="15" text-anchor="middle" xml:space="preserve"><tspan>B</tspan></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>C</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>D</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>E</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>F</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>G</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>H</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>I</tspan></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan>J</tspan></text><text x="546" y="15" text-anchor="middle" xml:space="preserve"><tspan>K</tspan></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan>L</tspan></text></g></g><g id="wavelane_14_0" transform="translate(0,425)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_14_0" transform="translate(0, 0)"/></g><g id="wavelane_15_0" transform="translate(0,455)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIL_BVALID</tspan></text><g id="wavelane_draw_15_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#0mv-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vvv-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vvv-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vvv-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vmv-2-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vvv-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vvv-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vvv-3" transform="translate(440)"/><use xlink:href="#vvv-3" transform="translate(460)"/><use xlink:href="#vmv-3-4" transform="translate(480)"/><use xlink:href="#vvv-4" transform="translate(500)"/><use xlink:href="#vvv-4" transform="translate(520)"/><use xlink:href="#vvv-4" transform="translate(540)"/><use xlink:href="#vvv-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vvv-4" transform="translate(600)"/><use xlink:href="#vvv-4" transform="translate(620)"/><use xlink:href="#vm0-4" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavelane_16_0" transform="translate(0,485)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_16_0" transform="translate(0, 0)"/></g><g id="wavelane_17_0" transform="translate(0,515)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_BVALID</tspan></text><g id="wavelane_draw_17_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#0mv-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vm0-2" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#0mv-3" transform="translate(480)"/><use xlink:href="#vvv-3" transform="translate(500)"/><use xlink:href="#vm0-3" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#0mv-4" transform="translate(640)"/><use xlink:href="#vvv-4" transform="translate(660)"/><use xlink:href="#vm0-4" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/><g id="wavegap_13_0" transform="translate(0,395)"/><g id="wavegap_14_0" transform="translate(0,425)"/><g id="wavegap_15_0" transform="translate(0,455)"/><g id="wavegap_16_0" transform="translate(0,485)"/><g id="wavegap_17_0" transform="translate(0,515)"/></g></g><g id="groups_0">g</g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi_narrow_burst-pg78.jpg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi_narrow_burst-pg78.jpg
new file mode 100644
index 0000000..7ba4130
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axi_narrow_burst-pg78.jpg
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidma.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidma.json
new file mode 100644
index 0000000..ed59c35
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidma.json
@@ -0,0 +1,30 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'p.............................'},
+  {name: 'S_AXI_ARESETN', wave: '01............................'},
+  {},
+  {name: 'S_AXIL_AWVALID',wave: '0.1...0.......................'},
+  {name: 'S_AXIL_WVALID', wave: '0.1...0.......................'},
+  {name: 'S_AXIL_AWADDR', wave: 'x.3456x.......................', data: ['LEN','DST','SRC','GO']},
+  {},
+  {name: 'M_AXI_ARVALID',wave: '0......1010...........10......'},
+  {name: 'M_AXI_ARADDR', wave: 'x......3x5x...........3x......', data: ['A0','A2','AA','A3']},
+  {name: 'M_AXI_ARLEN',  wave: 'x......3x5x...........3x......', data: ['1','7','0']},
+  {},
+  {name: 'M_AXI_RVALID', wave: '0.......1.........0.....10....'},
+  {name: 'M_AXI_RDATA',  wave: 'x.......3456734567x.....3x....', data: ['D0','D1','D2','D3','D4','D5','D6','D7','D8','D9','DA','DB']},
+  {name: 'M_AXI_RLAST',  wave: 'x.......010......1x.....1x....', data: ['0']},
+  {},
+  {name: 'M_AXI_AWVALID',wave: '0.........10......10......10..'},
+  {name: 'M_AXI_AWADDR', wave: 'x.........3x......4x......7x..', data: ['a0','a1','a9','a3']},
+  {name: 'M_AXI_AWLEN',  wave: 'x.........3x......4x......7x..', data: ['0','7','1','0']},
+  {},
+  {name: 'M_AXI_WVALID', wave: '0.........10......1.........0.'},
+  {name: 'M_AXI_WDATA',  wave: 'x.........3x......4567345673x.', data: ['D0','D1','D2','D3','D4','D5','D6','D7','D8','D9','DA','DB']},
+  {name: 'M_AXI_WLAST',  wave: 'x.........1x......0......101x.', data: ['0']},
+  {},
+  {name: 'S_AXI_BVALID', wave: '0..........30.............4070'},
+  {},
+  {name: 'fifo_fill',    wave: 'x2.......34.5673456345673.452.', data: ['0','1','2','3','4','5','6','7','8','9','8','7','6','5','4','3','2','1','0']},
+  {name: 'r_busy',       wave: '0.....1.....................0.'},
+  {name: 'o_int',        wave: '0...........................10'},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidma.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidma.png
new file mode 100644
index 0000000..8f536bd
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidma.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidma.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidma.svg
new file mode 100644
index 0000000..5dca2bd
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidma.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="840" width="1380" viewBox="0 0 1380 840" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{fill:#000;fill-opacity:1;stroke:none}.s7{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s10{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{color:#000;fill:#ccfdfe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s12{color:#000;fill:#cdfdc5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s13{color:#000;fill:#f0c1fb;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s14{color:#000;fill:#f5c2c0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s15{fill:#0041c4;fill-opacity:1;stroke:none}.s16{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s6"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s6"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s9"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s9"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s9"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s9"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s9"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s9"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-6"><path d="M2.875,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-6"><path d="M3,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-6"><path d="M20,20 0,20 0,0 20,0" class="s11"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-6"><path d="M0,20 0,0 3,0 9,20" class="s11"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-6"><path d="M0,0 0,20 3,20 9,0" class="s11"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-6"><path d="M0,0 0,20 3,20 6,10 3,0" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-6"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s11"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-6"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s11"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-6"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s11"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-7"><path d="M2.875,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-7"><path d="M3,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-7"><path d="M20,20 0,20 0,0 20,0" class="s12"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-7"><path d="M0,20 0,0 3,0 9,20" class="s12"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-7"><path d="M0,0 0,20 3,20 9,0" class="s12"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-7"><path d="M0,0 0,20 3,20 6,10 3,0" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-7"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s12"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-7"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s12"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-7"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s12"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-8"><path d="M2.875,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-8"><path d="M3,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-8"><path d="M20,20 0,20 0,0 20,0" class="s13"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-8"><path d="M0,20 0,0 3,0 9,20" class="s13"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-8"><path d="M0,0 0,20 3,20 9,0" class="s13"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-8"><path d="M0,0 0,20 3,20 6,10 3,0" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-8"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s13"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-8"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s13"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-8"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s13"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-9"><path d="M2.875,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-9"><path d="M3,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-9"><path d="M20,20 0,20 0,0 20,0" class="s14"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-9"><path d="M0,20 0,0 3,0 9,20" class="s14"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-9"><path d="M0,0 0,20 3,20 9,0" class="s14"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-9"><path d="M0,0 0,20 3,20 6,10 3,0" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-9"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s14"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-9"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s14"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-9"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s14"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s15"/><path d="M0,0 -15,0" class="s16"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><g style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"><line id="gmark_0_0" x1="0" y1="0" x2="0" y2="840"/><line id="gmark_1_0" x1="40" y1="0" x2="40" y2="840"/><line id="gmark_2_0" x1="80" y1="0" x2="80" y2="840"/><line id="gmark_3_0" x1="120" y1="0" x2="120" y2="840"/><line id="gmark_4_0" x1="160" y1="0" x2="160" y2="840"/><line id="gmark_5_0" x1="200" y1="0" x2="200" y2="840"/><line id="gmark_6_0" x1="240" y1="0" x2="240" y2="840"/><line id="gmark_7_0" x1="280" y1="0" x2="280" y2="840"/><line id="gmark_8_0" x1="320" y1="0" x2="320" y2="840"/><line id="gmark_9_0" x1="360" y1="0" x2="360" y2="840"/><line id="gmark_10_0" x1="400" y1="0" x2="400" y2="840"/><line id="gmark_11_0" x1="440" y1="0" x2="440" y2="840"/><line id="gmark_12_0" x1="480" y1="0" x2="480" y2="840"/><line id="gmark_13_0" x1="520" y1="0" x2="520" y2="840"/><line id="gmark_14_0" x1="560" y1="0" x2="560" y2="840"/><line id="gmark_15_0" x1="600" y1="0" x2="600" y2="840"/><line id="gmark_16_0" x1="640" y1="0" x2="640" y2="840"/><line id="gmark_17_0" x1="680" y1="0" x2="680" y2="840"/><line id="gmark_18_0" x1="720" y1="0" x2="720" y2="840"/><line id="gmark_19_0" x1="760" y1="0" x2="760" y2="840"/><line id="gmark_20_0" x1="800" y1="0" x2="800" y2="840"/><line id="gmark_21_0" x1="840" y1="0" x2="840" y2="840"/><line id="gmark_22_0" x1="880" y1="0" x2="880" y2="840"/><line id="gmark_23_0" x1="920" y1="0" x2="920" y2="840"/><line id="gmark_24_0" x1="960" y1="0" x2="960" y2="840"/><line id="gmark_25_0" x1="1000" y1="0" x2="1000" y2="840"/><line id="gmark_26_0" x1="1040" y1="0" x2="1040" y2="840"/><line id="gmark_27_0" x1="1080" y1="0" x2="1080" y2="840"/><line id="gmark_28_0" x1="1120" y1="0" x2="1120" y2="840"/><line id="gmark_29_0" x1="1160" y1="0" x2="1160" y2="840"/><line id="gmark_30_0" x1="1200" y1="0" x2="1200" y2="840"/></g></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/><use xlink:href="#pclk" transform="translate(200)"/><use xlink:href="#nclk" transform="translate(220)"/><use xlink:href="#pclk" transform="translate(240)"/><use xlink:href="#nclk" transform="translate(260)"/><use xlink:href="#pclk" transform="translate(280)"/><use xlink:href="#nclk" transform="translate(300)"/><use xlink:href="#pclk" transform="translate(320)"/><use xlink:href="#nclk" transform="translate(340)"/><use xlink:href="#pclk" transform="translate(360)"/><use xlink:href="#nclk" transform="translate(380)"/><use xlink:href="#pclk" transform="translate(400)"/><use xlink:href="#nclk" transform="translate(420)"/><use xlink:href="#pclk" transform="translate(440)"/><use xlink:href="#nclk" transform="translate(460)"/><use xlink:href="#pclk" transform="translate(480)"/><use xlink:href="#nclk" transform="translate(500)"/><use xlink:href="#pclk" transform="translate(520)"/><use xlink:href="#nclk" transform="translate(540)"/><use xlink:href="#pclk" transform="translate(560)"/><use xlink:href="#nclk" transform="translate(580)"/><use xlink:href="#pclk" transform="translate(600)"/><use xlink:href="#nclk" transform="translate(620)"/><use xlink:href="#pclk" transform="translate(640)"/><use xlink:href="#nclk" transform="translate(660)"/><use xlink:href="#pclk" transform="translate(680)"/><use xlink:href="#nclk" transform="translate(700)"/><use xlink:href="#pclk" transform="translate(720)"/><use xlink:href="#nclk" transform="translate(740)"/><use xlink:href="#pclk" transform="translate(760)"/><use xlink:href="#nclk" transform="translate(780)"/><use xlink:href="#pclk" transform="translate(800)"/><use xlink:href="#nclk" transform="translate(820)"/><use xlink:href="#pclk" transform="translate(840)"/><use xlink:href="#nclk" transform="translate(860)"/><use xlink:href="#pclk" transform="translate(880)"/><use xlink:href="#nclk" transform="translate(900)"/><use xlink:href="#pclk" transform="translate(920)"/><use xlink:href="#nclk" transform="translate(940)"/><use xlink:href="#pclk" transform="translate(960)"/><use xlink:href="#nclk" transform="translate(980)"/><use xlink:href="#pclk" transform="translate(1000)"/><use xlink:href="#nclk" transform="translate(1020)"/><use xlink:href="#pclk" transform="translate(1040)"/><use xlink:href="#nclk" transform="translate(1060)"/><use xlink:href="#pclk" transform="translate(1080)"/><use xlink:href="#nclk" transform="translate(1100)"/><use xlink:href="#pclk" transform="translate(1120)"/><use xlink:href="#nclk" transform="translate(1140)"/><use xlink:href="#pclk" transform="translate(1160)"/><use xlink:href="#nclk" transform="translate(1180)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#111" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#111" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#111" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#111" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#111" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#111" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#111" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#111" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#111" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#111" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"/></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXIL_AWVALID</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#1m0" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#000" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#000" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#000" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXIL_WVALID</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#1m0" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#000" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#000" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#000" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXIL_AWADDR</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-3" transform="translate(80)"/><use xlink:href="#vvv-3" transform="translate(100)"/><use xlink:href="#vmv-3-4" transform="translate(120)"/><use xlink:href="#vvv-4" transform="translate(140)"/><use xlink:href="#vmv-4-5" transform="translate(160)"/><use xlink:href="#vvv-5" transform="translate(180)"/><use xlink:href="#vmv-5-6" transform="translate(200)"/><use xlink:href="#vvv-6" transform="translate(220)"/><use xlink:href="#vmx-6" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xxx" transform="translate(400)"/><use xlink:href="#xxx" transform="translate(420)"/><use xlink:href="#xxx" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><use xlink:href="#xxx" transform="translate(760)"/><use xlink:href="#xxx" transform="translate(780)"/><use xlink:href="#xxx" transform="translate(800)"/><use xlink:href="#xxx" transform="translate(820)"/><use xlink:href="#xxx" transform="translate(840)"/><use xlink:href="#xxx" transform="translate(860)"/><use xlink:href="#xxx" transform="translate(880)"/><use xlink:href="#xxx" transform="translate(900)"/><use xlink:href="#xxx" transform="translate(920)"/><use xlink:href="#xxx" transform="translate(940)"/><use xlink:href="#xxx" transform="translate(960)"/><use xlink:href="#xxx" transform="translate(980)"/><use xlink:href="#xxx" transform="translate(1000)"/><use xlink:href="#xxx" transform="translate(1020)"/><use xlink:href="#xxx" transform="translate(1040)"/><use xlink:href="#xxx" transform="translate(1060)"/><use xlink:href="#xxx" transform="translate(1080)"/><use xlink:href="#xxx" transform="translate(1100)"/><use xlink:href="#xxx" transform="translate(1120)"/><use xlink:href="#xxx" transform="translate(1140)"/><use xlink:href="#xxx" transform="translate(1160)"/><use xlink:href="#xxx" transform="translate(1180)"/><text x="106" y="15" text-anchor="middle" xml:space="preserve"><tspan>LEN</tspan></text><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>DST</tspan></text><text x="186" y="15" text-anchor="middle" xml:space="preserve"><tspan>SRC</tspan></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>GO</tspan></text></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"/></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_ARVALID</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#0m1" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#1m0" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#0m1" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#1m0" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#0m1" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#1m0" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#000" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#000" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#000" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_ARADDR</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xmv-3" transform="translate(280)"/><use xlink:href="#vvv-3" transform="translate(300)"/><use xlink:href="#vmx-3" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xmv-5" transform="translate(360)"/><use xlink:href="#vvv-5" transform="translate(380)"/><use xlink:href="#vmx-5" transform="translate(400)"/><use xlink:href="#xxx" transform="translate(420)"/><use xlink:href="#xxx" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><use xlink:href="#xxx" transform="translate(760)"/><use xlink:href="#xxx" transform="translate(780)"/><use xlink:href="#xxx" transform="translate(800)"/><use xlink:href="#xxx" transform="translate(820)"/><use xlink:href="#xxx" transform="translate(840)"/><use xlink:href="#xxx" transform="translate(860)"/><use xlink:href="#xmv-3" transform="translate(880)"/><use xlink:href="#vvv-3" transform="translate(900)"/><use xlink:href="#vmx-3" transform="translate(920)"/><use xlink:href="#xxx" transform="translate(940)"/><use xlink:href="#xxx" transform="translate(960)"/><use xlink:href="#xxx" transform="translate(980)"/><use xlink:href="#xxx" transform="translate(1000)"/><use xlink:href="#xxx" transform="translate(1020)"/><use xlink:href="#xxx" transform="translate(1040)"/><use xlink:href="#xxx" transform="translate(1060)"/><use xlink:href="#xxx" transform="translate(1080)"/><use xlink:href="#xxx" transform="translate(1100)"/><use xlink:href="#xxx" transform="translate(1120)"/><use xlink:href="#xxx" transform="translate(1140)"/><use xlink:href="#xxx" transform="translate(1160)"/><use xlink:href="#xxx" transform="translate(1180)"/><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>A0</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>A2</tspan></text><text x="906" y="15" text-anchor="middle" xml:space="preserve"><tspan>AA</tspan></text></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_ARLEN</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xmv-3" transform="translate(280)"/><use xlink:href="#vvv-3" transform="translate(300)"/><use xlink:href="#vmx-3" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xmv-5" transform="translate(360)"/><use xlink:href="#vvv-5" transform="translate(380)"/><use xlink:href="#vmx-5" transform="translate(400)"/><use xlink:href="#xxx" transform="translate(420)"/><use xlink:href="#xxx" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><use xlink:href="#xxx" transform="translate(760)"/><use xlink:href="#xxx" transform="translate(780)"/><use xlink:href="#xxx" transform="translate(800)"/><use xlink:href="#xxx" transform="translate(820)"/><use xlink:href="#xxx" transform="translate(840)"/><use xlink:href="#xxx" transform="translate(860)"/><use xlink:href="#xmv-3" transform="translate(880)"/><use xlink:href="#vvv-3" transform="translate(900)"/><use xlink:href="#vmx-3" transform="translate(920)"/><use xlink:href="#xxx" transform="translate(940)"/><use xlink:href="#xxx" transform="translate(960)"/><use xlink:href="#xxx" transform="translate(980)"/><use xlink:href="#xxx" transform="translate(1000)"/><use xlink:href="#xxx" transform="translate(1020)"/><use xlink:href="#xxx" transform="translate(1040)"/><use xlink:href="#xxx" transform="translate(1060)"/><use xlink:href="#xxx" transform="translate(1080)"/><use xlink:href="#xxx" transform="translate(1100)"/><use xlink:href="#xxx" transform="translate(1120)"/><use xlink:href="#xxx" transform="translate(1140)"/><use xlink:href="#xxx" transform="translate(1160)"/><use xlink:href="#xxx" transform="translate(1180)"/><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>1</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>7</tspan></text><text x="906" y="15" text-anchor="middle" xml:space="preserve"><tspan>0</tspan></text></g></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"/></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_RVALID</tspan></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#0m1" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#1m0" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#0m1" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#1m0" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#000" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#000" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#000" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/></g></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_RDATA</tspan></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xmv-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vmv-3-4" transform="translate(360)"/><use xlink:href="#vvv-4" transform="translate(380)"/><use xlink:href="#vmv-4-5" transform="translate(400)"/><use xlink:href="#vvv-5" transform="translate(420)"/><use xlink:href="#vmv-5-6" transform="translate(440)"/><use xlink:href="#vvv-6" transform="translate(460)"/><use xlink:href="#vmv-6-7" transform="translate(480)"/><use xlink:href="#vvv-7" transform="translate(500)"/><use xlink:href="#vmv-7-3" transform="translate(520)"/><use xlink:href="#vvv-3" transform="translate(540)"/><use xlink:href="#vmv-3-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmv-4-5" transform="translate(600)"/><use xlink:href="#vvv-5" transform="translate(620)"/><use xlink:href="#vmv-5-6" transform="translate(640)"/><use xlink:href="#vvv-6" transform="translate(660)"/><use xlink:href="#vmv-6-7" transform="translate(680)"/><use xlink:href="#vvv-7" transform="translate(700)"/><use xlink:href="#vmx-7" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><use xlink:href="#xxx" transform="translate(760)"/><use xlink:href="#xxx" transform="translate(780)"/><use xlink:href="#xxx" transform="translate(800)"/><use xlink:href="#xxx" transform="translate(820)"/><use xlink:href="#xxx" transform="translate(840)"/><use xlink:href="#xxx" transform="translate(860)"/><use xlink:href="#xxx" transform="translate(880)"/><use xlink:href="#xxx" transform="translate(900)"/><use xlink:href="#xxx" transform="translate(920)"/><use xlink:href="#xxx" transform="translate(940)"/><use xlink:href="#xmv-3" transform="translate(960)"/><use xlink:href="#vvv-3" transform="translate(980)"/><use xlink:href="#vmx-3" transform="translate(1000)"/><use xlink:href="#xxx" transform="translate(1020)"/><use xlink:href="#xxx" transform="translate(1040)"/><use xlink:href="#xxx" transform="translate(1060)"/><use xlink:href="#xxx" transform="translate(1080)"/><use xlink:href="#xxx" transform="translate(1100)"/><use xlink:href="#xxx" transform="translate(1120)"/><use xlink:href="#xxx" transform="translate(1140)"/><use xlink:href="#xxx" transform="translate(1160)"/><use xlink:href="#xxx" transform="translate(1180)"/><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>D0</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>D1</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>D2</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>D3</tspan></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan>D4</tspan></text><text x="546" y="15" text-anchor="middle" xml:space="preserve"><tspan>D5</tspan></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan>D6</tspan></text><text x="626" y="15" text-anchor="middle" xml:space="preserve"><tspan>D7</tspan></text><text x="666" y="15" text-anchor="middle" xml:space="preserve"><tspan>D8</tspan></text><text x="706" y="15" text-anchor="middle" xml:space="preserve"><tspan>D9</tspan></text><text x="986" y="15" text-anchor="middle" xml:space="preserve"><tspan>DA</tspan></text></g></g><g id="wavelane_13_0" transform="translate(0,395)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_RLAST</tspan></text><g id="wavelane_draw_13_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xm0" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#0m1" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#1m0" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#0m1" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#1mx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><use xlink:href="#xxx" transform="translate(760)"/><use xlink:href="#xxx" transform="translate(780)"/><use xlink:href="#xxx" transform="translate(800)"/><use xlink:href="#xxx" transform="translate(820)"/><use xlink:href="#xxx" transform="translate(840)"/><use xlink:href="#xxx" transform="translate(860)"/><use xlink:href="#xxx" transform="translate(880)"/><use xlink:href="#xxx" transform="translate(900)"/><use xlink:href="#xxx" transform="translate(920)"/><use xlink:href="#xxx" transform="translate(940)"/><use xlink:href="#xm1" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#1mx" transform="translate(1000)"/><use xlink:href="#xxx" transform="translate(1020)"/><use xlink:href="#xxx" transform="translate(1040)"/><use xlink:href="#xxx" transform="translate(1060)"/><use xlink:href="#xxx" transform="translate(1080)"/><use xlink:href="#xxx" transform="translate(1100)"/><use xlink:href="#xxx" transform="translate(1120)"/><use xlink:href="#xxx" transform="translate(1140)"/><use xlink:href="#xxx" transform="translate(1160)"/><use xlink:href="#xxx" transform="translate(1180)"/></g></g><g id="wavelane_14_0" transform="translate(0,425)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_14_0" transform="translate(0, 0)"/></g><g id="wavelane_15_0" transform="translate(0,455)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_AWVALID</tspan></text><g id="wavelane_draw_15_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#0m1" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#1m0" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#0m1" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#1m0" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#0m1" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#1m0" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#000" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#000" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/></g></g><g id="wavelane_16_0" transform="translate(0,485)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_AWADDR</tspan></text><g id="wavelane_draw_16_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xmv-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmx-3" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xmv-4" transform="translate(720)"/><use xlink:href="#vvv-4" transform="translate(740)"/><use xlink:href="#vmx-4" transform="translate(760)"/><use xlink:href="#xxx" transform="translate(780)"/><use xlink:href="#xxx" transform="translate(800)"/><use xlink:href="#xxx" transform="translate(820)"/><use xlink:href="#xxx" transform="translate(840)"/><use xlink:href="#xxx" transform="translate(860)"/><use xlink:href="#xxx" transform="translate(880)"/><use xlink:href="#xxx" transform="translate(900)"/><use xlink:href="#xxx" transform="translate(920)"/><use xlink:href="#xxx" transform="translate(940)"/><use xlink:href="#xxx" transform="translate(960)"/><use xlink:href="#xxx" transform="translate(980)"/><use xlink:href="#xxx" transform="translate(1000)"/><use xlink:href="#xxx" transform="translate(1020)"/><use xlink:href="#xmv-7" transform="translate(1040)"/><use xlink:href="#vvv-7" transform="translate(1060)"/><use xlink:href="#vmx-7" transform="translate(1080)"/><use xlink:href="#xxx" transform="translate(1100)"/><use xlink:href="#xxx" transform="translate(1120)"/><use xlink:href="#xxx" transform="translate(1140)"/><use xlink:href="#xxx" transform="translate(1160)"/><use xlink:href="#xxx" transform="translate(1180)"/><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>a0</tspan></text><text x="746" y="15" text-anchor="middle" xml:space="preserve"><tspan>a1</tspan></text><text x="1066" y="15" text-anchor="middle" xml:space="preserve"><tspan>a9</tspan></text></g></g><g id="wavelane_17_0" transform="translate(0,515)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_AWLEN</tspan></text><g id="wavelane_draw_17_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xmv-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmx-3" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xmv-4" transform="translate(720)"/><use xlink:href="#vvv-4" transform="translate(740)"/><use xlink:href="#vmx-4" transform="translate(760)"/><use xlink:href="#xxx" transform="translate(780)"/><use xlink:href="#xxx" transform="translate(800)"/><use xlink:href="#xxx" transform="translate(820)"/><use xlink:href="#xxx" transform="translate(840)"/><use xlink:href="#xxx" transform="translate(860)"/><use xlink:href="#xxx" transform="translate(880)"/><use xlink:href="#xxx" transform="translate(900)"/><use xlink:href="#xxx" transform="translate(920)"/><use xlink:href="#xxx" transform="translate(940)"/><use xlink:href="#xxx" transform="translate(960)"/><use xlink:href="#xxx" transform="translate(980)"/><use xlink:href="#xxx" transform="translate(1000)"/><use xlink:href="#xxx" transform="translate(1020)"/><use xlink:href="#xmv-7" transform="translate(1040)"/><use xlink:href="#vvv-7" transform="translate(1060)"/><use xlink:href="#vmx-7" transform="translate(1080)"/><use xlink:href="#xxx" transform="translate(1100)"/><use xlink:href="#xxx" transform="translate(1120)"/><use xlink:href="#xxx" transform="translate(1140)"/><use xlink:href="#xxx" transform="translate(1160)"/><use xlink:href="#xxx" transform="translate(1180)"/><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>0</tspan></text><text x="746" y="15" text-anchor="middle" xml:space="preserve"><tspan>7</tspan></text><text x="1066" y="15" text-anchor="middle" xml:space="preserve"><tspan>1</tspan></text></g></g><g id="wavelane_18_0" transform="translate(0,545)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_18_0" transform="translate(0, 0)"/></g><g id="wavelane_19_0" transform="translate(0,575)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_WVALID</tspan></text><g id="wavelane_draw_19_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#0m1" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#1m0" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#0m1" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#111" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#111" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#111" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#111" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#111" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#111" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#111" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#111" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#1m0" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#000" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/></g></g><g id="wavelane_20_0" transform="translate(0,605)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_WDATA</tspan></text><g id="wavelane_draw_20_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xmv-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmx-3" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xmv-4" transform="translate(720)"/><use xlink:href="#vvv-4" transform="translate(740)"/><use xlink:href="#vmv-4-5" transform="translate(760)"/><use xlink:href="#vvv-5" transform="translate(780)"/><use xlink:href="#vmv-5-6" transform="translate(800)"/><use xlink:href="#vvv-6" transform="translate(820)"/><use xlink:href="#vmv-6-7" transform="translate(840)"/><use xlink:href="#vvv-7" transform="translate(860)"/><use xlink:href="#vmv-7-3" transform="translate(880)"/><use xlink:href="#vvv-3" transform="translate(900)"/><use xlink:href="#vmv-3-4" transform="translate(920)"/><use xlink:href="#vvv-4" transform="translate(940)"/><use xlink:href="#vmv-4-5" transform="translate(960)"/><use xlink:href="#vvv-5" transform="translate(980)"/><use xlink:href="#vmv-5-6" transform="translate(1000)"/><use xlink:href="#vvv-6" transform="translate(1020)"/><use xlink:href="#vmv-6-7" transform="translate(1040)"/><use xlink:href="#vvv-7" transform="translate(1060)"/><use xlink:href="#vmv-7-3" transform="translate(1080)"/><use xlink:href="#vvv-3" transform="translate(1100)"/><use xlink:href="#vmx-3" transform="translate(1120)"/><use xlink:href="#xxx" transform="translate(1140)"/><use xlink:href="#xxx" transform="translate(1160)"/><use xlink:href="#xxx" transform="translate(1180)"/><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>D0</tspan></text><text x="746" y="15" text-anchor="middle" xml:space="preserve"><tspan>D1</tspan></text><text x="786" y="15" text-anchor="middle" xml:space="preserve"><tspan>D2</tspan></text><text x="826" y="15" text-anchor="middle" xml:space="preserve"><tspan>D3</tspan></text><text x="866" y="15" text-anchor="middle" xml:space="preserve"><tspan>D4</tspan></text><text x="906" y="15" text-anchor="middle" xml:space="preserve"><tspan>D5</tspan></text><text x="946" y="15" text-anchor="middle" xml:space="preserve"><tspan>D6</tspan></text><text x="986" y="15" text-anchor="middle" xml:space="preserve"><tspan>D7</tspan></text><text x="1026" y="15" text-anchor="middle" xml:space="preserve"><tspan>D8</tspan></text><text x="1066" y="15" text-anchor="middle" xml:space="preserve"><tspan>D9</tspan></text><text x="1106" y="15" text-anchor="middle" xml:space="preserve"><tspan>DA</tspan></text></g></g><g id="wavelane_21_0" transform="translate(0,635)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_WLAST</tspan></text><g id="wavelane_draw_21_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xm1" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#1mx" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xm0" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#0m1" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#1m0" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#0m1" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#1mx" transform="translate(1120)"/><use xlink:href="#xxx" transform="translate(1140)"/><use xlink:href="#xxx" transform="translate(1160)"/><use xlink:href="#xxx" transform="translate(1180)"/></g></g><g id="wavelane_22_0" transform="translate(0,665)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_22_0" transform="translate(0, 0)"/></g><g id="wavelane_23_0" transform="translate(0,695)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_BVALID</tspan></text><g id="wavelane_draw_23_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#0mv-3" transform="translate(440)"/><use xlink:href="#vvv-3" transform="translate(460)"/><use xlink:href="#vm0-3" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#0mv-4" transform="translate(1040)"/><use xlink:href="#vvv-4" transform="translate(1060)"/><use xlink:href="#vm0-4" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#0mv-7" transform="translate(1120)"/><use xlink:href="#vvv-7" transform="translate(1140)"/><use xlink:href="#vm0-7" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/></g></g><g id="wavelane_24_0" transform="translate(0,725)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_24_0" transform="translate(0, 0)"/></g><g id="wavelane_25_0" transform="translate(0,755)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>fifo_fill</tspan></text><g id="wavelane_draw_25_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xmv-2" transform="translate(40)"/><use xlink:href="#vvv-2" transform="translate(60)"/><use xlink:href="#vvv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vvv-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vvv-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vvv-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vvv-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vvv-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vvv-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vmv-2-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vmv-3-4" transform="translate(400)"/><use xlink:href="#vvv-4" transform="translate(420)"/><use xlink:href="#vvv-4" transform="translate(440)"/><use xlink:href="#vvv-4" transform="translate(460)"/><use xlink:href="#vmv-4-5" transform="translate(480)"/><use xlink:href="#vvv-5" transform="translate(500)"/><use xlink:href="#vmv-5-6" transform="translate(520)"/><use xlink:href="#vvv-6" transform="translate(540)"/><use xlink:href="#vmv-6-7" transform="translate(560)"/><use xlink:href="#vvv-7" transform="translate(580)"/><use xlink:href="#vmv-7-3" transform="translate(600)"/><use xlink:href="#vvv-3" transform="translate(620)"/><use xlink:href="#vmv-3-4" transform="translate(640)"/><use xlink:href="#vvv-4" transform="translate(660)"/><use xlink:href="#vmv-4-5" transform="translate(680)"/><use xlink:href="#vvv-5" transform="translate(700)"/><use xlink:href="#vmv-5-6" transform="translate(720)"/><use xlink:href="#vvv-6" transform="translate(740)"/><use xlink:href="#vmv-6-3" transform="translate(760)"/><use xlink:href="#vvv-3" transform="translate(780)"/><use xlink:href="#vmv-3-4" transform="translate(800)"/><use xlink:href="#vvv-4" transform="translate(820)"/><use xlink:href="#vmv-4-5" transform="translate(840)"/><use xlink:href="#vvv-5" transform="translate(860)"/><use xlink:href="#vmv-5-6" transform="translate(880)"/><use xlink:href="#vvv-6" transform="translate(900)"/><use xlink:href="#vmv-6-7" transform="translate(920)"/><use xlink:href="#vvv-7" transform="translate(940)"/><use xlink:href="#vmv-7-3" transform="translate(960)"/><use xlink:href="#vvv-3" transform="translate(980)"/><use xlink:href="#vvv-3" transform="translate(1000)"/><use xlink:href="#vvv-3" transform="translate(1020)"/><use xlink:href="#vmv-3-4" transform="translate(1040)"/><use xlink:href="#vvv-4" transform="translate(1060)"/><use xlink:href="#vmv-4-5" transform="translate(1080)"/><use xlink:href="#vvv-5" transform="translate(1100)"/><use xlink:href="#vmv-5-2" transform="translate(1120)"/><use xlink:href="#vvv-2" transform="translate(1140)"/><use xlink:href="#vvv-2" transform="translate(1160)"/><use xlink:href="#vvv-2" transform="translate(1180)"/><text x="206" y="15" text-anchor="middle" xml:space="preserve"><tspan>0</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>1</tspan></text><text x="446" y="15" text-anchor="middle" xml:space="preserve"><tspan>2</tspan></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan>3</tspan></text><text x="546" y="15" text-anchor="middle" xml:space="preserve"><tspan>4</tspan></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan>5</tspan></text><text x="626" y="15" text-anchor="middle" xml:space="preserve"><tspan>6</tspan></text><text x="666" y="15" text-anchor="middle" xml:space="preserve"><tspan>7</tspan></text><text x="706" y="15" text-anchor="middle" xml:space="preserve"><tspan>8</tspan></text><text x="746" y="15" text-anchor="middle" xml:space="preserve"><tspan>9</tspan></text><text x="786" y="15" text-anchor="middle" xml:space="preserve"><tspan>8</tspan></text><text x="826" y="15" text-anchor="middle" xml:space="preserve"><tspan>7</tspan></text><text x="866" y="15" text-anchor="middle" xml:space="preserve"><tspan>6</tspan></text><text x="906" y="15" text-anchor="middle" xml:space="preserve"><tspan>5</tspan></text><text x="946" y="15" text-anchor="middle" xml:space="preserve"><tspan>4</tspan></text><text x="1006" y="15" text-anchor="middle" xml:space="preserve"><tspan>3</tspan></text><text x="1066" y="15" text-anchor="middle" xml:space="preserve"><tspan>2</tspan></text><text x="1106" y="15" text-anchor="middle" xml:space="preserve"><tspan>1</tspan></text><text x="1166" y="15" text-anchor="middle" xml:space="preserve"><tspan>0</tspan></text></g></g><g id="wavelane_26_0" transform="translate(0,785)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>r_busy</tspan></text><g id="wavelane_draw_26_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0m1" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#111" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#111" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#111" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#111" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#111" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#111" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#111" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#111" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#1m0" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#000" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/></g></g><g id="wavelane_27_0" transform="translate(0,815)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>o_int</tspan></text><g id="wavelane_draw_27_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#000" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#0m1" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#1m0" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/><g id="wavegap_13_0" transform="translate(0,395)"/><g id="wavegap_14_0" transform="translate(0,425)"/><g id="wavegap_15_0" transform="translate(0,455)"/><g id="wavegap_16_0" transform="translate(0,485)"/><g id="wavegap_17_0" transform="translate(0,515)"/><g id="wavegap_18_0" transform="translate(0,545)"/><g id="wavegap_19_0" transform="translate(0,575)"/><g id="wavegap_20_0" transform="translate(0,605)"/><g id="wavegap_21_0" transform="translate(0,635)"/><g id="wavegap_22_0" transform="translate(0,665)"/><g id="wavegap_23_0" transform="translate(0,695)"/><g id="wavegap_24_0" transform="translate(0,725)"/><g id="wavegap_25_0" transform="translate(0,755)"/><g id="wavegap_26_0" transform="translate(0,785)"/><g id="wavegap_27_0" transform="translate(0,815)"/></g></g><g id="groups_0"><g/></g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-read.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-read.json
new file mode 100644
index 0000000..da5bfb5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-read.json
@@ -0,0 +1,19 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'p...................'},
+  {name: 'S_AXI_ARESETN', wave: '01..................', data: ['B7','B6','B5 ...']},
+  {},
+  {name: 'S_AXI_ARVALID', wave: '0.1x..1x..10........'},
+  {name: 'S_AXI_ARREADY', wave: '1..0..10..10........'},
+  {name: 'S_AXI_ARLEN',   wave: 'x.2x..3x..4x........', data: ['3','3','3','3','3']},
+  {name: 'S_AXI_ARADDR',  wave: 'x.2x..3x..4x........', data: ['A0','A1','A2','A3','A4']},
+  {},
+  {name: 'S_AXI_RVALID',  wave: '0.....1...........0.'},
+  {name: 'S_AXI_RREADY',  wave: 'x.....1...........x.'},
+  {name: 'S_AXI_RDATA',   wave: 'x.....2222333344440.', data: ['D0','','','','D1','','','','D2','','','','D3','','','']},
+  {name: 'S_AXI_RLAST',   wave: 'x0.......20..30..40.'},
+  {},
+  {name: 'M_AXI_ARVALID', wave: '0..2...3...4...0....', data: ['S0','S1','S2']},
+  {name: '(M_AXI_RVALID)',wave: 'x...1...........0...'},
+  {name: 'M_AXI_RDATA',   wave: 'x...2222333344440...', data: ['D0','','','','D1','','','','D2','','','','D3','','','']},
+  {},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-read.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-read.png
new file mode 100644
index 0000000..a9843c5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-read.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-read.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-read.svg
new file mode 100644
index 0000000..e9a8908
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-read.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="510" width="980" viewBox="0 0 980 510" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{fill:#000;fill-opacity:1;stroke:none}.s7{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s10{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{color:#000;fill:#ccfdfe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s12{color:#000;fill:#cdfdc5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s13{color:#000;fill:#f0c1fb;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s14{color:#000;fill:#f5c2c0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s15{fill:#0041c4;fill-opacity:1;stroke:none}.s16{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s6"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s6"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s9"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s9"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s9"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s9"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s9"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s9"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-6"><path d="M2.875,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-6"><path d="M3,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-6"><path d="M20,20 0,20 0,0 20,0" class="s11"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-6"><path d="M0,20 0,0 3,0 9,20" class="s11"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-6"><path d="M0,0 0,20 3,20 9,0" class="s11"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-6"><path d="M0,0 0,20 3,20 6,10 3,0" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-6"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s11"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-6"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s11"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-6"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s11"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-7"><path d="M2.875,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-7"><path d="M3,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-7"><path d="M20,20 0,20 0,0 20,0" class="s12"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-7"><path d="M0,20 0,0 3,0 9,20" class="s12"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-7"><path d="M0,0 0,20 3,20 9,0" class="s12"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-7"><path d="M0,0 0,20 3,20 6,10 3,0" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-7"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s12"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-7"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s12"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-7"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s12"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-8"><path d="M2.875,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-8"><path d="M3,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-8"><path d="M20,20 0,20 0,0 20,0" class="s13"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-8"><path d="M0,20 0,0 3,0 9,20" class="s13"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-8"><path d="M0,0 0,20 3,20 9,0" class="s13"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-8"><path d="M0,0 0,20 3,20 6,10 3,0" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-8"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s13"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-8"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s13"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-8"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s13"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-9"><path d="M2.875,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-9"><path d="M3,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-9"><path d="M20,20 0,20 0,0 20,0" class="s14"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-9"><path d="M0,20 0,0 3,0 9,20" class="s14"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-9"><path d="M0,0 0,20 3,20 9,0" class="s14"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-9"><path d="M0,0 0,20 3,20 6,10 3,0" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-9"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s14"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-9"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s14"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-9"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s14"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s15"/><path d="M0,0 -15,0" class="s16"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_1_0" d="m 40,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_2_0" d="m 80,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_3_0" d="m 120,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_4_0" d="m 160,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_5_0" d="m 200,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_6_0" d="m 240,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_7_0" d="m 280,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_8_0" d="m 320,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_9_0" d="m 360,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_10_0" d="m 400,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_11_0" d="m 440,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_12_0" d="m 480,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_13_0" d="m 520,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_14_0" d="m 560,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_15_0" d="m 600,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_16_0" d="m 640,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_17_0" d="m 680,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_18_0" d="m 720,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_19_0" d="m 760,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_20_0" d="m 800,0 0,510" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/><use xlink:href="#pclk" transform="translate(200)"/><use xlink:href="#nclk" transform="translate(220)"/><use xlink:href="#pclk" transform="translate(240)"/><use xlink:href="#nclk" transform="translate(260)"/><use xlink:href="#pclk" transform="translate(280)"/><use xlink:href="#nclk" transform="translate(300)"/><use xlink:href="#pclk" transform="translate(320)"/><use xlink:href="#nclk" transform="translate(340)"/><use xlink:href="#pclk" transform="translate(360)"/><use xlink:href="#nclk" transform="translate(380)"/><use xlink:href="#pclk" transform="translate(400)"/><use xlink:href="#nclk" transform="translate(420)"/><use xlink:href="#pclk" transform="translate(440)"/><use xlink:href="#nclk" transform="translate(460)"/><use xlink:href="#pclk" transform="translate(480)"/><use xlink:href="#nclk" transform="translate(500)"/><use xlink:href="#pclk" transform="translate(520)"/><use xlink:href="#nclk" transform="translate(540)"/><use xlink:href="#pclk" transform="translate(560)"/><use xlink:href="#nclk" transform="translate(580)"/><use xlink:href="#pclk" transform="translate(600)"/><use xlink:href="#nclk" transform="translate(620)"/><use xlink:href="#pclk" transform="translate(640)"/><use xlink:href="#nclk" transform="translate(660)"/><use xlink:href="#pclk" transform="translate(680)"/><use xlink:href="#nclk" transform="translate(700)"/><use xlink:href="#pclk" transform="translate(720)"/><use xlink:href="#nclk" transform="translate(740)"/><use xlink:href="#pclk" transform="translate(760)"/><use xlink:href="#nclk" transform="translate(780)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"/></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARVALID</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1mx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xm1" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#1mx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xm1" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#1m0" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARREADY</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#111" transform="translate(0)"/><use xlink:href="#111" transform="translate(20)"/><use xlink:href="#111" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1m0" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0m1" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#1m0" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#0m1" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#1m0" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARLEN</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vmx-2" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xmv-3" transform="translate(240)"/><use xlink:href="#vvv-3" transform="translate(260)"/><use xlink:href="#vmx-3" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xmv-4" transform="translate(400)"/><use xlink:href="#vvv-4" transform="translate(420)"/><use xlink:href="#vmx-4" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><use xlink:href="#xxx" transform="translate(760)"/><use xlink:href="#xxx" transform="translate(780)"/><text x="106" y="15" text-anchor="middle" xml:space="preserve"><tspan>3</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>3</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>3</tspan></text></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARADDR</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vmx-2" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xmv-3" transform="translate(240)"/><use xlink:href="#vvv-3" transform="translate(260)"/><use xlink:href="#vmx-3" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xmv-4" transform="translate(400)"/><use xlink:href="#vvv-4" transform="translate(420)"/><use xlink:href="#vmx-4" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><use xlink:href="#xxx" transform="translate(760)"/><use xlink:href="#xxx" transform="translate(780)"/><text x="106" y="15" text-anchor="middle" xml:space="preserve"><tspan>A0</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>A1</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>A2</tspan></text></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"/></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RVALID</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0m1" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#1m0" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RREADY</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xm1" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#1mx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><use xlink:href="#xxx" transform="translate(760)"/><use xlink:href="#xxx" transform="translate(780)"/></g></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RDATA</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xmv-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vmv-2-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vmv-2-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vmv-2-2" transform="translate(360)"/><use xlink:href="#vvv-2" transform="translate(380)"/><use xlink:href="#vmv-2-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmv-3-3" transform="translate(440)"/><use xlink:href="#vvv-3" transform="translate(460)"/><use xlink:href="#vmv-3-3" transform="translate(480)"/><use xlink:href="#vvv-3" transform="translate(500)"/><use xlink:href="#vmv-3-3" transform="translate(520)"/><use xlink:href="#vvv-3" transform="translate(540)"/><use xlink:href="#vmv-3-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmv-4-4" transform="translate(600)"/><use xlink:href="#vvv-4" transform="translate(620)"/><use xlink:href="#vmv-4-4" transform="translate(640)"/><use xlink:href="#vvv-4" transform="translate(660)"/><use xlink:href="#vmv-4-4" transform="translate(680)"/><use xlink:href="#vvv-4" transform="translate(700)"/><use xlink:href="#vm0-4" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>D0</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>D1</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="546" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan>D2</tspan></text><text x="626" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="666" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="706" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RLAST</tspan></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xm0" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#0mv-2" transform="translate(360)"/><use xlink:href="#vvv-2" transform="translate(380)"/><use xlink:href="#vm0-2" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#0mv-3" transform="translate(520)"/><use xlink:href="#vvv-3" transform="translate(540)"/><use xlink:href="#vm0-3" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#0mv-4" transform="translate(680)"/><use xlink:href="#vvv-4" transform="translate(700)"/><use xlink:href="#vm0-4" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/></g></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"/></g><g id="wavelane_13_0" transform="translate(0,395)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_ARVALID</tspan></text><g id="wavelane_draw_13_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0mv-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vvv-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vvv-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vvv-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vmv-2-3" transform="translate(280)"/><use xlink:href="#vvv-3" transform="translate(300)"/><use xlink:href="#vvv-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vvv-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vvv-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmv-3-4" transform="translate(440)"/><use xlink:href="#vvv-4" transform="translate(460)"/><use xlink:href="#vvv-4" transform="translate(480)"/><use xlink:href="#vvv-4" transform="translate(500)"/><use xlink:href="#vvv-4" transform="translate(520)"/><use xlink:href="#vvv-4" transform="translate(540)"/><use xlink:href="#vvv-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vm0-4" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><text x="206" y="15" text-anchor="middle" xml:space="preserve"><tspan>S0</tspan></text><text x="366" y="15" text-anchor="middle" xml:space="preserve"><tspan>S1</tspan></text><text x="526" y="15" text-anchor="middle" xml:space="preserve"><tspan>S2</tspan></text></g></g><g id="wavelane_14_0" transform="translate(0,425)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>(M_AXI_RVALID)</tspan></text><g id="wavelane_draw_14_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xm1" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#1m0" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/></g></g><g id="wavelane_15_0" transform="translate(0,455)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_RDATA</tspan></text><g id="wavelane_draw_15_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xmv-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vmv-2-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vmv-2-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vmv-2-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vmv-2-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vmv-3-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vmv-3-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmv-3-3" transform="translate(440)"/><use xlink:href="#vvv-3" transform="translate(460)"/><use xlink:href="#vmv-3-4" transform="translate(480)"/><use xlink:href="#vvv-4" transform="translate(500)"/><use xlink:href="#vmv-4-4" transform="translate(520)"/><use xlink:href="#vvv-4" transform="translate(540)"/><use xlink:href="#vmv-4-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmv-4-4" transform="translate(600)"/><use xlink:href="#vvv-4" transform="translate(620)"/><use xlink:href="#vm0-4" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><text x="186" y="15" text-anchor="middle" xml:space="preserve"><tspan>D0</tspan></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>D1</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan>D2</tspan></text><text x="546" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="626" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text></g></g><g id="wavelane_16_0" transform="translate(0,485)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_16_0" transform="translate(0, 0)"/></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/><g id="wavegap_13_0" transform="translate(0,395)"/><g id="wavegap_14_0" transform="translate(0,425)"/><g id="wavegap_15_0" transform="translate(0,455)"/><g id="wavegap_16_0" transform="translate(0,485)"/></g></g><g id="groups_0">g</g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-write.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-write.json
new file mode 100644
index 0000000..da5bfb5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-write.json
@@ -0,0 +1,19 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'p...................'},
+  {name: 'S_AXI_ARESETN', wave: '01..................', data: ['B7','B6','B5 ...']},
+  {},
+  {name: 'S_AXI_ARVALID', wave: '0.1x..1x..10........'},
+  {name: 'S_AXI_ARREADY', wave: '1..0..10..10........'},
+  {name: 'S_AXI_ARLEN',   wave: 'x.2x..3x..4x........', data: ['3','3','3','3','3']},
+  {name: 'S_AXI_ARADDR',  wave: 'x.2x..3x..4x........', data: ['A0','A1','A2','A3','A4']},
+  {},
+  {name: 'S_AXI_RVALID',  wave: '0.....1...........0.'},
+  {name: 'S_AXI_RREADY',  wave: 'x.....1...........x.'},
+  {name: 'S_AXI_RDATA',   wave: 'x.....2222333344440.', data: ['D0','','','','D1','','','','D2','','','','D3','','','']},
+  {name: 'S_AXI_RLAST',   wave: 'x0.......20..30..40.'},
+  {},
+  {name: 'M_AXI_ARVALID', wave: '0..2...3...4...0....', data: ['S0','S1','S2']},
+  {name: '(M_AXI_RVALID)',wave: 'x...1...........0...'},
+  {name: 'M_AXI_RDATA',   wave: 'x...2222333344440...', data: ['D0','','','','D1','','','','D2','','','','D3','','','']},
+  {},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-write.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-write.png
new file mode 100644
index 0000000..cfa20d2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-write.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-write.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-write.svg
new file mode 100644
index 0000000..a8a28b3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axidouble-write.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="570" width="1140" viewBox="0 0 1140 570" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{fill:#000;fill-opacity:1;stroke:none}.s7{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s10{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{color:#000;fill:#ccfdfe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s12{color:#000;fill:#cdfdc5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s13{color:#000;fill:#f0c1fb;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s14{color:#000;fill:#f5c2c0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s15{fill:#0041c4;fill-opacity:1;stroke:none}.s16{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s6"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s6"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s9"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s9"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s9"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s9"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s9"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s9"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-6"><path d="M2.875,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-6"><path d="M3,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-6"><path d="M20,20 0,20 0,0 20,0" class="s11"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-6"><path d="M0,20 0,0 3,0 9,20" class="s11"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-6"><path d="M0,0 0,20 3,20 9,0" class="s11"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-6"><path d="M0,0 0,20 3,20 6,10 3,0" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-6"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s11"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-6"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s11"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-6"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s11"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-7"><path d="M2.875,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-7"><path d="M3,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-7"><path d="M20,20 0,20 0,0 20,0" class="s12"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-7"><path d="M0,20 0,0 3,0 9,20" class="s12"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-7"><path d="M0,0 0,20 3,20 9,0" class="s12"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-7"><path d="M0,0 0,20 3,20 6,10 3,0" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-7"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s12"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-7"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s12"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-7"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s12"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-8"><path d="M2.875,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-8"><path d="M3,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-8"><path d="M20,20 0,20 0,0 20,0" class="s13"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-8"><path d="M0,20 0,0 3,0 9,20" class="s13"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-8"><path d="M0,0 0,20 3,20 9,0" class="s13"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-8"><path d="M0,0 0,20 3,20 6,10 3,0" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-8"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s13"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-8"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s13"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-8"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s13"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-9"><path d="M2.875,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-9"><path d="M3,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-9"><path d="M20,20 0,20 0,0 20,0" class="s14"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-9"><path d="M0,20 0,0 3,0 9,20" class="s14"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-9"><path d="M0,0 0,20 3,20 9,0" class="s14"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-9"><path d="M0,0 0,20 3,20 6,10 3,0" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-9"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s14"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-9"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s14"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-9"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s14"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s15"/><path d="M0,0 -15,0" class="s16"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_1_0" d="m 40,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_2_0" d="m 80,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_3_0" d="m 120,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_4_0" d="m 160,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_5_0" d="m 200,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_6_0" d="m 240,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_7_0" d="m 280,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_8_0" d="m 320,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_9_0" d="m 360,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_10_0" d="m 400,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_11_0" d="m 440,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_12_0" d="m 480,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_13_0" d="m 520,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_14_0" d="m 560,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_15_0" d="m 600,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_16_0" d="m 640,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_17_0" d="m 680,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_18_0" d="m 720,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_19_0" d="m 760,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_20_0" d="m 800,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_21_0" d="m 840,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_22_0" d="m 880,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_23_0" d="m 920,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_24_0" d="m 960,0 0,570" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/><use xlink:href="#pclk" transform="translate(200)"/><use xlink:href="#nclk" transform="translate(220)"/><use xlink:href="#pclk" transform="translate(240)"/><use xlink:href="#nclk" transform="translate(260)"/><use xlink:href="#pclk" transform="translate(280)"/><use xlink:href="#nclk" transform="translate(300)"/><use xlink:href="#pclk" transform="translate(320)"/><use xlink:href="#nclk" transform="translate(340)"/><use xlink:href="#pclk" transform="translate(360)"/><use xlink:href="#nclk" transform="translate(380)"/><use xlink:href="#pclk" transform="translate(400)"/><use xlink:href="#nclk" transform="translate(420)"/><use xlink:href="#pclk" transform="translate(440)"/><use xlink:href="#nclk" transform="translate(460)"/><use xlink:href="#pclk" transform="translate(480)"/><use xlink:href="#nclk" transform="translate(500)"/><use xlink:href="#pclk" transform="translate(520)"/><use xlink:href="#nclk" transform="translate(540)"/><use xlink:href="#pclk" transform="translate(560)"/><use xlink:href="#nclk" transform="translate(580)"/><use xlink:href="#pclk" transform="translate(600)"/><use xlink:href="#nclk" transform="translate(620)"/><use xlink:href="#pclk" transform="translate(640)"/><use xlink:href="#nclk" transform="translate(660)"/><use xlink:href="#pclk" transform="translate(680)"/><use xlink:href="#nclk" transform="translate(700)"/><use xlink:href="#pclk" transform="translate(720)"/><use xlink:href="#nclk" transform="translate(740)"/><use xlink:href="#pclk" transform="translate(760)"/><use xlink:href="#nclk" transform="translate(780)"/><use xlink:href="#pclk" transform="translate(800)"/><use xlink:href="#nclk" transform="translate(820)"/><use xlink:href="#pclk" transform="translate(840)"/><use xlink:href="#nclk" transform="translate(860)"/><use xlink:href="#pclk" transform="translate(880)"/><use xlink:href="#nclk" transform="translate(900)"/><use xlink:href="#pclk" transform="translate(920)"/><use xlink:href="#nclk" transform="translate(940)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#111" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#111" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#111" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#111" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"/></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWVALID</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1mx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xm1" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#1mx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xm1" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#1mx" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xm1" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#1mx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><use xlink:href="#xxx" transform="translate(760)"/><use xlink:href="#xxx" transform="translate(780)"/><use xlink:href="#xxx" transform="translate(800)"/><use xlink:href="#xxx" transform="translate(820)"/><use xlink:href="#xxx" transform="translate(840)"/><use xlink:href="#xxx" transform="translate(860)"/><use xlink:href="#xxx" transform="translate(880)"/><use xlink:href="#xxx" transform="translate(900)"/><use xlink:href="#xxx" transform="translate(920)"/><use xlink:href="#xxx" transform="translate(940)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWREADY</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#111" transform="translate(0)"/><use xlink:href="#111" transform="translate(20)"/><use xlink:href="#111" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1m0" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0m1" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#1m0" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#0m1" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#1m0" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#0m1" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#1m0" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWLEN</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vmx-2" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xmv-3" transform="translate(240)"/><use xlink:href="#vvv-3" transform="translate(260)"/><use xlink:href="#vmx-3" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xmv-4" transform="translate(400)"/><use xlink:href="#vvv-4" transform="translate(420)"/><use xlink:href="#vmx-4" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xmv-5" transform="translate(560)"/><use xlink:href="#vvv-5" transform="translate(580)"/><use xlink:href="#vmx-5" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><use xlink:href="#xxx" transform="translate(760)"/><use xlink:href="#xxx" transform="translate(780)"/><use xlink:href="#xxx" transform="translate(800)"/><use xlink:href="#xxx" transform="translate(820)"/><use xlink:href="#xxx" transform="translate(840)"/><use xlink:href="#xxx" transform="translate(860)"/><use xlink:href="#xxx" transform="translate(880)"/><use xlink:href="#xxx" transform="translate(900)"/><use xlink:href="#xxx" transform="translate(920)"/><use xlink:href="#xxx" transform="translate(940)"/><text x="106" y="15" text-anchor="middle" xml:space="preserve"><tspan>3</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>3</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>3</tspan></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan>3</tspan></text></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWADDR</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vmx-2" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xmv-3" transform="translate(240)"/><use xlink:href="#vvv-3" transform="translate(260)"/><use xlink:href="#vmx-3" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xmv-4" transform="translate(400)"/><use xlink:href="#vvv-4" transform="translate(420)"/><use xlink:href="#vmx-4" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xmv-5" transform="translate(560)"/><use xlink:href="#vvv-5" transform="translate(580)"/><use xlink:href="#vmx-5" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><use xlink:href="#xxx" transform="translate(760)"/><use xlink:href="#xxx" transform="translate(780)"/><use xlink:href="#xxx" transform="translate(800)"/><use xlink:href="#xxx" transform="translate(820)"/><use xlink:href="#xxx" transform="translate(840)"/><use xlink:href="#xxx" transform="translate(860)"/><use xlink:href="#xxx" transform="translate(880)"/><use xlink:href="#xxx" transform="translate(900)"/><use xlink:href="#xxx" transform="translate(920)"/><use xlink:href="#xxx" transform="translate(940)"/><text x="106" y="15" text-anchor="middle" xml:space="preserve"><tspan>A0</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>A1</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>A2</tspan></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan>A3</tspan></text></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"/></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WVALID</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xm1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#1m0" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WREADY</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0m1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#1m0" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/></g></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WDATA</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vvv-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vmv-2-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vmv-2-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vmv-2-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vmv-2-3" transform="translate(280)"/><use xlink:href="#vvv-3" transform="translate(300)"/><use xlink:href="#vmv-3-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vmv-3-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vmv-3-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmv-3-4" transform="translate(440)"/><use xlink:href="#vvv-4" transform="translate(460)"/><use xlink:href="#vmv-4-4" transform="translate(480)"/><use xlink:href="#vvv-4" transform="translate(500)"/><use xlink:href="#vmv-4-4" transform="translate(520)"/><use xlink:href="#vvv-4" transform="translate(540)"/><use xlink:href="#vmv-4-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmv-4-5" transform="translate(600)"/><use xlink:href="#vvv-5" transform="translate(620)"/><use xlink:href="#vmv-5-5" transform="translate(640)"/><use xlink:href="#vvv-5" transform="translate(660)"/><use xlink:href="#vmv-5-5" transform="translate(680)"/><use xlink:href="#vvv-5" transform="translate(700)"/><use xlink:href="#vmv-5-5" transform="translate(720)"/><use xlink:href="#vvv-5" transform="translate(740)"/><use xlink:href="#vm0-5" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><text x="126" y="15" text-anchor="middle" xml:space="preserve"><tspan>D0</tspan></text><text x="186" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>D1</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>D2</tspan></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="546" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="626" y="15" text-anchor="middle" xml:space="preserve"><tspan>D3</tspan></text><text x="666" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="706" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text><text x="746" y="15" text-anchor="middle" xml:space="preserve"><tspan/></text></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WLAST</tspan></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xm0" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0mv-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vm0-2" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#0mv-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vm0-3" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#0mv-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vm0-4" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#0mv-5" transform="translate(720)"/><use xlink:href="#vvv-5" transform="translate(740)"/><use xlink:href="#vm0-5" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/></g></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"/></g><g id="wavelane_13_0" transform="translate(0,395)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_BVALID</tspan></text><g id="wavelane_draw_13_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#0mv-2" transform="translate(360)"/><use xlink:href="#vvv-2" transform="translate(380)"/><use xlink:href="#vm0-2" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#0mv-3" transform="translate(520)"/><use xlink:href="#vvv-3" transform="translate(540)"/><use xlink:href="#vm0-3" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#0mv-4" transform="translate(680)"/><use xlink:href="#vvv-4" transform="translate(700)"/><use xlink:href="#vm0-4" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#0mv-5" transform="translate(840)"/><use xlink:href="#vvv-5" transform="translate(860)"/><use xlink:href="#vm0-5" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>B0</tspan></text><text x="546" y="15" text-anchor="middle" xml:space="preserve"><tspan>B1</tspan></text><text x="706" y="15" text-anchor="middle" xml:space="preserve"><tspan>B2</tspan></text><text x="866" y="15" text-anchor="middle" xml:space="preserve"><tspan>B3</tspan></text></g></g><g id="wavelane_14_0" transform="translate(0,425)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_BREADY</tspan></text><g id="wavelane_draw_14_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xm1" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#1mx" transform="translate(400)"/><use xlink:href="#xxx" transform="translate(420)"/><use xlink:href="#xxx" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xm1" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#1mx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xm1" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#1mx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><use xlink:href="#xxx" transform="translate(760)"/><use xlink:href="#xxx" transform="translate(780)"/><use xlink:href="#xxx" transform="translate(800)"/><use xlink:href="#xxx" transform="translate(820)"/><use xlink:href="#xm1" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#1mx" transform="translate(880)"/><use xlink:href="#xxx" transform="translate(900)"/><use xlink:href="#xxx" transform="translate(920)"/><use xlink:href="#xxx" transform="translate(940)"/></g></g><g id="wavelane_15_0" transform="translate(0,455)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_15_0" transform="translate(0, 0)"/></g><g id="wavelane_16_0" transform="translate(0,485)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_AWVALID</tspan></text><g id="wavelane_draw_16_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0mv-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vmv-2-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vmv-2-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vmv-2-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vmv-2-3" transform="translate(280)"/><use xlink:href="#vvv-3" transform="translate(300)"/><use xlink:href="#vmv-3-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vmv-3-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vmv-3-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmv-3-4" transform="translate(440)"/><use xlink:href="#vvv-4" transform="translate(460)"/><use xlink:href="#vmv-4-4" transform="translate(480)"/><use xlink:href="#vvv-4" transform="translate(500)"/><use xlink:href="#vmv-4-4" transform="translate(520)"/><use xlink:href="#vvv-4" transform="translate(540)"/><use xlink:href="#vmv-4-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmv-4-5" transform="translate(600)"/><use xlink:href="#vvv-5" transform="translate(620)"/><use xlink:href="#vmv-5-5" transform="translate(640)"/><use xlink:href="#vvv-5" transform="translate(660)"/><use xlink:href="#vmv-5-5" transform="translate(680)"/><use xlink:href="#vvv-5" transform="translate(700)"/><use xlink:href="#vmv-5-5" transform="translate(720)"/><use xlink:href="#vvv-5" transform="translate(740)"/><use xlink:href="#vm0-5" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/></g></g><g id="wavelane_17_0" transform="translate(0,515)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>(M_AXI_BVALID)</tspan></text><g id="wavelane_draw_17_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xmv-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vmv-2-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vmv-2-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vmv-2-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vmv-2-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vmv-3-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vmv-3-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmv-3-3" transform="translate(440)"/><use xlink:href="#vvv-3" transform="translate(460)"/><use xlink:href="#vmv-3-4" transform="translate(480)"/><use xlink:href="#vvv-4" transform="translate(500)"/><use xlink:href="#vmv-4-4" transform="translate(520)"/><use xlink:href="#vvv-4" transform="translate(540)"/><use xlink:href="#vmv-4-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmv-4-4" transform="translate(600)"/><use xlink:href="#vvv-4" transform="translate(620)"/><use xlink:href="#vmv-4-5" transform="translate(640)"/><use xlink:href="#vvv-5" transform="translate(660)"/><use xlink:href="#vmv-5-5" transform="translate(680)"/><use xlink:href="#vvv-5" transform="translate(700)"/><use xlink:href="#vmv-5-5" transform="translate(720)"/><use xlink:href="#vvv-5" transform="translate(740)"/><use xlink:href="#vmv-5-5" transform="translate(760)"/><use xlink:href="#vvv-5" transform="translate(780)"/><use xlink:href="#vm0-5" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/></g></g><g id="wavelane_18_0" transform="translate(0,545)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_18_0" transform="translate(0, 0)"/></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/><g id="wavegap_13_0" transform="translate(0,395)"/><g id="wavegap_14_0" transform="translate(0,425)"/><g id="wavegap_15_0" transform="translate(0,455)"/><g id="wavegap_16_0" transform="translate(0,485)"/><g id="wavegap_17_0" transform="translate(0,515)"/><g id="wavegap_18_0" transform="translate(0,545)"/></g></g><g id="groups_0">g</g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axif-8pt-readburst.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axif-8pt-readburst.png
new file mode 100644
index 0000000..2da3b9b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axif-8pt-readburst.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axif-8pt-writeburst.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axif-8pt-writeburst.png
new file mode 100644
index 0000000..13246be
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axif-8pt-writeburst.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-bvalid-fail-trace.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-bvalid-fail-trace.png
new file mode 100644
index 0000000..fade59a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-bvalid-fail-trace.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-bvalid-fail.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-bvalid-fail.json
new file mode 100644
index 0000000..5fdb703
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-bvalid-fail.json
@@ -0,0 +1,16 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'p.........'},
+  {name: 'S_AXI_ARESETN', wave: '01........'},
+  {},
+  {name: 'S_AXI_AWVALID', wave: '0.1.01.0..'},
+  {name: 'S_AXI_AWREADY', wave: '0..10.10..'},
+  {name: 'S_AXI_AWLEN',   wave: 'x.2.x3.x..', data: ['0','0']},
+  {},
+  {name: 'S_AXI_WVALID',  wave: '0.1..01.0.'},
+  {name: 'S_AXI_WREADY',  wave: '0...10.10.'},
+  {name: 'S_AXI_WDATA',   wave: 'x...2x.3x.'},
+  {name: 'S_AXI_WLAST',   wave: 'x...1x.1x.'},
+  {},
+  {name: 'S_AXI_BVALID',  wave: '0....1...0'},
+  {name: 'S_AXI_BREADY',  wave: '0.......10'},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-bvalid-fail.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-bvalid-fail.png
new file mode 100644
index 0000000..195d746
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-bvalid-fail.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-bvalid-fail.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-bvalid-fail.svg
new file mode 100644
index 0000000..68bb64c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-bvalid-fail.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="420" viewBox="0 0 580 420" width="580" overflow="hidden"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill: rgb(0, 65, 196);" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill: rgb(0, 65, 196);" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_1_0" d="m 40,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_2_0" d="m 80,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_3_0" d="m 120,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_4_0" d="m 160,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_5_0" d="m 200,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_6_0" d="m 240,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_7_0" d="m 280,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_8_0" d="m 320,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_9_0" d="m 360,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_10_0" d="m 400,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"/></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWVALID</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWREADY</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWLEN</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#xmv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#vmx-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#xmv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#vmx-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><text x="126" y="15" text-anchor="middle" xml:space="preserve"><tspan>0</tspan></text><text x="246" y="15" text-anchor="middle" xml:space="preserve"><tspan>0</tspan></text></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"/></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WVALID</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WREADY</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WDATA</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#xmv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#vvv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#vmx-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/></g></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WLAST</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#xm1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#1mx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"/></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_BVALID</tspan></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/></g></g><g id="wavelane_13_0" transform="translate(0,395)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_BREADY</tspan></text><g id="wavelane_draw_13_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/><g id="wavegap_13_0" transform="translate(0,395)"/></g></g><g id="groups_0"><g/></g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rd.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rd.json
new file mode 100644
index 0000000..18ee072
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rd.json
@@ -0,0 +1,14 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'p...............'},
+  {},
+  {name: 'S_AXI_ARVALID', wave: '01.0............'},
+  {name: 'S_AXI_ARREADY', wave: '0.10............'},
+  {name: 'S_AXI_ARLEN',   wave: 'x2.x............', data: ['5']},
+  {},
+  {name: 'S_AXI_RVALID',  wave: '0..101010101010.'},
+  {name: 'S_AXI_RREADY',  wave: '0..1..........0.'},
+  {name: 'S_AXI_RDATA',   wave: '0..2x3x4x5x2x3x.'},
+  {name: 'S_AXI_RLAST',   wave: 'x.0..........1x.'},
+  {},
+  {name: 'axi_arv_arr_flag',  wave: '0.1...........0.'},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rd.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rd.png
new file mode 100644
index 0000000..6fab11a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rd.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rd.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rd.svg
new file mode 100644
index 0000000..913e192
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rd.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="360" viewBox="0 0 820 360" width="820" overflow="hidden"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill: rgb(0, 65, 196);" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill: rgb(0, 65, 196);" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_1_0" d="m 40,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_2_0" d="m 80,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_3_0" d="m 120,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_4_0" d="m 160,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_5_0" d="m 200,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_6_0" d="m 240,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_7_0" d="m 280,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_8_0" d="m 320,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_9_0" d="m 360,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_10_0" d="m 400,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_11_0" d="m 440,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_12_0" d="m 480,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_13_0" d="m 520,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_14_0" d="m 560,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_15_0" d="m 600,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_16_0" d="m 640,0 0,360" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"/></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARVALID</tspan></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARREADY</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARLEN</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xmv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#vmx-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/><text x="86" y="15" text-anchor="middle" xml:space="preserve"><tspan>5</tspan></text></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"/></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RVALID</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RREADY</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RDATA</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#0mv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#vmx-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#xmv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#vvv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#vmx-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#xmv-4" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#vvv-4" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#vmx-4" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#xmv-5" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#vvv-5" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#vmx-5" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#xmv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#vmx-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#xmv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#vvv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#vmx-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RLAST</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#xm0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#1mx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"/></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>axi_arv_arr_flag</tspan></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/></g></g><g id="groups_0"><g/></g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdid.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdid.json
new file mode 100644
index 0000000..18dd3f4
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdid.json
@@ -0,0 +1,12 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'P....'},
+  {name: 'S_AXI_ARESETN', wave: '01...'},
+  {name: 'S_AXI_ARVALID', wave: '0.10.'},
+  {name: 'S_AXI_ARREADY', wave: '0.10.'},
+  {name: 'S_AXI_ARLEN',   wave: 'x.2x.', data: ['0']},
+  {name: 'S_AXI_ARID',    wave: 'x.23x', data: ['0','1']},
+  {},
+  {name: 'S_AXI_RVALID',  wave: '0..10'},
+  {name: 'S_AXI_RLAST',   wave: 'x..1x'},
+  {name: 'S_AXI_RID',     wave: 'x.23x', data: ['0','1']},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdid.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdid.png
new file mode 100644
index 0000000..3c03455
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdid.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdid.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdid.svg
new file mode 100644
index 0000000..48d9cbb
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdid.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="300" width="380" viewBox="0 0 380 300" overflow="hidden"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,300" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_1_0" d="m 40,0 0,300" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_2_0" d="m 80,0 0,300" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_3_0" d="m 120,0 0,300" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_4_0" d="m 160,0 0,300" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_5_0" d="m 200,0 0,300" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#Pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#Pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#Pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#Pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#Pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARVALID</tspan></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1m0" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/></g></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARREADY</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1m0" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARLEN</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vmx-2" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><text x="106" y="15" text-anchor="middle" xml:space="preserve"><tspan>0</tspan></text></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARID</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vmv-2-3" transform="translate(120)"/><use xlink:href="#vvv-3" transform="translate(140)"/><use xlink:href="#vmx-3" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><text x="106" y="15" text-anchor="middle" xml:space="preserve"><tspan>0</tspan></text><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>1</tspan></text></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"/></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RVALID</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0m1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#1m0" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RLAST</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xm1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#1mx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RID</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vmv-2-3" transform="translate(120)"/><use xlink:href="#vvv-3" transform="translate(140)"/><use xlink:href="#vmx-3" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><text x="106" y="15" text-anchor="middle" xml:space="preserve"><tspan>0</tspan></text><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>1</tspan></text></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/></g></g><g id="groups_0">g</g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdwr.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdwr.json
new file mode 100644
index 0000000..c0d2da3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdwr.json
@@ -0,0 +1,20 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'p...............'},
+  {name: 'S_AXI_ARESETN', wave: '01..............'},
+  {name: 'S_AXI_ARVALID', wave: '0.1.0...........'},
+  {name: 'S_AXI_ARREADY', wave: '0..10...........'},
+  {name: 'S_AXI_ARLEN',   wave: 'x..2x...........', data: ['2']},
+  {name: 'S_AXI_RVALID',  wave: '0...304050......'},
+  {name: 'S_AXI_RREADY',  wave: 'x...1....x......'},
+  {name: 'S_AXI_RLAST',   wave: '0.......10......'},
+  {},
+  {name: 'S_AXI_AWVALID', wave: '0.....1....0....'},
+  {name: 'S_AXI_AWREADY', wave: '0.........10....'},
+  {name: 'S_AXI_AWLEN',   wave: 'x.........2x....', data: ['2']},
+  {name: 'S_AXI_WVALID',  wave: '0.........1...0.'},
+  {name: 'S_AXI_WREADY',  wave: '0..........1..0.'},
+  {name: 'S_AXI_WDATA',   wave: '0..........3450.'},
+  {name: 'S_AXI_WLAST',   wave: '0............10.'},
+  {name: 'S_AXI_BVALID',  wave: '0.............10'},
+  {},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdwr.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdwr.png
new file mode 100644
index 0000000..1b77ea4
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdwr.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdwr.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdwr.svg
new file mode 100644
index 0000000..17fd438
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-rdwr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="540" viewBox="0 0 820 540" width="820" overflow="hidden"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill: rgb(0, 65, 196);" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill: rgb(0, 65, 196);" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_1_0" d="m 40,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_2_0" d="m 80,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_3_0" d="m 120,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_4_0" d="m 160,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_5_0" d="m 200,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_6_0" d="m 240,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_7_0" d="m 280,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_8_0" d="m 320,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_9_0" d="m 360,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_10_0" d="m 400,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_11_0" d="m 440,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_12_0" d="m 480,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_13_0" d="m 520,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_14_0" d="m 560,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_15_0" d="m 600,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_16_0" d="m 640,0 0,540" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARVALID</tspan></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARREADY</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARLEN</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#xmv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#vmx-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>2</tspan></text></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RVALID</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#0mv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#vvv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#vm0-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#0mv-4" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#vvv-4" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#vm0-4" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#0mv-5" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#vvv-5" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#vm0-5" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RREADY</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#xm1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#1mx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RLAST</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"/></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWVALID</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWREADY</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWLEN</tspan></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#xmv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#vmx-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>2</tspan></text></g></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WVALID</tspan></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_13_0" transform="translate(0,395)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WREADY</tspan></text><g id="wavelane_draw_13_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_14_0" transform="translate(0,425)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WDATA</tspan></text><g id="wavelane_draw_14_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#0mv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#vvv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#vmv-3-4" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#vvv-4" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#vmv-4-5" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#vvv-5" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#vm0-5" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_15_0" transform="translate(0,455)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WLAST</tspan></text><g id="wavelane_draw_15_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_16_0" transform="translate(0,485)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_BVALID</tspan></text><g id="wavelane_draw_16_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(440)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(460)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(480)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(500)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(520)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(540)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(560)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(580)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(600)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(620)"/></g></g><g id="wavelane_17_0" transform="translate(0,515)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_17_0" transform="translate(0, 0)"/></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/><g id="wavegap_13_0" transform="translate(0,395)"/><g id="wavegap_14_0" transform="translate(0,425)"/><g id="wavegap_15_0" transform="translate(0,455)"/><g id="wavegap_16_0" transform="translate(0,485)"/><g id="wavegap_17_0" transform="translate(0,515)"/></g></g><g id="groups_0"><g/></g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wlast.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wlast.json
new file mode 100644
index 0000000..a6bffec
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wlast.json
@@ -0,0 +1,13 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'p........'},
+  {name: 'S_AXI_ARESETN', wave: '01.......'},
+  {},
+  {name: 'S_AXI_AWVALID', wave: '0.1.0....'},
+  {name: 'S_AXI_AWREADY', wave: '0..10....'},
+  {name: 'S_AXI_AWLEN',   wave: 'x.2.x....', data: ['8']},
+  {},
+  {name: 'S_AXI_WVALID',  wave: '0..1.01..'},
+  {name: 'S_AXI_WREADY',  wave: '0...1.0..'},
+  {name: 'S_AXI_WDATA',   wave: '0...2x3..'},
+  {name: 'S_AXI_WLAST',   wave: 'x..0.10..'},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wlast.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wlast.png
new file mode 100644
index 0000000..bffe070
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wlast.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wlast.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wlast.svg
new file mode 100644
index 0000000..ae1463f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wlast.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="330" viewBox="0 0 540 330" width="540" overflow="hidden"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill: rgb(0, 65, 196);" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill: rgb(0, 65, 196);" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,330" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_1_0" d="m 40,0 0,330" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_2_0" d="m 80,0 0,330" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_3_0" d="m 120,0 0,330" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_4_0" d="m 160,0 0,330" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_5_0" d="m 200,0 0,330" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_6_0" d="m 240,0 0,330" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_7_0" d="m 280,0 0,330" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_8_0" d="m 320,0 0,330" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_9_0" d="m 360,0 0,330" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"/></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWVALID</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWREADY</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWLEN</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#xmv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#vmx-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><text x="126" y="15" text-anchor="middle" xml:space="preserve"><tspan>8</tspan></text></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"/></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WVALID</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WREADY</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WDATA</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#0mv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#vmx-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#xmv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#vvv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#vvv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#vvv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#vvv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#vvv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/></g></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WLAST</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#xm0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/></g></g><g id="groups_0"><g/></g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wr.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wr.json
new file mode 100644
index 0000000..d6b555b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wr.json
@@ -0,0 +1,16 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'p......p...'},
+  {},
+  {name: 'S_AXI_AWVALID', wave: '01.0.......'},
+  {name: 'S_AXI_AWREADY', wave: '0.10.......'},
+  {name: 'S_AXI_AWLEN',   wave: 'x2.x.......', data: ['5']},
+  {},
+  {name: 'S_AXI_WVALID',  wave: '0.1......0.'},
+  {name: 'S_AXI_WREADY',  wave: '0..1.....0.'},
+  {name: 'S_AXI_WDATA',   wave: '0.2.345230.'},
+  {name: 'S_AXI_WLAST',   wave: 'x.0.....1x.'},
+  {},
+  {name: 'S_AXI_BVALID',  wave: '0........10'},
+  {},
+  {name: 'axi_awv_awr_flag',  wave: '0..1.....0.'},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wr.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wr.png
new file mode 100644
index 0000000..d1850c6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wr.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wr.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wr.svg
new file mode 100644
index 0000000..4b7d94a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axifull-wr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="420" viewBox="0 0 620 420" width="620" overflow="hidden"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill: rgb(0, 65, 196);" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill: rgb(0, 65, 196);" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_1_0" d="m 40,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_2_0" d="m 80,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_3_0" d="m 120,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_4_0" d="m 160,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_5_0" d="m 200,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_6_0" d="m 240,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_7_0" d="m 280,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_8_0" d="m 320,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_9_0" d="m 360,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_10_0" d="m 400,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/><path id="gmark_11_0" d="m 440,0 0,420" style="stroke: rgb(136, 136, 136); stroke-width: 0.5; stroke-dasharray: 1, 3;"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#pclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#nclk" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"/></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWVALID</tspan></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/></g></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWREADY</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_AWLEN</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xmv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#vmx-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/><text x="86" y="15" text-anchor="middle" xml:space="preserve"><tspan>5</tspan></text></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"/></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WVALID</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WREADY</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WDATA</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#0mv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#vmv-2-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#vvv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#vmv-3-4" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#vvv-4" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#vmv-4-5" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#vvv-5" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#vmv-5-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#vvv-2" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#vmv-2-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#vvv-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#vm0-3" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_WLAST</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#xm0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#1mx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#xxx" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/></g></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"/></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_BVALID</tspan></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/></g></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"/></g><g id="wavelane_13_0" transform="translate(0,395)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>axi_awv_awr_flag</tspan></text><g id="wavelane_draw_13_0" transform="translate(0, 0)"><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(0)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(20)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(40)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(60)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(80)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(100)"/><use xlink:href="#0m1" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(120)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(140)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(160)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(180)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(200)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(220)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(240)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(260)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(280)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(300)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(320)"/><use xlink:href="#111" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(340)"/><use xlink:href="#1m0" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(360)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(380)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(400)"/><use xlink:href="#000" xmlns:xlink="http://www.w3.org/1999/xlink" transform="translate(420)"/></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/><g id="wavegap_13_0" transform="translate(0,395)"/></g></g><g id="groups_0"><g/></g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-double-valid.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-double-valid.json
new file mode 100644
index 0000000..637f2ea
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-double-valid.json
@@ -0,0 +1,14 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'P......'},
+  {name: 'S_AXI_ARESETN', wave: '01.....'},
+  {},
+  {name: 'S_AXI_AWVALID', wave: 'x010...',   data: ['S1','S2']},
+  {name: 'S_AXI_AWREADY', wave: 'x1.....'},
+  {name: 'S_AXI_WVALID',  wave: 'x01....'},
+  {name: 'S_AXI_WREADY',  wave: 'x0.....'},
+  {name: 'S_AXI_BVALID',  wave: '0......'},
+  {},
+  {name: 'S_AXI_ARVALID', wave: 'x010...'},
+  {name: 'S_AXI_ARREADY', wave: 'x1.....'},
+  {name: 'S_AXI_RVALID',  wave: '0......'}
+]}
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-double-valid.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-double-valid.png
new file mode 100644
index 0000000..d84ba4a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-double-valid.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-missed-handshake.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-missed-handshake.json
new file mode 100644
index 0000000..ec857c0
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-missed-handshake.json
@@ -0,0 +1,10 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'P......'},
+  {name: 'S_AXI_ARESETN', wave: '01.....'},
+  {},
+  {name: 'S_AXI_ARVALID', wave: '0.1x...'},
+  {name: 'S_AXI_ARREADY', wave: '1..0..1'},
+  {},
+  {name: 'S_AXI_RVALID',  wave: 'x0...10'},
+  {name: 'S_AXI_RREADY',  wave: '1....01'},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-missed-handshake.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-missed-handshake.png
new file mode 100644
index 0000000..97e90ad
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-missed-handshake.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-read-example.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-read-example.png
new file mode 100644
index 0000000..703b221
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-read-example.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-registered.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-registered.png
new file mode 100644
index 0000000..a6826e3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-registered.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-xilinx-read-broken.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-xilinx-read-broken.png
new file mode 100644
index 0000000..efa01fa
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil-xilinx-read-broken.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil2apb-reads.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil2apb-reads.png
new file mode 100644
index 0000000..9fc3143
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axil2apb-reads.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axildouble-rd.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axildouble-rd.png
new file mode 100644
index 0000000..aa08915
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axildouble-rd.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axildouble-wr.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axildouble-wr.png
new file mode 100644
index 0000000..88300b6
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axildouble-wr.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilsafety-diagram.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilsafety-diagram.png
new file mode 100644
index 0000000..9991071
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilsafety-diagram.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilsafety-readfault-burst.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilsafety-readfault-burst.png
new file mode 100644
index 0000000..f56c412
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilsafety-readfault-burst.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilsafety-readfault-burst.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilsafety-readfault-burst.svg
new file mode 100644
index 0000000..e521df8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilsafety-readfault-burst.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="660" width="780" viewBox="0 0 780 660" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{fill:#000;fill-opacity:1;stroke:none}.s7{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s10{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{color:#000;fill:#ccfdfe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s12{color:#000;fill:#cdfdc5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s13{color:#000;fill:#f0c1fb;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s14{color:#000;fill:#f5c2c0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s15{fill:#0041c4;fill-opacity:1;stroke:none}.s16{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s6"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s6"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s9"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s9"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s9"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s9"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s9"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s9"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-6"><path d="M2.875,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-6"><path d="M3,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-6"><path d="M20,20 0,20 0,0 20,0" class="s11"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-6"><path d="M0,20 0,0 3,0 9,20" class="s11"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-6"><path d="M0,0 0,20 3,20 9,0" class="s11"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-6"><path d="M0,0 0,20 3,20 6,10 3,0" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-6"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s11"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-6"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s11"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-6"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s11"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-7"><path d="M2.875,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-7"><path d="M3,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-7"><path d="M20,20 0,20 0,0 20,0" class="s12"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-7"><path d="M0,20 0,0 3,0 9,20" class="s12"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-7"><path d="M0,0 0,20 3,20 9,0" class="s12"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-7"><path d="M0,0 0,20 3,20 6,10 3,0" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-7"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s12"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-7"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s12"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-7"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s12"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-8"><path d="M2.875,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-8"><path d="M3,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-8"><path d="M20,20 0,20 0,0 20,0" class="s13"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-8"><path d="M0,20 0,0 3,0 9,20" class="s13"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-8"><path d="M0,0 0,20 3,20 9,0" class="s13"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-8"><path d="M0,0 0,20 3,20 6,10 3,0" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-8"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s13"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-8"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s13"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-8"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s13"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-9"><path d="M2.875,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-9"><path d="M3,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-9"><path d="M20,20 0,20 0,0 20,0" class="s14"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-9"><path d="M0,20 0,0 3,0 9,20" class="s14"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-9"><path d="M0,0 0,20 3,20 9,0" class="s14"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-9"><path d="M0,0 0,20 3,20 6,10 3,0" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-9"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s14"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-9"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s14"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-9"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s14"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s15"/><path d="M0,0 -15,0" class="s16"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><g style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"><line id="gmark_0_0" x1="0" y1="0" x2="0" y2="660"/><line id="gmark_1_0" x1="40" y1="0" x2="40" y2="660"/><line id="gmark_2_0" x1="80" y1="0" x2="80" y2="660"/><line id="gmark_3_0" x1="120" y1="0" x2="120" y2="660"/><line id="gmark_4_0" x1="160" y1="0" x2="160" y2="660"/><line id="gmark_5_0" x1="200" y1="0" x2="200" y2="660"/><line id="gmark_6_0" x1="240" y1="0" x2="240" y2="660"/><line id="gmark_7_0" x1="280" y1="0" x2="280" y2="660"/><line id="gmark_8_0" x1="320" y1="0" x2="320" y2="660"/><line id="gmark_9_0" x1="360" y1="0" x2="360" y2="660"/><line id="gmark_10_0" x1="400" y1="0" x2="400" y2="660"/><line id="gmark_11_0" x1="440" y1="0" x2="440" y2="660"/><line id="gmark_12_0" x1="480" y1="0" x2="480" y2="660"/><line id="gmark_13_0" x1="520" y1="0" x2="520" y2="660"/><line id="gmark_14_0" x1="560" y1="0" x2="560" y2="660"/><line id="gmark_15_0" x1="600" y1="0" x2="600" y2="660"/></g></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/><use xlink:href="#pclk" transform="translate(200)"/><use xlink:href="#nclk" transform="translate(220)"/><use xlink:href="#pclk" transform="translate(240)"/><use xlink:href="#nclk" transform="translate(260)"/><use xlink:href="#pclk" transform="translate(280)"/><use xlink:href="#nclk" transform="translate(300)"/><use xlink:href="#pclk" transform="translate(320)"/><use xlink:href="#nclk" transform="translate(340)"/><use xlink:href="#pclk" transform="translate(360)"/><use xlink:href="#nclk" transform="translate(380)"/><use xlink:href="#pclk" transform="translate(400)"/><use xlink:href="#nclk" transform="translate(420)"/><use xlink:href="#pclk" transform="translate(440)"/><use xlink:href="#nclk" transform="translate(460)"/><use xlink:href="#pclk" transform="translate(480)"/><use xlink:href="#nclk" transform="translate(500)"/><use xlink:href="#pclk" transform="translate(520)"/><use xlink:href="#nclk" transform="translate(540)"/><use xlink:href="#pclk" transform="translate(560)"/><use xlink:href="#nclk" transform="translate(580)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"/></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_ARESETN</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1m0" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#0m1" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>o_read_fault</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#1m0" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"/></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARVALID</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0mv-9" transform="translate(80)"/><use xlink:href="#vvv-9" transform="translate(100)"/><use xlink:href="#vm0-9" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#0mv-3" transform="translate(200)"/><use xlink:href="#vvv-3" transform="translate(220)"/><use xlink:href="#vmv-3-4" transform="translate(240)"/><use xlink:href="#vvv-4" transform="translate(260)"/><use xlink:href="#vmv-4-5" transform="translate(280)"/><use xlink:href="#vvv-5" transform="translate(300)"/><use xlink:href="#vmv-5-6" transform="translate(320)"/><use xlink:href="#vvv-6" transform="translate(340)"/><use xlink:href="#vmv-6-7" transform="translate(360)"/><use xlink:href="#vvv-7" transform="translate(380)"/><use xlink:href="#vmv-7-8" transform="translate(400)"/><use xlink:href="#vvv-8" transform="translate(420)"/><use xlink:href="#vm0-8" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARREADY</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#111" transform="translate(0)"/><use xlink:href="#111" transform="translate(20)"/><use xlink:href="#111" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARADDR</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xmv-9" transform="translate(80)"/><use xlink:href="#vvv-9" transform="translate(100)"/><use xlink:href="#vmx-9" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xmv-3" transform="translate(200)"/><use xlink:href="#vvv-3" transform="translate(220)"/><use xlink:href="#vmv-3-4" transform="translate(240)"/><use xlink:href="#vvv-4" transform="translate(260)"/><use xlink:href="#vmv-4-5" transform="translate(280)"/><use xlink:href="#vvv-5" transform="translate(300)"/><use xlink:href="#vmv-5-6" transform="translate(320)"/><use xlink:href="#vvv-6" transform="translate(340)"/><use xlink:href="#vmv-6-7" transform="translate(360)"/><use xlink:href="#vvv-7" transform="translate(380)"/><use xlink:href="#vmv-7-8" transform="translate(400)"/><use xlink:href="#vvv-8" transform="translate(420)"/><use xlink:href="#vmx-8" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><text x="106" y="15" text-anchor="middle" xml:space="preserve"><tspan>AER</tspan></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>A0</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>A1</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>A2</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>A3</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>A4</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>A5</tspan></text></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"/></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_ARVALID</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0mv-3" transform="translate(240)"/><use xlink:href="#vvv-3" transform="translate(260)"/><use xlink:href="#vmv-3-4" transform="translate(280)"/><use xlink:href="#vvv-4" transform="translate(300)"/><use xlink:href="#vmv-4-5" transform="translate(320)"/><use xlink:href="#vvv-5" transform="translate(340)"/><use xlink:href="#vmv-5-6" transform="translate(360)"/><use xlink:href="#vvv-6" transform="translate(380)"/><use xlink:href="#vmv-6-7" transform="translate(400)"/><use xlink:href="#vvv-7" transform="translate(420)"/><use xlink:href="#vmv-7-8" transform="translate(440)"/><use xlink:href="#vvv-8" transform="translate(460)"/><use xlink:href="#vm0-8" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_ARREADY</tspan></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"><use xlink:href="#111" transform="translate(0)"/><use xlink:href="#111" transform="translate(20)"/><use xlink:href="#111" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/></g></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_ARADDR</tspan></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xmv-3" transform="translate(240)"/><use xlink:href="#vvv-3" transform="translate(260)"/><use xlink:href="#vmv-3-4" transform="translate(280)"/><use xlink:href="#vvv-4" transform="translate(300)"/><use xlink:href="#vmv-4-5" transform="translate(320)"/><use xlink:href="#vvv-5" transform="translate(340)"/><use xlink:href="#vmv-5-6" transform="translate(360)"/><use xlink:href="#vvv-6" transform="translate(380)"/><use xlink:href="#vmv-6-7" transform="translate(400)"/><use xlink:href="#vvv-7" transform="translate(420)"/><use xlink:href="#vmv-7-8" transform="translate(440)"/><use xlink:href="#vvv-8" transform="translate(460)"/><use xlink:href="#vmx-8" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>A0</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>A1</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>A2</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>A3</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>A4</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>A5</tspan></text></g></g><g id="wavelane_13_0" transform="translate(0,395)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_13_0" transform="translate(0, 0)"/></g><g id="wavelane_14_0" transform="translate(0,425)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_RVALID</tspan></text><g id="wavelane_draw_14_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0mv-9" transform="translate(40)"/><use xlink:href="#vvv-9" transform="translate(60)"/><use xlink:href="#vm0-9" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0mv-9" transform="translate(120)"/><use xlink:href="#vvv-9" transform="translate(140)"/><use xlink:href="#vm0-9" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#0mv-3" transform="translate(280)"/><use xlink:href="#vvv-3" transform="translate(300)"/><use xlink:href="#vmv-3-4" transform="translate(320)"/><use xlink:href="#vvv-4" transform="translate(340)"/><use xlink:href="#vmv-4-5" transform="translate(360)"/><use xlink:href="#vvv-5" transform="translate(380)"/><use xlink:href="#vmv-5-6" transform="translate(400)"/><use xlink:href="#vvv-6" transform="translate(420)"/><use xlink:href="#vmv-6-7" transform="translate(440)"/><use xlink:href="#vvv-7" transform="translate(460)"/><use xlink:href="#vmv-7-8" transform="translate(480)"/><use xlink:href="#vvv-8" transform="translate(500)"/><use xlink:href="#vm0-8" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/></g></g><g id="wavelane_15_0" transform="translate(0,455)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_RREADY</tspan></text><g id="wavelane_draw_15_0" transform="translate(0, 0)"><use xlink:href="#111" transform="translate(0)"/><use xlink:href="#111" transform="translate(20)"/><use xlink:href="#111" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/></g></g><g id="wavelane_16_0" transform="translate(0,485)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_RDATA</tspan></text><g id="wavelane_draw_16_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xmv-3" transform="translate(280)"/><use xlink:href="#vvv-3" transform="translate(300)"/><use xlink:href="#vmv-3-4" transform="translate(320)"/><use xlink:href="#vvv-4" transform="translate(340)"/><use xlink:href="#vmv-4-5" transform="translate(360)"/><use xlink:href="#vvv-5" transform="translate(380)"/><use xlink:href="#vmv-5-6" transform="translate(400)"/><use xlink:href="#vvv-6" transform="translate(420)"/><use xlink:href="#vmv-6-7" transform="translate(440)"/><use xlink:href="#vvv-7" transform="translate(460)"/><use xlink:href="#vmv-7-8" transform="translate(480)"/><use xlink:href="#vvv-8" transform="translate(500)"/><use xlink:href="#vmx-8" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>D0</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>D1</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>D2</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>D3</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>D4</tspan></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan>D5</tspan></text></g></g><g id="wavelane_17_0" transform="translate(0,515)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_17_0" transform="translate(0, 0)"/></g><g id="wavelane_18_0" transform="translate(0,545)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RVALID</tspan></text><g id="wavelane_draw_18_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0mv-9" transform="translate(120)"/><use xlink:href="#vvv-9" transform="translate(140)"/><use xlink:href="#vm0-9" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#0mv-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vmv-3-4" transform="translate(360)"/><use xlink:href="#vvv-4" transform="translate(380)"/><use xlink:href="#vmv-4-5" transform="translate(400)"/><use xlink:href="#vvv-5" transform="translate(420)"/><use xlink:href="#vmv-5-6" transform="translate(440)"/><use xlink:href="#vvv-6" transform="translate(460)"/><use xlink:href="#vmv-6-7" transform="translate(480)"/><use xlink:href="#vvv-7" transform="translate(500)"/><use xlink:href="#vmv-7-8" transform="translate(520)"/><use xlink:href="#vvv-8" transform="translate(540)"/><use xlink:href="#vm0-8" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/></g></g><g id="wavelane_19_0" transform="translate(0,575)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RREADY</tspan></text><g id="wavelane_draw_19_0" transform="translate(0, 0)"><use xlink:href="#111" transform="translate(0)"/><use xlink:href="#111" transform="translate(20)"/><use xlink:href="#111" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/></g></g><g id="wavelane_20_0" transform="translate(0,605)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RDATA</tspan></text><g id="wavelane_draw_20_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xmv-3" transform="translate(320)"/><use xlink:href="#vvv-3" transform="translate(340)"/><use xlink:href="#vmv-3-4" transform="translate(360)"/><use xlink:href="#vvv-4" transform="translate(380)"/><use xlink:href="#vmv-4-5" transform="translate(400)"/><use xlink:href="#vvv-5" transform="translate(420)"/><use xlink:href="#vmv-5-6" transform="translate(440)"/><use xlink:href="#vvv-6" transform="translate(460)"/><use xlink:href="#vmv-6-7" transform="translate(480)"/><use xlink:href="#vvv-7" transform="translate(500)"/><use xlink:href="#vmv-7-8" transform="translate(520)"/><use xlink:href="#vvv-8" transform="translate(540)"/><use xlink:href="#vmx-8" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>D0</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>D1</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>D2</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>D3</tspan></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan>D4</tspan></text><text x="546" y="15" text-anchor="middle" xml:space="preserve"><tspan>D5</tspan></text></g></g><g id="wavelane_21_0" transform="translate(0,635)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RRESP</tspan></text><g id="wavelane_draw_21_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xmv-9" transform="translate(120)"/><use xlink:href="#vvv-9" transform="translate(140)"/><use xlink:href="#vmx-9" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xmv-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vvv-2" transform="translate(360)"/><use xlink:href="#vvv-2" transform="translate(380)"/><use xlink:href="#vvv-2" transform="translate(400)"/><use xlink:href="#vvv-2" transform="translate(420)"/><use xlink:href="#vvv-2" transform="translate(440)"/><use xlink:href="#vvv-2" transform="translate(460)"/><use xlink:href="#vvv-2" transform="translate(480)"/><use xlink:href="#vvv-2" transform="translate(500)"/><use xlink:href="#vvv-2" transform="translate(520)"/><use xlink:href="#vvv-2" transform="translate(540)"/><use xlink:href="#vmx-2" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>ERR</tspan></text><text x="446" y="15" text-anchor="middle" xml:space="preserve"><tspan>OKAY</tspan></text></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/><g id="wavegap_13_0" transform="translate(0,395)"/><g id="wavegap_14_0" transform="translate(0,425)"/><g id="wavegap_15_0" transform="translate(0,455)"/><g id="wavegap_16_0" transform="translate(0,485)"/><g id="wavegap_17_0" transform="translate(0,515)"/><g id="wavegap_18_0" transform="translate(0,545)"/><g id="wavegap_19_0" transform="translate(0,575)"/><g id="wavegap_20_0" transform="translate(0,605)"/><g id="wavegap_21_0" transform="translate(0,635)"/></g></g><g id="groups_0"><g/></g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilsingle-rd.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilsingle-rd.png
new file mode 100644
index 0000000..bc5b8e3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilsingle-rd.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilsingle-wr.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilsingle-wr.png
new file mode 100644
index 0000000..edaf2ed
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilsingle-wr.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilxbar-vivado-floorplanning.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilxbar-vivado-floorplanning.png
new file mode 100644
index 0000000..e44b301
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axilxbar-vivado-floorplanning.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximrd2wbsp.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximrd2wbsp.json
new file mode 100644
index 0000000..64e4dca
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximrd2wbsp.json
@@ -0,0 +1,22 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'P..........'},
+  {name: 'S_AXI_ARESETN', wave: '01.........'},
+  {},
+  {name: 'S_AXI_ARVALID', wave: '0.1....0...', data:[]},
+  {name: 'S_AXI_ARREADY', wave: '01.0101....', data:[]},
+  {name: 'S_AXI_ARID',    wave: 'x.3.4.5x...', data:['I0','I1','I2']},
+  {name: 'S_AXI_ARADDR',  wave: 'x.3.4.5x...', data:['A0','A1','A2']},
+  {name: 'S_AXI_ARLEN',   wave: 'x.3.4.5x...', data:['1','1','1']},
+  {},
+  {name: 'o_cyc',         wave: 'x0.1.....0.', data:['A0']},
+  {name: 'o_stb',         wave: 'x0.1.....0.', data:['A0']},
+  {name: 'o_addr',        wave: 'x0.3344550.', data:['A0','','A1','','A2']},
+  {name: 'i_ack',         wave: 'x0.1.....0.'},
+  {name: 'i_data',        wave: 'x..3344550.', data:['D0','D1','D2','D3','D4','D5']},
+  {},
+  {name: 'S_AXI_RVALID',  wave: '0...1.....0'},
+  {name: 'S_AXI_RREADY',  wave: 'x1.........'},
+  {name: 'S_AXI_RID',     wave: 'x...3.4.5.x', data:['I0','I1','I2']},
+  {name: 'S_AXI_RDATA',   wave: 'x...334455x', data:['D0','D1','D2','D3','D4','D5']},
+  {name: 'S_AXI_RLAST',   wave: 'x...010101x'},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximrd2wbsp.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximrd2wbsp.png
new file mode 100644
index 0000000..8a6b399
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximrd2wbsp.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximwr2wbsp-burst.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximwr2wbsp-burst.json
new file mode 100644
index 0000000..b9cdc74
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximwr2wbsp-burst.json
@@ -0,0 +1,24 @@
+{signal: [
+  {name: 'S_AXI_ACLK',   wave: 'p............'},
+  {name: 'S_AXI_ARESETN',wave: '01...........'},
+  {},
+  {name: 'S_AXI_AWVALID',wave: '0.1....0.....'},
+  {name: 'S_AXI_AWREADY',wave: '01.010101....'},
+  {name: 'S_AXI_AWID',   wave: 'x.2....x.....', data: ['Constant ID']},
+  {name: 'S_AXI_AWADDR', wave: 'x.34.5.x.....', data: ['A0','A1','A2']},
+  {name: 'S_AXI_AWLEN',  wave: 'x.34.5.x.....', data: ['1','1','1']},
+  {},
+  {name: 'S_AXI_WVALID', wave: '0.1.....0....'},
+  {name: 'S_AXI_WREADY', wave: '01...........'},
+  {name: 'S_AXI_WDATA',  wave: 'x.334455x....', data: ['D0','D1','D2','D3','D4','D5']},
+  {name: 'S_AXI_WLAST',  wave: 'x.010101x....', data: ['0']},
+  {},
+  {name: 'o_wb_stb',  wave: '0..1.....0...'},
+  {name: 'o_wb_addr', wave: 'x..334455x...', data: ['A0','','A1','','A2']},
+  {name: 'o_wb_data', wave: 'x..334455x...', data: ['D0','D1','D2','D3','D4','D5']},
+  {name: 'i_wb_ack',  wave: '0..1.....0...'},
+  {},
+  {name: 'S_AXI_BVALID', wave: '0......304050'},
+  {name: 'S_AXI_BREADY', wave: 'x......1x1x1x'},
+  {name: 'S_AXI_BID',    wave: 'x......2....x', data: ['Same constant ID']},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximwr2wbsp-burst.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximwr2wbsp-burst.png
new file mode 100644
index 0000000..def8c97
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximwr2wbsp-burst.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximwr2wbsp-single.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximwr2wbsp-single.json
new file mode 100644
index 0000000..2675091
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximwr2wbsp-single.json
@@ -0,0 +1,25 @@
+{signal: [
+  {name: 'S_AXI_ACLK',   wave: 'p........'},
+  {name: 'S_AXI_ARESETN',wave: '01.......'},
+  {},
+  {name: 'S_AXI_AWVALID',wave: '0.1....0.'},
+  {name: 'S_AXI_AWREADY',wave: '01...01..'},
+  {name: 'S_AXI_AWID',   wave: 'x.2..6.x.', data: ['2','3']},
+  {name: 'S_AXI_AWADDR', wave: 'x.3456.x.', data: ['A0','A1','A2','A3']},
+  {name: 'S_AXI_AWLEN',  wave: 'x.3456.x.', data: ['0','0','0','0']},
+  {},
+  {name: 'S_AXI_WVALID', wave: '0.1..010.'},
+  {name: 'S_AXI_WREADY', wave: '01.......'},
+  {name: 'S_AXI_WDATA',  wave: 'x.345x6x.', data: ['D0','D1','D2','D3','D4','D5']},
+  {name: 'S_AXI_WLAST',  wave: 'x.1..x1x.', data: ['0']},
+  {},
+  {name: 'o_wb_stb',  wave: '0..1..01.'},
+  {name: 'o_wb_addr', wave: 'x..345.6.', data: ['A0','A1','A2','A3']},
+  {name: 'o_wb_data', wave: 'x..345x6x', data: ['D0','D1','D2','D3','D4','D5']},
+  {name: 'i_wb_stall',wave: '0......1.'},
+  {name: 'i_wb_ack',  wave: '0..1..0.1'},
+  {},
+  {name: 'S_AXI_BVALID', wave: '0.....345'},
+  {name: 'S_AXI_BREADY', wave: 'x.....1..'},
+  {name: 'S_AXI_BID',    wave: 'x.....2..', data: ['2']},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximwr2wbsp-single.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximwr2wbsp-single.png
new file mode 100644
index 0000000..5a6a416
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/aximwr2wbsp-single.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axisafety-fault.dia b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axisafety-fault.dia
new file mode 100644
index 0000000..adc32ef
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axisafety-fault.dia
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axisafety-reset.dia b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axisafety-reset.dia
new file mode 100644
index 0000000..5ded625
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axisafety-reset.dia
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivdma.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivdma.json
new file mode 100644
index 0000000..1f6eafe
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivdma.json
@@ -0,0 +1,19 @@
+{signal: [
+  {name: 'ACLK',       wave: 'P..........................................'},
+  {name: 'ARESETN',    wave: '01.........................................'},
+  {},
+  {name: 'cfg_active', wave: '0....1.....................................'},
+  {},
+  {name: 'M_AXI_ARVALID', wave: '0........10.10.10.10.10.10.10.10.10.10.10.1'},
+  {name: 'M_AXI_ARADDR',  wave: '0........3..4..5..6..7..8..9..3..4..5..6..7'},
+  {name: 'M_AXI_ARLEN',   wave: 'x........2.................................', data: ['5']},
+  {},
+  {name: 'M_AXI_RVALID', wave: '0.........1........................01....01'},
+  {name: 'M_AXI_RDATA',  wave: 'x.........3333334444445555556666667x77777x8'},
+  {name: 'M_AXI_RLAST',  wave: 'x.........0....30....40....50....60x0...7x0'},
+  {},
+  {name: 'M_AXIS_TVALID', wave: '0..........1........................01....0'},
+  {name: 'M_AXIS_TDATA',  wave: 'x..........3333334444445555556666667x77777x'},
+  {name: 'H-LAST',        wave: 'x..........0....10....10....10....10.....1x'},
+  {name: 'V-LAST',        wave: 'x..........0.............................1x'},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivdma.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivdma.png
new file mode 100644
index 0000000..eca5698
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivdma.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivdma.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivdma.svg
new file mode 100644
index 0000000..fc6f229
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivdma.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="510" width="1880" viewBox="0 0 1880 510" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{fill:#000;fill-opacity:1;stroke:none}.s7{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s10{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{color:#000;fill:#ccfdfe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s12{color:#000;fill:#cdfdc5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s13{color:#000;fill:#f0c1fb;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s14{color:#000;fill:#f5c2c0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s15{fill:#0041c4;fill-opacity:1;stroke:none}.s16{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s6"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s6"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s9"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s9"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s9"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s9"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s9"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s9"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-6"><path d="M2.875,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-6"><path d="M3,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-6"><path d="M20,20 0,20 0,0 20,0" class="s11"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-6"><path d="M0,20 0,0 3,0 9,20" class="s11"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-6"><path d="M0,0 0,20 3,20 9,0" class="s11"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-6"><path d="M0,0 0,20 3,20 6,10 3,0" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-6"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s11"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-6"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s11"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-6"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s11"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-7"><path d="M2.875,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-7"><path d="M3,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-7"><path d="M20,20 0,20 0,0 20,0" class="s12"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-7"><path d="M0,20 0,0 3,0 9,20" class="s12"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-7"><path d="M0,0 0,20 3,20 9,0" class="s12"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-7"><path d="M0,0 0,20 3,20 6,10 3,0" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-7"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s12"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-7"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s12"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-7"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s12"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-8"><path d="M2.875,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-8"><path d="M3,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-8"><path d="M20,20 0,20 0,0 20,0" class="s13"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-8"><path d="M0,20 0,0 3,0 9,20" class="s13"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-8"><path d="M0,0 0,20 3,20 9,0" class="s13"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-8"><path d="M0,0 0,20 3,20 6,10 3,0" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-8"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s13"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-8"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s13"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-8"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s13"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-9"><path d="M2.875,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-9"><path d="M3,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-9"><path d="M20,20 0,20 0,0 20,0" class="s14"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-9"><path d="M0,20 0,0 3,0 9,20" class="s14"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-9"><path d="M0,0 0,20 3,20 9,0" class="s14"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-9"><path d="M0,0 0,20 3,20 6,10 3,0" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-9"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s14"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-9"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s14"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-9"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s14"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s15"/><path d="M0,0 -15,0" class="s16"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(140.5, 0.5)"><g id="gmarks_0"><g style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"><line id="gmark_0_0" x1="0" y1="0" x2="0" y2="510"/><line id="gmark_1_0" x1="40" y1="0" x2="40" y2="510"/><line id="gmark_2_0" x1="80" y1="0" x2="80" y2="510"/><line id="gmark_3_0" x1="120" y1="0" x2="120" y2="510"/><line id="gmark_4_0" x1="160" y1="0" x2="160" y2="510"/><line id="gmark_5_0" x1="200" y1="0" x2="200" y2="510"/><line id="gmark_6_0" x1="240" y1="0" x2="240" y2="510"/><line id="gmark_7_0" x1="280" y1="0" x2="280" y2="510"/><line id="gmark_8_0" x1="320" y1="0" x2="320" y2="510"/><line id="gmark_9_0" x1="360" y1="0" x2="360" y2="510"/><line id="gmark_10_0" x1="400" y1="0" x2="400" y2="510"/><line id="gmark_11_0" x1="440" y1="0" x2="440" y2="510"/><line id="gmark_12_0" x1="480" y1="0" x2="480" y2="510"/><line id="gmark_13_0" x1="520" y1="0" x2="520" y2="510"/><line id="gmark_14_0" x1="560" y1="0" x2="560" y2="510"/><line id="gmark_15_0" x1="600" y1="0" x2="600" y2="510"/><line id="gmark_16_0" x1="640" y1="0" x2="640" y2="510"/><line id="gmark_17_0" x1="680" y1="0" x2="680" y2="510"/><line id="gmark_18_0" x1="720" y1="0" x2="720" y2="510"/><line id="gmark_19_0" x1="760" y1="0" x2="760" y2="510"/><line id="gmark_20_0" x1="800" y1="0" x2="800" y2="510"/><line id="gmark_21_0" x1="840" y1="0" x2="840" y2="510"/><line id="gmark_22_0" x1="880" y1="0" x2="880" y2="510"/><line id="gmark_23_0" x1="920" y1="0" x2="920" y2="510"/><line id="gmark_24_0" x1="960" y1="0" x2="960" y2="510"/><line id="gmark_25_0" x1="1000" y1="0" x2="1000" y2="510"/><line id="gmark_26_0" x1="1040" y1="0" x2="1040" y2="510"/><line id="gmark_27_0" x1="1080" y1="0" x2="1080" y2="510"/><line id="gmark_28_0" x1="1120" y1="0" x2="1120" y2="510"/><line id="gmark_29_0" x1="1160" y1="0" x2="1160" y2="510"/><line id="gmark_30_0" x1="1200" y1="0" x2="1200" y2="510"/><line id="gmark_31_0" x1="1240" y1="0" x2="1240" y2="510"/><line id="gmark_32_0" x1="1280" y1="0" x2="1280" y2="510"/><line id="gmark_33_0" x1="1320" y1="0" x2="1320" y2="510"/><line id="gmark_34_0" x1="1360" y1="0" x2="1360" y2="510"/><line id="gmark_35_0" x1="1400" y1="0" x2="1400" y2="510"/><line id="gmark_36_0" x1="1440" y1="0" x2="1440" y2="510"/><line id="gmark_37_0" x1="1480" y1="0" x2="1480" y2="510"/><line id="gmark_38_0" x1="1520" y1="0" x2="1520" y2="510"/><line id="gmark_39_0" x1="1560" y1="0" x2="1560" y2="510"/><line id="gmark_40_0" x1="1600" y1="0" x2="1600" y2="510"/><line id="gmark_41_0" x1="1640" y1="0" x2="1640" y2="510"/><line id="gmark_42_0" x1="1680" y1="0" x2="1680" y2="510"/><line id="gmark_43_0" x1="1720" y1="0" x2="1720" y2="510"/></g></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#Pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#Pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#Pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#Pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#Pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/><use xlink:href="#Pclk" transform="translate(200)"/><use xlink:href="#nclk" transform="translate(220)"/><use xlink:href="#Pclk" transform="translate(240)"/><use xlink:href="#nclk" transform="translate(260)"/><use xlink:href="#Pclk" transform="translate(280)"/><use xlink:href="#nclk" transform="translate(300)"/><use xlink:href="#Pclk" transform="translate(320)"/><use xlink:href="#nclk" transform="translate(340)"/><use xlink:href="#Pclk" transform="translate(360)"/><use xlink:href="#nclk" transform="translate(380)"/><use xlink:href="#Pclk" transform="translate(400)"/><use xlink:href="#nclk" transform="translate(420)"/><use xlink:href="#Pclk" transform="translate(440)"/><use xlink:href="#nclk" transform="translate(460)"/><use xlink:href="#Pclk" transform="translate(480)"/><use xlink:href="#nclk" transform="translate(500)"/><use xlink:href="#Pclk" transform="translate(520)"/><use xlink:href="#nclk" transform="translate(540)"/><use xlink:href="#Pclk" transform="translate(560)"/><use xlink:href="#nclk" transform="translate(580)"/><use xlink:href="#Pclk" transform="translate(600)"/><use xlink:href="#nclk" transform="translate(620)"/><use xlink:href="#Pclk" transform="translate(640)"/><use xlink:href="#nclk" transform="translate(660)"/><use xlink:href="#Pclk" transform="translate(680)"/><use xlink:href="#nclk" transform="translate(700)"/><use xlink:href="#Pclk" transform="translate(720)"/><use xlink:href="#nclk" transform="translate(740)"/><use xlink:href="#Pclk" transform="translate(760)"/><use xlink:href="#nclk" transform="translate(780)"/><use xlink:href="#Pclk" transform="translate(800)"/><use xlink:href="#nclk" transform="translate(820)"/><use xlink:href="#Pclk" transform="translate(840)"/><use xlink:href="#nclk" transform="translate(860)"/><use xlink:href="#Pclk" transform="translate(880)"/><use xlink:href="#nclk" transform="translate(900)"/><use xlink:href="#Pclk" transform="translate(920)"/><use xlink:href="#nclk" transform="translate(940)"/><use xlink:href="#Pclk" transform="translate(960)"/><use xlink:href="#nclk" transform="translate(980)"/><use xlink:href="#Pclk" transform="translate(1000)"/><use xlink:href="#nclk" transform="translate(1020)"/><use xlink:href="#Pclk" transform="translate(1040)"/><use xlink:href="#nclk" transform="translate(1060)"/><use xlink:href="#Pclk" transform="translate(1080)"/><use xlink:href="#nclk" transform="translate(1100)"/><use xlink:href="#Pclk" transform="translate(1120)"/><use xlink:href="#nclk" transform="translate(1140)"/><use xlink:href="#Pclk" transform="translate(1160)"/><use xlink:href="#nclk" transform="translate(1180)"/><use xlink:href="#Pclk" transform="translate(1200)"/><use xlink:href="#nclk" transform="translate(1220)"/><use xlink:href="#Pclk" transform="translate(1240)"/><use xlink:href="#nclk" transform="translate(1260)"/><use xlink:href="#Pclk" transform="translate(1280)"/><use xlink:href="#nclk" transform="translate(1300)"/><use xlink:href="#Pclk" transform="translate(1320)"/><use xlink:href="#nclk" transform="translate(1340)"/><use xlink:href="#Pclk" transform="translate(1360)"/><use xlink:href="#nclk" transform="translate(1380)"/><use xlink:href="#Pclk" transform="translate(1400)"/><use xlink:href="#nclk" transform="translate(1420)"/><use xlink:href="#Pclk" transform="translate(1440)"/><use xlink:href="#nclk" transform="translate(1460)"/><use xlink:href="#Pclk" transform="translate(1480)"/><use xlink:href="#nclk" transform="translate(1500)"/><use xlink:href="#Pclk" transform="translate(1520)"/><use xlink:href="#nclk" transform="translate(1540)"/><use xlink:href="#Pclk" transform="translate(1560)"/><use xlink:href="#nclk" transform="translate(1580)"/><use xlink:href="#Pclk" transform="translate(1600)"/><use xlink:href="#nclk" transform="translate(1620)"/><use xlink:href="#Pclk" transform="translate(1640)"/><use xlink:href="#nclk" transform="translate(1660)"/><use xlink:href="#Pclk" transform="translate(1680)"/><use xlink:href="#nclk" transform="translate(1700)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#111" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#111" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#111" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#111" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#111" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#111" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#111" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#111" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#111" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#111" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#111" transform="translate(1200)"/><use xlink:href="#111" transform="translate(1220)"/><use xlink:href="#111" transform="translate(1240)"/><use xlink:href="#111" transform="translate(1260)"/><use xlink:href="#111" transform="translate(1280)"/><use xlink:href="#111" transform="translate(1300)"/><use xlink:href="#111" transform="translate(1320)"/><use xlink:href="#111" transform="translate(1340)"/><use xlink:href="#111" transform="translate(1360)"/><use xlink:href="#111" transform="translate(1380)"/><use xlink:href="#111" transform="translate(1400)"/><use xlink:href="#111" transform="translate(1420)"/><use xlink:href="#111" transform="translate(1440)"/><use xlink:href="#111" transform="translate(1460)"/><use xlink:href="#111" transform="translate(1480)"/><use xlink:href="#111" transform="translate(1500)"/><use xlink:href="#111" transform="translate(1520)"/><use xlink:href="#111" transform="translate(1540)"/><use xlink:href="#111" transform="translate(1560)"/><use xlink:href="#111" transform="translate(1580)"/><use xlink:href="#111" transform="translate(1600)"/><use xlink:href="#111" transform="translate(1620)"/><use xlink:href="#111" transform="translate(1640)"/><use xlink:href="#111" transform="translate(1660)"/><use xlink:href="#111" transform="translate(1680)"/><use xlink:href="#111" transform="translate(1700)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"/></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>cfg_active</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#0m1" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#111" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#111" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#111" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#111" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#111" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#111" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#111" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#111" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#111" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#111" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#111" transform="translate(1200)"/><use xlink:href="#111" transform="translate(1220)"/><use xlink:href="#111" transform="translate(1240)"/><use xlink:href="#111" transform="translate(1260)"/><use xlink:href="#111" transform="translate(1280)"/><use xlink:href="#111" transform="translate(1300)"/><use xlink:href="#111" transform="translate(1320)"/><use xlink:href="#111" transform="translate(1340)"/><use xlink:href="#111" transform="translate(1360)"/><use xlink:href="#111" transform="translate(1380)"/><use xlink:href="#111" transform="translate(1400)"/><use xlink:href="#111" transform="translate(1420)"/><use xlink:href="#111" transform="translate(1440)"/><use xlink:href="#111" transform="translate(1460)"/><use xlink:href="#111" transform="translate(1480)"/><use xlink:href="#111" transform="translate(1500)"/><use xlink:href="#111" transform="translate(1520)"/><use xlink:href="#111" transform="translate(1540)"/><use xlink:href="#111" transform="translate(1560)"/><use xlink:href="#111" transform="translate(1580)"/><use xlink:href="#111" transform="translate(1600)"/><use xlink:href="#111" transform="translate(1620)"/><use xlink:href="#111" transform="translate(1640)"/><use xlink:href="#111" transform="translate(1660)"/><use xlink:href="#111" transform="translate(1680)"/><use xlink:href="#111" transform="translate(1700)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"/></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_ARVALID</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#0m1" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#1m0" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#0m1" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#1m0" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#0m1" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#1m0" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#0m1" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#1m0" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#0m1" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#1m0" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#0m1" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#1m0" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#0m1" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#1m0" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#000" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/><use xlink:href="#0m1" transform="translate(1200)"/><use xlink:href="#111" transform="translate(1220)"/><use xlink:href="#1m0" transform="translate(1240)"/><use xlink:href="#000" transform="translate(1260)"/><use xlink:href="#000" transform="translate(1280)"/><use xlink:href="#000" transform="translate(1300)"/><use xlink:href="#0m1" transform="translate(1320)"/><use xlink:href="#111" transform="translate(1340)"/><use xlink:href="#1m0" transform="translate(1360)"/><use xlink:href="#000" transform="translate(1380)"/><use xlink:href="#000" transform="translate(1400)"/><use xlink:href="#000" transform="translate(1420)"/><use xlink:href="#0m1" transform="translate(1440)"/><use xlink:href="#111" transform="translate(1460)"/><use xlink:href="#1m0" transform="translate(1480)"/><use xlink:href="#000" transform="translate(1500)"/><use xlink:href="#000" transform="translate(1520)"/><use xlink:href="#000" transform="translate(1540)"/><use xlink:href="#0m1" transform="translate(1560)"/><use xlink:href="#111" transform="translate(1580)"/><use xlink:href="#1m0" transform="translate(1600)"/><use xlink:href="#000" transform="translate(1620)"/><use xlink:href="#000" transform="translate(1640)"/><use xlink:href="#000" transform="translate(1660)"/><use xlink:href="#0m1" transform="translate(1680)"/><use xlink:href="#111" transform="translate(1700)"/></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_ARADDR</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#0mv-3" transform="translate(360)"/><use xlink:href="#vvv-3" transform="translate(380)"/><use xlink:href="#vvv-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vvv-3" transform="translate(440)"/><use xlink:href="#vvv-3" transform="translate(460)"/><use xlink:href="#vmv-3-4" transform="translate(480)"/><use xlink:href="#vvv-4" transform="translate(500)"/><use xlink:href="#vvv-4" transform="translate(520)"/><use xlink:href="#vvv-4" transform="translate(540)"/><use xlink:href="#vvv-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmv-4-5" transform="translate(600)"/><use xlink:href="#vvv-5" transform="translate(620)"/><use xlink:href="#vvv-5" transform="translate(640)"/><use xlink:href="#vvv-5" transform="translate(660)"/><use xlink:href="#vvv-5" transform="translate(680)"/><use xlink:href="#vvv-5" transform="translate(700)"/><use xlink:href="#vmv-5-6" transform="translate(720)"/><use xlink:href="#vvv-6" transform="translate(740)"/><use xlink:href="#vvv-6" transform="translate(760)"/><use xlink:href="#vvv-6" transform="translate(780)"/><use xlink:href="#vvv-6" transform="translate(800)"/><use xlink:href="#vvv-6" transform="translate(820)"/><use xlink:href="#vmv-6-7" transform="translate(840)"/><use xlink:href="#vvv-7" transform="translate(860)"/><use xlink:href="#vvv-7" transform="translate(880)"/><use xlink:href="#vvv-7" transform="translate(900)"/><use xlink:href="#vvv-7" transform="translate(920)"/><use xlink:href="#vvv-7" transform="translate(940)"/><use xlink:href="#vmv-7-8" transform="translate(960)"/><use xlink:href="#vvv-8" transform="translate(980)"/><use xlink:href="#vvv-8" transform="translate(1000)"/><use xlink:href="#vvv-8" transform="translate(1020)"/><use xlink:href="#vvv-8" transform="translate(1040)"/><use xlink:href="#vvv-8" transform="translate(1060)"/><use xlink:href="#vmv-8-9" transform="translate(1080)"/><use xlink:href="#vvv-9" transform="translate(1100)"/><use xlink:href="#vvv-9" transform="translate(1120)"/><use xlink:href="#vvv-9" transform="translate(1140)"/><use xlink:href="#vvv-9" transform="translate(1160)"/><use xlink:href="#vvv-9" transform="translate(1180)"/><use xlink:href="#vmv-9-3" transform="translate(1200)"/><use xlink:href="#vvv-3" transform="translate(1220)"/><use xlink:href="#vvv-3" transform="translate(1240)"/><use xlink:href="#vvv-3" transform="translate(1260)"/><use xlink:href="#vvv-3" transform="translate(1280)"/><use xlink:href="#vvv-3" transform="translate(1300)"/><use xlink:href="#vmv-3-4" transform="translate(1320)"/><use xlink:href="#vvv-4" transform="translate(1340)"/><use xlink:href="#vvv-4" transform="translate(1360)"/><use xlink:href="#vvv-4" transform="translate(1380)"/><use xlink:href="#vvv-4" transform="translate(1400)"/><use xlink:href="#vvv-4" transform="translate(1420)"/><use xlink:href="#vmv-4-5" transform="translate(1440)"/><use xlink:href="#vvv-5" transform="translate(1460)"/><use xlink:href="#vvv-5" transform="translate(1480)"/><use xlink:href="#vvv-5" transform="translate(1500)"/><use xlink:href="#vvv-5" transform="translate(1520)"/><use xlink:href="#vvv-5" transform="translate(1540)"/><use xlink:href="#vmv-5-6" transform="translate(1560)"/><use xlink:href="#vvv-6" transform="translate(1580)"/><use xlink:href="#vvv-6" transform="translate(1600)"/><use xlink:href="#vvv-6" transform="translate(1620)"/><use xlink:href="#vvv-6" transform="translate(1640)"/><use xlink:href="#vvv-6" transform="translate(1660)"/><use xlink:href="#vmv-6-7" transform="translate(1680)"/><use xlink:href="#vvv-7" transform="translate(1700)"/></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_ARLEN</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xmv-2" transform="translate(360)"/><use xlink:href="#vvv-2" transform="translate(380)"/><use xlink:href="#vvv-2" transform="translate(400)"/><use xlink:href="#vvv-2" transform="translate(420)"/><use xlink:href="#vvv-2" transform="translate(440)"/><use xlink:href="#vvv-2" transform="translate(460)"/><use xlink:href="#vvv-2" transform="translate(480)"/><use xlink:href="#vvv-2" transform="translate(500)"/><use xlink:href="#vvv-2" transform="translate(520)"/><use xlink:href="#vvv-2" transform="translate(540)"/><use xlink:href="#vvv-2" transform="translate(560)"/><use xlink:href="#vvv-2" transform="translate(580)"/><use xlink:href="#vvv-2" transform="translate(600)"/><use xlink:href="#vvv-2" transform="translate(620)"/><use xlink:href="#vvv-2" transform="translate(640)"/><use xlink:href="#vvv-2" transform="translate(660)"/><use xlink:href="#vvv-2" transform="translate(680)"/><use xlink:href="#vvv-2" transform="translate(700)"/><use xlink:href="#vvv-2" transform="translate(720)"/><use xlink:href="#vvv-2" transform="translate(740)"/><use xlink:href="#vvv-2" transform="translate(760)"/><use xlink:href="#vvv-2" transform="translate(780)"/><use xlink:href="#vvv-2" transform="translate(800)"/><use xlink:href="#vvv-2" transform="translate(820)"/><use xlink:href="#vvv-2" transform="translate(840)"/><use xlink:href="#vvv-2" transform="translate(860)"/><use xlink:href="#vvv-2" transform="translate(880)"/><use xlink:href="#vvv-2" transform="translate(900)"/><use xlink:href="#vvv-2" transform="translate(920)"/><use xlink:href="#vvv-2" transform="translate(940)"/><use xlink:href="#vvv-2" transform="translate(960)"/><use xlink:href="#vvv-2" transform="translate(980)"/><use xlink:href="#vvv-2" transform="translate(1000)"/><use xlink:href="#vvv-2" transform="translate(1020)"/><use xlink:href="#vvv-2" transform="translate(1040)"/><use xlink:href="#vvv-2" transform="translate(1060)"/><use xlink:href="#vvv-2" transform="translate(1080)"/><use xlink:href="#vvv-2" transform="translate(1100)"/><use xlink:href="#vvv-2" transform="translate(1120)"/><use xlink:href="#vvv-2" transform="translate(1140)"/><use xlink:href="#vvv-2" transform="translate(1160)"/><use xlink:href="#vvv-2" transform="translate(1180)"/><use xlink:href="#vvv-2" transform="translate(1200)"/><use xlink:href="#vvv-2" transform="translate(1220)"/><use xlink:href="#vvv-2" transform="translate(1240)"/><use xlink:href="#vvv-2" transform="translate(1260)"/><use xlink:href="#vvv-2" transform="translate(1280)"/><use xlink:href="#vvv-2" transform="translate(1300)"/><use xlink:href="#vvv-2" transform="translate(1320)"/><use xlink:href="#vvv-2" transform="translate(1340)"/><use xlink:href="#vvv-2" transform="translate(1360)"/><use xlink:href="#vvv-2" transform="translate(1380)"/><use xlink:href="#vvv-2" transform="translate(1400)"/><use xlink:href="#vvv-2" transform="translate(1420)"/><use xlink:href="#vvv-2" transform="translate(1440)"/><use xlink:href="#vvv-2" transform="translate(1460)"/><use xlink:href="#vvv-2" transform="translate(1480)"/><use xlink:href="#vvv-2" transform="translate(1500)"/><use xlink:href="#vvv-2" transform="translate(1520)"/><use xlink:href="#vvv-2" transform="translate(1540)"/><use xlink:href="#vvv-2" transform="translate(1560)"/><use xlink:href="#vvv-2" transform="translate(1580)"/><use xlink:href="#vvv-2" transform="translate(1600)"/><use xlink:href="#vvv-2" transform="translate(1620)"/><use xlink:href="#vvv-2" transform="translate(1640)"/><use xlink:href="#vvv-2" transform="translate(1660)"/><use xlink:href="#vvv-2" transform="translate(1680)"/><use xlink:href="#vvv-2" transform="translate(1700)"/><text x="1046" y="15" text-anchor="middle" xml:space="preserve"><tspan>5</tspan></text></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"/></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_RVALID</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#0m1" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#111" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#111" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#111" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#111" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#111" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#111" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#111" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#111" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#111" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#111" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#111" transform="translate(1200)"/><use xlink:href="#111" transform="translate(1220)"/><use xlink:href="#111" transform="translate(1240)"/><use xlink:href="#111" transform="translate(1260)"/><use xlink:href="#111" transform="translate(1280)"/><use xlink:href="#111" transform="translate(1300)"/><use xlink:href="#111" transform="translate(1320)"/><use xlink:href="#111" transform="translate(1340)"/><use xlink:href="#111" transform="translate(1360)"/><use xlink:href="#111" transform="translate(1380)"/><use xlink:href="#1m0" transform="translate(1400)"/><use xlink:href="#000" transform="translate(1420)"/><use xlink:href="#0m1" transform="translate(1440)"/><use xlink:href="#111" transform="translate(1460)"/><use xlink:href="#111" transform="translate(1480)"/><use xlink:href="#111" transform="translate(1500)"/><use xlink:href="#111" transform="translate(1520)"/><use xlink:href="#111" transform="translate(1540)"/><use xlink:href="#111" transform="translate(1560)"/><use xlink:href="#111" transform="translate(1580)"/><use xlink:href="#111" transform="translate(1600)"/><use xlink:href="#111" transform="translate(1620)"/><use xlink:href="#1m0" transform="translate(1640)"/><use xlink:href="#000" transform="translate(1660)"/><use xlink:href="#0m1" transform="translate(1680)"/><use xlink:href="#111" transform="translate(1700)"/></g></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_RDATA</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xmv-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vmv-3-3" transform="translate(440)"/><use xlink:href="#vvv-3" transform="translate(460)"/><use xlink:href="#vmv-3-3" transform="translate(480)"/><use xlink:href="#vvv-3" transform="translate(500)"/><use xlink:href="#vmv-3-3" transform="translate(520)"/><use xlink:href="#vvv-3" transform="translate(540)"/><use xlink:href="#vmv-3-3" transform="translate(560)"/><use xlink:href="#vvv-3" transform="translate(580)"/><use xlink:href="#vmv-3-3" transform="translate(600)"/><use xlink:href="#vvv-3" transform="translate(620)"/><use xlink:href="#vmv-3-4" transform="translate(640)"/><use xlink:href="#vvv-4" transform="translate(660)"/><use xlink:href="#vmv-4-4" transform="translate(680)"/><use xlink:href="#vvv-4" transform="translate(700)"/><use xlink:href="#vmv-4-4" transform="translate(720)"/><use xlink:href="#vvv-4" transform="translate(740)"/><use xlink:href="#vmv-4-4" transform="translate(760)"/><use xlink:href="#vvv-4" transform="translate(780)"/><use xlink:href="#vmv-4-4" transform="translate(800)"/><use xlink:href="#vvv-4" transform="translate(820)"/><use xlink:href="#vmv-4-4" transform="translate(840)"/><use xlink:href="#vvv-4" transform="translate(860)"/><use xlink:href="#vmv-4-5" transform="translate(880)"/><use xlink:href="#vvv-5" transform="translate(900)"/><use xlink:href="#vmv-5-5" transform="translate(920)"/><use xlink:href="#vvv-5" transform="translate(940)"/><use xlink:href="#vmv-5-5" transform="translate(960)"/><use xlink:href="#vvv-5" transform="translate(980)"/><use xlink:href="#vmv-5-5" transform="translate(1000)"/><use xlink:href="#vvv-5" transform="translate(1020)"/><use xlink:href="#vmv-5-5" transform="translate(1040)"/><use xlink:href="#vvv-5" transform="translate(1060)"/><use xlink:href="#vmv-5-5" transform="translate(1080)"/><use xlink:href="#vvv-5" transform="translate(1100)"/><use xlink:href="#vmv-5-6" transform="translate(1120)"/><use xlink:href="#vvv-6" transform="translate(1140)"/><use xlink:href="#vmv-6-6" transform="translate(1160)"/><use xlink:href="#vvv-6" transform="translate(1180)"/><use xlink:href="#vmv-6-6" transform="translate(1200)"/><use xlink:href="#vvv-6" transform="translate(1220)"/><use xlink:href="#vmv-6-6" transform="translate(1240)"/><use xlink:href="#vvv-6" transform="translate(1260)"/><use xlink:href="#vmv-6-6" transform="translate(1280)"/><use xlink:href="#vvv-6" transform="translate(1300)"/><use xlink:href="#vmv-6-6" transform="translate(1320)"/><use xlink:href="#vvv-6" transform="translate(1340)"/><use xlink:href="#vmv-6-7" transform="translate(1360)"/><use xlink:href="#vvv-7" transform="translate(1380)"/><use xlink:href="#vmx-7" transform="translate(1400)"/><use xlink:href="#xxx" transform="translate(1420)"/><use xlink:href="#xmv-7" transform="translate(1440)"/><use xlink:href="#vvv-7" transform="translate(1460)"/><use xlink:href="#vmv-7-7" transform="translate(1480)"/><use xlink:href="#vvv-7" transform="translate(1500)"/><use xlink:href="#vmv-7-7" transform="translate(1520)"/><use xlink:href="#vvv-7" transform="translate(1540)"/><use xlink:href="#vmv-7-7" transform="translate(1560)"/><use xlink:href="#vvv-7" transform="translate(1580)"/><use xlink:href="#vmv-7-7" transform="translate(1600)"/><use xlink:href="#vvv-7" transform="translate(1620)"/><use xlink:href="#vmx-7" transform="translate(1640)"/><use xlink:href="#xxx" transform="translate(1660)"/><use xlink:href="#xmv-8" transform="translate(1680)"/><use xlink:href="#vvv-8" transform="translate(1700)"/></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_RLAST</tspan></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xm0" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#0mv-3" transform="translate(600)"/><use xlink:href="#vvv-3" transform="translate(620)"/><use xlink:href="#vm0-3" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#0mv-4" transform="translate(840)"/><use xlink:href="#vvv-4" transform="translate(860)"/><use xlink:href="#vm0-4" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#0mv-5" transform="translate(1080)"/><use xlink:href="#vvv-5" transform="translate(1100)"/><use xlink:href="#vm0-5" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#000" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/><use xlink:href="#000" transform="translate(1200)"/><use xlink:href="#000" transform="translate(1220)"/><use xlink:href="#000" transform="translate(1240)"/><use xlink:href="#000" transform="translate(1260)"/><use xlink:href="#000" transform="translate(1280)"/><use xlink:href="#000" transform="translate(1300)"/><use xlink:href="#0mv-6" transform="translate(1320)"/><use xlink:href="#vvv-6" transform="translate(1340)"/><use xlink:href="#vm0-6" transform="translate(1360)"/><use xlink:href="#000" transform="translate(1380)"/><use xlink:href="#0mx" transform="translate(1400)"/><use xlink:href="#xxx" transform="translate(1420)"/><use xlink:href="#xm0" transform="translate(1440)"/><use xlink:href="#000" transform="translate(1460)"/><use xlink:href="#000" transform="translate(1480)"/><use xlink:href="#000" transform="translate(1500)"/><use xlink:href="#000" transform="translate(1520)"/><use xlink:href="#000" transform="translate(1540)"/><use xlink:href="#000" transform="translate(1560)"/><use xlink:href="#000" transform="translate(1580)"/><use xlink:href="#0mv-7" transform="translate(1600)"/><use xlink:href="#vvv-7" transform="translate(1620)"/><use xlink:href="#vmx-7" transform="translate(1640)"/><use xlink:href="#xxx" transform="translate(1660)"/><use xlink:href="#xm0" transform="translate(1680)"/><use xlink:href="#000" transform="translate(1700)"/></g></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"/></g><g id="wavelane_13_0" transform="translate(0,395)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIS_TVALID</tspan></text><g id="wavelane_draw_13_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#0m1" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#111" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#111" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#111" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#111" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#111" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#111" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#111" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#111" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#111" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#111" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#111" transform="translate(1200)"/><use xlink:href="#111" transform="translate(1220)"/><use xlink:href="#111" transform="translate(1240)"/><use xlink:href="#111" transform="translate(1260)"/><use xlink:href="#111" transform="translate(1280)"/><use xlink:href="#111" transform="translate(1300)"/><use xlink:href="#111" transform="translate(1320)"/><use xlink:href="#111" transform="translate(1340)"/><use xlink:href="#111" transform="translate(1360)"/><use xlink:href="#111" transform="translate(1380)"/><use xlink:href="#111" transform="translate(1400)"/><use xlink:href="#111" transform="translate(1420)"/><use xlink:href="#1m0" transform="translate(1440)"/><use xlink:href="#000" transform="translate(1460)"/><use xlink:href="#0m1" transform="translate(1480)"/><use xlink:href="#111" transform="translate(1500)"/><use xlink:href="#111" transform="translate(1520)"/><use xlink:href="#111" transform="translate(1540)"/><use xlink:href="#111" transform="translate(1560)"/><use xlink:href="#111" transform="translate(1580)"/><use xlink:href="#111" transform="translate(1600)"/><use xlink:href="#111" transform="translate(1620)"/><use xlink:href="#111" transform="translate(1640)"/><use xlink:href="#111" transform="translate(1660)"/><use xlink:href="#1m0" transform="translate(1680)"/><use xlink:href="#000" transform="translate(1700)"/></g></g><g id="wavelane_14_0" transform="translate(0,425)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIS_TDATA</tspan></text><g id="wavelane_draw_14_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xxx" transform="translate(400)"/><use xlink:href="#xxx" transform="translate(420)"/><use xlink:href="#xmv-3" transform="translate(440)"/><use xlink:href="#vvv-3" transform="translate(460)"/><use xlink:href="#vmv-3-3" transform="translate(480)"/><use xlink:href="#vvv-3" transform="translate(500)"/><use xlink:href="#vmv-3-3" transform="translate(520)"/><use xlink:href="#vvv-3" transform="translate(540)"/><use xlink:href="#vmv-3-3" transform="translate(560)"/><use xlink:href="#vvv-3" transform="translate(580)"/><use xlink:href="#vmv-3-3" transform="translate(600)"/><use xlink:href="#vvv-3" transform="translate(620)"/><use xlink:href="#vmv-3-3" transform="translate(640)"/><use xlink:href="#vvv-3" transform="translate(660)"/><use xlink:href="#vmv-3-4" transform="translate(680)"/><use xlink:href="#vvv-4" transform="translate(700)"/><use xlink:href="#vmv-4-4" transform="translate(720)"/><use xlink:href="#vvv-4" transform="translate(740)"/><use xlink:href="#vmv-4-4" transform="translate(760)"/><use xlink:href="#vvv-4" transform="translate(780)"/><use xlink:href="#vmv-4-4" transform="translate(800)"/><use xlink:href="#vvv-4" transform="translate(820)"/><use xlink:href="#vmv-4-4" transform="translate(840)"/><use xlink:href="#vvv-4" transform="translate(860)"/><use xlink:href="#vmv-4-4" transform="translate(880)"/><use xlink:href="#vvv-4" transform="translate(900)"/><use xlink:href="#vmv-4-5" transform="translate(920)"/><use xlink:href="#vvv-5" transform="translate(940)"/><use xlink:href="#vmv-5-5" transform="translate(960)"/><use xlink:href="#vvv-5" transform="translate(980)"/><use xlink:href="#vmv-5-5" transform="translate(1000)"/><use xlink:href="#vvv-5" transform="translate(1020)"/><use xlink:href="#vmv-5-5" transform="translate(1040)"/><use xlink:href="#vvv-5" transform="translate(1060)"/><use xlink:href="#vmv-5-5" transform="translate(1080)"/><use xlink:href="#vvv-5" transform="translate(1100)"/><use xlink:href="#vmv-5-5" transform="translate(1120)"/><use xlink:href="#vvv-5" transform="translate(1140)"/><use xlink:href="#vmv-5-6" transform="translate(1160)"/><use xlink:href="#vvv-6" transform="translate(1180)"/><use xlink:href="#vmv-6-6" transform="translate(1200)"/><use xlink:href="#vvv-6" transform="translate(1220)"/><use xlink:href="#vmv-6-6" transform="translate(1240)"/><use xlink:href="#vvv-6" transform="translate(1260)"/><use xlink:href="#vmv-6-6" transform="translate(1280)"/><use xlink:href="#vvv-6" transform="translate(1300)"/><use xlink:href="#vmv-6-6" transform="translate(1320)"/><use xlink:href="#vvv-6" transform="translate(1340)"/><use xlink:href="#vmv-6-6" transform="translate(1360)"/><use xlink:href="#vvv-6" transform="translate(1380)"/><use xlink:href="#vmv-6-7" transform="translate(1400)"/><use xlink:href="#vvv-7" transform="translate(1420)"/><use xlink:href="#vmx-7" transform="translate(1440)"/><use xlink:href="#xxx" transform="translate(1460)"/><use xlink:href="#xmv-7" transform="translate(1480)"/><use xlink:href="#vvv-7" transform="translate(1500)"/><use xlink:href="#vmv-7-7" transform="translate(1520)"/><use xlink:href="#vvv-7" transform="translate(1540)"/><use xlink:href="#vmv-7-7" transform="translate(1560)"/><use xlink:href="#vvv-7" transform="translate(1580)"/><use xlink:href="#vmv-7-7" transform="translate(1600)"/><use xlink:href="#vvv-7" transform="translate(1620)"/><use xlink:href="#vmv-7-7" transform="translate(1640)"/><use xlink:href="#vvv-7" transform="translate(1660)"/><use xlink:href="#vmx-7" transform="translate(1680)"/><use xlink:href="#xxx" transform="translate(1700)"/></g></g><g id="wavelane_15_0" transform="translate(0,455)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>H-LAST</tspan></text><g id="wavelane_draw_15_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xxx" transform="translate(400)"/><use xlink:href="#xxx" transform="translate(420)"/><use xlink:href="#xm0" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#0m1" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#1m0" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#0m1" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#1m0" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#000" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#0m1" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#1m0" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/><use xlink:href="#000" transform="translate(1200)"/><use xlink:href="#000" transform="translate(1220)"/><use xlink:href="#000" transform="translate(1240)"/><use xlink:href="#000" transform="translate(1260)"/><use xlink:href="#000" transform="translate(1280)"/><use xlink:href="#000" transform="translate(1300)"/><use xlink:href="#000" transform="translate(1320)"/><use xlink:href="#000" transform="translate(1340)"/><use xlink:href="#0m1" transform="translate(1360)"/><use xlink:href="#111" transform="translate(1380)"/><use xlink:href="#1m0" transform="translate(1400)"/><use xlink:href="#000" transform="translate(1420)"/><use xlink:href="#000" transform="translate(1440)"/><use xlink:href="#000" transform="translate(1460)"/><use xlink:href="#000" transform="translate(1480)"/><use xlink:href="#000" transform="translate(1500)"/><use xlink:href="#000" transform="translate(1520)"/><use xlink:href="#000" transform="translate(1540)"/><use xlink:href="#000" transform="translate(1560)"/><use xlink:href="#000" transform="translate(1580)"/><use xlink:href="#000" transform="translate(1600)"/><use xlink:href="#000" transform="translate(1620)"/><use xlink:href="#0m1" transform="translate(1640)"/><use xlink:href="#111" transform="translate(1660)"/><use xlink:href="#1mx" transform="translate(1680)"/><use xlink:href="#xxx" transform="translate(1700)"/></g></g><g id="wavelane_16_0" transform="translate(0,485)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>V-LAST</tspan></text><g id="wavelane_draw_16_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xxx" transform="translate(400)"/><use xlink:href="#xxx" transform="translate(420)"/><use xlink:href="#xm0" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#000" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#000" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#000" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/><use xlink:href="#000" transform="translate(1200)"/><use xlink:href="#000" transform="translate(1220)"/><use xlink:href="#000" transform="translate(1240)"/><use xlink:href="#000" transform="translate(1260)"/><use xlink:href="#000" transform="translate(1280)"/><use xlink:href="#000" transform="translate(1300)"/><use xlink:href="#000" transform="translate(1320)"/><use xlink:href="#000" transform="translate(1340)"/><use xlink:href="#000" transform="translate(1360)"/><use xlink:href="#000" transform="translate(1380)"/><use xlink:href="#000" transform="translate(1400)"/><use xlink:href="#000" transform="translate(1420)"/><use xlink:href="#000" transform="translate(1440)"/><use xlink:href="#000" transform="translate(1460)"/><use xlink:href="#000" transform="translate(1480)"/><use xlink:href="#000" transform="translate(1500)"/><use xlink:href="#000" transform="translate(1520)"/><use xlink:href="#000" transform="translate(1540)"/><use xlink:href="#000" transform="translate(1560)"/><use xlink:href="#000" transform="translate(1580)"/><use xlink:href="#000" transform="translate(1600)"/><use xlink:href="#000" transform="translate(1620)"/><use xlink:href="#0m1" transform="translate(1640)"/><use xlink:href="#111" transform="translate(1660)"/><use xlink:href="#1mx" transform="translate(1680)"/><use xlink:href="#xxx" transform="translate(1700)"/></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/><g id="wavegap_13_0" transform="translate(0,395)"/><g id="wavegap_14_0" transform="translate(0,425)"/><g id="wavegap_15_0" transform="translate(0,455)"/><g id="wavegap_16_0" transform="translate(0,485)"/></g></g><g id="groups_0"><g/></g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivfifo.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivfifo.json
new file mode 100644
index 0000000..e8e1e7a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivfifo.json
@@ -0,0 +1,21 @@
+{signal: [
+  {name: 'S_AXI_ARESETN', wave: '01......................................'},
+  {name: 'S_AXI_ACLK',    wave: 'PP......................................'},
+  {name: 'o_fill',        wave: '2..222222222222222222222................', data: ['0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24']},
+  {name: 'o_empty',       wave: '1..0....................................'},
+  {},
+  {name: 'S_AXIS_TVALID', wave: '0.1.....................................'},
+  {},
+  {name: 'ififo_fill',    wave: '2..2.22222222...........................', data: ['0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24']},
+  {name: 'M_AXI_AWVALID', wave: '0...........10......10......10......10..'},
+  {name: 'M_AXI_WVALID',  wave: '0...........2345678923456789234567892345'},
+  {name: 'M_AXI_WLAST',   wave: 'x...........0......10......10......10...', data: ['A0','A1','A2','A3','A4','A5','A6','A7','A8','A9']},
+  {name: 'M_AXI_BVALID',  wave: '0...................10......10......10..'},
+  {},
+  {name: 'M_AXI_ARVALID',wave: '0....................10......10......10.'},
+  {name: 'M_AXI_RVALID', wave: '0.....................23456789234567890.'},
+  {name: 'M_AXI_RLAST',  wave: 'x.....................0......10......1x.', data: ['D0','D1','D2','D3','d1','d2','d3','d4']},
+  {},
+  {name: 'ofifo_fill',  wave:  '0......................2...............0', data: ['1']},
+  {name: 'M_AXI_TVALID',wave:  '0......................11111111111111110', data: ['D0','D1','D2','D3','d1','d2','d3','d4']},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivfifo.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivfifo.png
new file mode 100644
index 0000000..f50d0c2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivfifo.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivfifo.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivfifo.svg
new file mode 100644
index 0000000..f6dc4c4
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axivfifo.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="570" width="1760" viewBox="0 0 1760 570" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{fill:#000;fill-opacity:1;stroke:none}.s7{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible}.s8{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible}.s9{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible}.s10{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible}.s11{color:#000;fill:#ccfdfe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible}.s12{color:#000;fill:#cdfdc5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible}.s13{color:#000;fill:#f0c1fb;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible}.s14{color:#000;fill:#f5c2c0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible}.s15{fill:#0041c4;fill-opacity:1;stroke:none}.s16{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s6"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s6"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s9"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s9"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s9"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s9"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s9"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s9"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-6"><path d="M2.875,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-6"><path d="M3,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-6"><path d="M20,20 0,20 0,0 20,0" class="s11"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-6"><path d="M0,20 0,0 3,0 9,20" class="s11"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-6"><path d="M0,0 0,20 3,20 9,0" class="s11"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-6"><path d="M0,0 0,20 3,20 6,10 3,0" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-6"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s11"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-6"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s11"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-6"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s11"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-7"><path d="M2.875,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-7"><path d="M3,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-7"><path d="M20,20 0,20 0,0 20,0" class="s12"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-7"><path d="M0,20 0,0 3,0 9,20" class="s12"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-7"><path d="M0,0 0,20 3,20 9,0" class="s12"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-7"><path d="M0,0 0,20 3,20 6,10 3,0" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-7"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s12"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-7"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s12"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-7"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s12"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-8"><path d="M2.875,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-8"><path d="M3,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-8"><path d="M20,20 0,20 0,0 20,0" class="s13"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-8"><path d="M0,20 0,0 3,0 9,20" class="s13"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-8"><path d="M0,0 0,20 3,20 9,0" class="s13"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-8"><path d="M0,0 0,20 3,20 6,10 3,0" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-8"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s13"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-8"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s13"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-8"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s13"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-9"><path d="M2.875,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-9"><path d="M3,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-9"><path d="M20,20 0,20 0,0 20,0" class="s14"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-9"><path d="M0,20 0,0 3,0 9,20" class="s14"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-9"><path d="M0,0 0,20 3,20 9,0" class="s14"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-9"><path d="M0,0 0,20 3,20 6,10 3,0" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-9"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s14"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-9"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s14"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-9"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s14"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s15"/><path d="M0,0 -15,0" class="s16"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(140.5, 0.5)"><g id="gmarks_0"><g style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"><line id="gmark_0_0" x1="0" y1="0" x2="0" y2="570"/><line id="gmark_1_0" x1="40" y1="0" x2="40" y2="570"/><line id="gmark_2_0" x1="80" y1="0" x2="80" y2="570"/><line id="gmark_3_0" x1="120" y1="0" x2="120" y2="570"/><line id="gmark_4_0" x1="160" y1="0" x2="160" y2="570"/><line id="gmark_5_0" x1="200" y1="0" x2="200" y2="570"/><line id="gmark_6_0" x1="240" y1="0" x2="240" y2="570"/><line id="gmark_7_0" x1="280" y1="0" x2="280" y2="570"/><line id="gmark_8_0" x1="320" y1="0" x2="320" y2="570"/><line id="gmark_9_0" x1="360" y1="0" x2="360" y2="570"/><line id="gmark_10_0" x1="400" y1="0" x2="400" y2="570"/><line id="gmark_11_0" x1="440" y1="0" x2="440" y2="570"/><line id="gmark_12_0" x1="480" y1="0" x2="480" y2="570"/><line id="gmark_13_0" x1="520" y1="0" x2="520" y2="570"/><line id="gmark_14_0" x1="560" y1="0" x2="560" y2="570"/><line id="gmark_15_0" x1="600" y1="0" x2="600" y2="570"/><line id="gmark_16_0" x1="640" y1="0" x2="640" y2="570"/><line id="gmark_17_0" x1="680" y1="0" x2="680" y2="570"/><line id="gmark_18_0" x1="720" y1="0" x2="720" y2="570"/><line id="gmark_19_0" x1="760" y1="0" x2="760" y2="570"/><line id="gmark_20_0" x1="800" y1="0" x2="800" y2="570"/><line id="gmark_21_0" x1="840" y1="0" x2="840" y2="570"/><line id="gmark_22_0" x1="880" y1="0" x2="880" y2="570"/><line id="gmark_23_0" x1="920" y1="0" x2="920" y2="570"/><line id="gmark_24_0" x1="960" y1="0" x2="960" y2="570"/><line id="gmark_25_0" x1="1000" y1="0" x2="1000" y2="570"/><line id="gmark_26_0" x1="1040" y1="0" x2="1040" y2="570"/><line id="gmark_27_0" x1="1080" y1="0" x2="1080" y2="570"/><line id="gmark_28_0" x1="1120" y1="0" x2="1120" y2="570"/><line id="gmark_29_0" x1="1160" y1="0" x2="1160" y2="570"/><line id="gmark_30_0" x1="1200" y1="0" x2="1200" y2="570"/><line id="gmark_31_0" x1="1240" y1="0" x2="1240" y2="570"/><line id="gmark_32_0" x1="1280" y1="0" x2="1280" y2="570"/><line id="gmark_33_0" x1="1320" y1="0" x2="1320" y2="570"/><line id="gmark_34_0" x1="1360" y1="0" x2="1360" y2="570"/><line id="gmark_35_0" x1="1400" y1="0" x2="1400" y2="570"/><line id="gmark_36_0" x1="1440" y1="0" x2="1440" y2="570"/><line id="gmark_37_0" x1="1480" y1="0" x2="1480" y2="570"/><line id="gmark_38_0" x1="1520" y1="0" x2="1520" y2="570"/><line id="gmark_39_0" x1="1560" y1="0" x2="1560" y2="570"/><line id="gmark_40_0" x1="1600" y1="0" x2="1600" y2="570"/></g></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#111" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#111" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#111" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#111" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#111" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#111" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#111" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#111" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#111" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#111" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#111" transform="translate(1200)"/><use xlink:href="#111" transform="translate(1220)"/><use xlink:href="#111" transform="translate(1240)"/><use xlink:href="#111" transform="translate(1260)"/><use xlink:href="#111" transform="translate(1280)"/><use xlink:href="#111" transform="translate(1300)"/><use xlink:href="#111" transform="translate(1320)"/><use xlink:href="#111" transform="translate(1340)"/><use xlink:href="#111" transform="translate(1360)"/><use xlink:href="#111" transform="translate(1380)"/><use xlink:href="#111" transform="translate(1400)"/><use xlink:href="#111" transform="translate(1420)"/><use xlink:href="#111" transform="translate(1440)"/><use xlink:href="#111" transform="translate(1460)"/><use xlink:href="#111" transform="translate(1480)"/><use xlink:href="#111" transform="translate(1500)"/><use xlink:href="#111" transform="translate(1520)"/><use xlink:href="#111" transform="translate(1540)"/><use xlink:href="#111" transform="translate(1560)"/><use xlink:href="#111" transform="translate(1580)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#Pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#Pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#Pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#Pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#Pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/><use xlink:href="#Pclk" transform="translate(200)"/><use xlink:href="#nclk" transform="translate(220)"/><use xlink:href="#Pclk" transform="translate(240)"/><use xlink:href="#nclk" transform="translate(260)"/><use xlink:href="#Pclk" transform="translate(280)"/><use xlink:href="#nclk" transform="translate(300)"/><use xlink:href="#Pclk" transform="translate(320)"/><use xlink:href="#nclk" transform="translate(340)"/><use xlink:href="#Pclk" transform="translate(360)"/><use xlink:href="#nclk" transform="translate(380)"/><use xlink:href="#Pclk" transform="translate(400)"/><use xlink:href="#nclk" transform="translate(420)"/><use xlink:href="#Pclk" transform="translate(440)"/><use xlink:href="#nclk" transform="translate(460)"/><use xlink:href="#Pclk" transform="translate(480)"/><use xlink:href="#nclk" transform="translate(500)"/><use xlink:href="#Pclk" transform="translate(520)"/><use xlink:href="#nclk" transform="translate(540)"/><use xlink:href="#Pclk" transform="translate(560)"/><use xlink:href="#nclk" transform="translate(580)"/><use xlink:href="#Pclk" transform="translate(600)"/><use xlink:href="#nclk" transform="translate(620)"/><use xlink:href="#Pclk" transform="translate(640)"/><use xlink:href="#nclk" transform="translate(660)"/><use xlink:href="#Pclk" transform="translate(680)"/><use xlink:href="#nclk" transform="translate(700)"/><use xlink:href="#Pclk" transform="translate(720)"/><use xlink:href="#nclk" transform="translate(740)"/><use xlink:href="#Pclk" transform="translate(760)"/><use xlink:href="#nclk" transform="translate(780)"/><use xlink:href="#Pclk" transform="translate(800)"/><use xlink:href="#nclk" transform="translate(820)"/><use xlink:href="#Pclk" transform="translate(840)"/><use xlink:href="#nclk" transform="translate(860)"/><use xlink:href="#Pclk" transform="translate(880)"/><use xlink:href="#nclk" transform="translate(900)"/><use xlink:href="#Pclk" transform="translate(920)"/><use xlink:href="#nclk" transform="translate(940)"/><use xlink:href="#Pclk" transform="translate(960)"/><use xlink:href="#nclk" transform="translate(980)"/><use xlink:href="#Pclk" transform="translate(1000)"/><use xlink:href="#nclk" transform="translate(1020)"/><use xlink:href="#Pclk" transform="translate(1040)"/><use xlink:href="#nclk" transform="translate(1060)"/><use xlink:href="#Pclk" transform="translate(1080)"/><use xlink:href="#nclk" transform="translate(1100)"/><use xlink:href="#Pclk" transform="translate(1120)"/><use xlink:href="#nclk" transform="translate(1140)"/><use xlink:href="#Pclk" transform="translate(1160)"/><use xlink:href="#nclk" transform="translate(1180)"/><use xlink:href="#Pclk" transform="translate(1200)"/><use xlink:href="#nclk" transform="translate(1220)"/><use xlink:href="#Pclk" transform="translate(1240)"/><use xlink:href="#nclk" transform="translate(1260)"/><use xlink:href="#Pclk" transform="translate(1280)"/><use xlink:href="#nclk" transform="translate(1300)"/><use xlink:href="#Pclk" transform="translate(1320)"/><use xlink:href="#nclk" transform="translate(1340)"/><use xlink:href="#Pclk" transform="translate(1360)"/><use xlink:href="#nclk" transform="translate(1380)"/><use xlink:href="#Pclk" transform="translate(1400)"/><use xlink:href="#nclk" transform="translate(1420)"/><use xlink:href="#Pclk" transform="translate(1440)"/><use xlink:href="#nclk" transform="translate(1460)"/><use xlink:href="#Pclk" transform="translate(1480)"/><use xlink:href="#nclk" transform="translate(1500)"/><use xlink:href="#Pclk" transform="translate(1520)"/><use xlink:href="#nclk" transform="translate(1540)"/><use xlink:href="#Pclk" transform="translate(1560)"/><use xlink:href="#nclk" transform="translate(1580)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>o_fill</tspan></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"><use xlink:href="#vvv-2" transform="translate(0)"/><use xlink:href="#vvv-2" transform="translate(20)"/><use xlink:href="#vvv-2" transform="translate(40)"/><use xlink:href="#vvv-2" transform="translate(60)"/><use xlink:href="#vvv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vmv-2-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vmv-2-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vmv-2-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vmv-2-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vmv-2-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vmv-2-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vmv-2-2" transform="translate(360)"/><use xlink:href="#vvv-2" transform="translate(380)"/><use xlink:href="#vmv-2-2" transform="translate(400)"/><use xlink:href="#vvv-2" transform="translate(420)"/><use xlink:href="#vmv-2-2" transform="translate(440)"/><use xlink:href="#vvv-2" transform="translate(460)"/><use xlink:href="#vmv-2-2" transform="translate(480)"/><use xlink:href="#vvv-2" transform="translate(500)"/><use xlink:href="#vmv-2-2" transform="translate(520)"/><use xlink:href="#vvv-2" transform="translate(540)"/><use xlink:href="#vmv-2-2" transform="translate(560)"/><use xlink:href="#vvv-2" transform="translate(580)"/><use xlink:href="#vmv-2-2" transform="translate(600)"/><use xlink:href="#vvv-2" transform="translate(620)"/><use xlink:href="#vmv-2-2" transform="translate(640)"/><use xlink:href="#vvv-2" transform="translate(660)"/><use xlink:href="#vmv-2-2" transform="translate(680)"/><use xlink:href="#vvv-2" transform="translate(700)"/><use xlink:href="#vmv-2-2" transform="translate(720)"/><use xlink:href="#vvv-2" transform="translate(740)"/><use xlink:href="#vmv-2-2" transform="translate(760)"/><use xlink:href="#vvv-2" transform="translate(780)"/><use xlink:href="#vmv-2-2" transform="translate(800)"/><use xlink:href="#vvv-2" transform="translate(820)"/><use xlink:href="#vmv-2-2" transform="translate(840)"/><use xlink:href="#vvv-2" transform="translate(860)"/><use xlink:href="#vmv-2-2" transform="translate(880)"/><use xlink:href="#vvv-2" transform="translate(900)"/><use xlink:href="#vmv-2-2" transform="translate(920)"/><use xlink:href="#vvv-2" transform="translate(940)"/><use xlink:href="#vvv-2" transform="translate(960)"/><use xlink:href="#vvv-2" transform="translate(980)"/><use xlink:href="#vvv-2" transform="translate(1000)"/><use xlink:href="#vvv-2" transform="translate(1020)"/><use xlink:href="#vvv-2" transform="translate(1040)"/><use xlink:href="#vvv-2" transform="translate(1060)"/><use xlink:href="#vvv-2" transform="translate(1080)"/><use xlink:href="#vvv-2" transform="translate(1100)"/><use xlink:href="#vvv-2" transform="translate(1120)"/><use xlink:href="#vvv-2" transform="translate(1140)"/><use xlink:href="#vvv-2" transform="translate(1160)"/><use xlink:href="#vvv-2" transform="translate(1180)"/><use xlink:href="#vvv-2" transform="translate(1200)"/><use xlink:href="#vvv-2" transform="translate(1220)"/><use xlink:href="#vvv-2" transform="translate(1240)"/><use xlink:href="#vvv-2" transform="translate(1260)"/><use xlink:href="#vvv-2" transform="translate(1280)"/><use xlink:href="#vvv-2" transform="translate(1300)"/><use xlink:href="#vvv-2" transform="translate(1320)"/><use xlink:href="#vvv-2" transform="translate(1340)"/><use xlink:href="#vvv-2" transform="translate(1360)"/><use xlink:href="#vvv-2" transform="translate(1380)"/><use xlink:href="#vvv-2" transform="translate(1400)"/><use xlink:href="#vvv-2" transform="translate(1420)"/><use xlink:href="#vvv-2" transform="translate(1440)"/><use xlink:href="#vvv-2" transform="translate(1460)"/><use xlink:href="#vvv-2" transform="translate(1480)"/><use xlink:href="#vvv-2" transform="translate(1500)"/><use xlink:href="#vvv-2" transform="translate(1520)"/><use xlink:href="#vvv-2" transform="translate(1540)"/><use xlink:href="#vvv-2" transform="translate(1560)"/><use xlink:href="#vvv-2" transform="translate(1580)"/><text x="56" y="15" text-anchor="middle" xml:space="preserve"><tspan>0</tspan></text><text x="146" y="15" text-anchor="middle" xml:space="preserve"><tspan>1</tspan></text><text x="186" y="15" text-anchor="middle" xml:space="preserve"><tspan>2</tspan></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>3</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>4</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>5</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>6</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>7</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>8</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>9</tspan></text><text x="506" y="15" text-anchor="middle" xml:space="preserve"><tspan>10</tspan></text><text x="546" y="15" text-anchor="middle" xml:space="preserve"><tspan>11</tspan></text><text x="586" y="15" text-anchor="middle" xml:space="preserve"><tspan>12</tspan></text><text x="626" y="15" text-anchor="middle" xml:space="preserve"><tspan>13</tspan></text><text x="666" y="15" text-anchor="middle" xml:space="preserve"><tspan>14</tspan></text><text x="706" y="15" text-anchor="middle" xml:space="preserve"><tspan>15</tspan></text><text x="746" y="15" text-anchor="middle" xml:space="preserve"><tspan>16</tspan></text><text x="786" y="15" text-anchor="middle" xml:space="preserve"><tspan>17</tspan></text><text x="826" y="15" text-anchor="middle" xml:space="preserve"><tspan>18</tspan></text><text x="866" y="15" text-anchor="middle" xml:space="preserve"><tspan>19</tspan></text><text x="906" y="15" text-anchor="middle" xml:space="preserve"><tspan>20</tspan></text><text x="1266" y="15" text-anchor="middle" xml:space="preserve"><tspan>21</tspan></text></g></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>o_empty</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#111" transform="translate(0)"/><use xlink:href="#111" transform="translate(20)"/><use xlink:href="#111" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1m0" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#000" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#000" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#000" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/><use xlink:href="#000" transform="translate(1200)"/><use xlink:href="#000" transform="translate(1220)"/><use xlink:href="#000" transform="translate(1240)"/><use xlink:href="#000" transform="translate(1260)"/><use xlink:href="#000" transform="translate(1280)"/><use xlink:href="#000" transform="translate(1300)"/><use xlink:href="#000" transform="translate(1320)"/><use xlink:href="#000" transform="translate(1340)"/><use xlink:href="#000" transform="translate(1360)"/><use xlink:href="#000" transform="translate(1380)"/><use xlink:href="#000" transform="translate(1400)"/><use xlink:href="#000" transform="translate(1420)"/><use xlink:href="#000" transform="translate(1440)"/><use xlink:href="#000" transform="translate(1460)"/><use xlink:href="#000" transform="translate(1480)"/><use xlink:href="#000" transform="translate(1500)"/><use xlink:href="#000" transform="translate(1520)"/><use xlink:href="#000" transform="translate(1540)"/><use xlink:href="#000" transform="translate(1560)"/><use xlink:href="#000" transform="translate(1580)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"/></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXIS_TVALID</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#111" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#111" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#111" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#111" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#111" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#111" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#111" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#111" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#111" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#111" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#111" transform="translate(1200)"/><use xlink:href="#111" transform="translate(1220)"/><use xlink:href="#111" transform="translate(1240)"/><use xlink:href="#111" transform="translate(1260)"/><use xlink:href="#111" transform="translate(1280)"/><use xlink:href="#111" transform="translate(1300)"/><use xlink:href="#111" transform="translate(1320)"/><use xlink:href="#111" transform="translate(1340)"/><use xlink:href="#111" transform="translate(1360)"/><use xlink:href="#111" transform="translate(1380)"/><use xlink:href="#111" transform="translate(1400)"/><use xlink:href="#111" transform="translate(1420)"/><use xlink:href="#111" transform="translate(1440)"/><use xlink:href="#111" transform="translate(1460)"/><use xlink:href="#111" transform="translate(1480)"/><use xlink:href="#111" transform="translate(1500)"/><use xlink:href="#111" transform="translate(1520)"/><use xlink:href="#111" transform="translate(1540)"/><use xlink:href="#111" transform="translate(1560)"/><use xlink:href="#111" transform="translate(1580)"/></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"/></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>ififo_fill</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#vvv-2" transform="translate(0)"/><use xlink:href="#vvv-2" transform="translate(20)"/><use xlink:href="#vvv-2" transform="translate(40)"/><use xlink:href="#vvv-2" transform="translate(60)"/><use xlink:href="#vvv-2" transform="translate(80)"/><use xlink:href="#vvv-2" transform="translate(100)"/><use xlink:href="#vmv-2-2" transform="translate(120)"/><use xlink:href="#vvv-2" transform="translate(140)"/><use xlink:href="#vvv-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vmv-2-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vmv-2-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vmv-2-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vmv-2-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vmv-2-2" transform="translate(360)"/><use xlink:href="#vvv-2" transform="translate(380)"/><use xlink:href="#vmv-2-2" transform="translate(400)"/><use xlink:href="#vvv-2" transform="translate(420)"/><use xlink:href="#vmv-2-2" transform="translate(440)"/><use xlink:href="#vvv-2" transform="translate(460)"/><use xlink:href="#vmv-2-2" transform="translate(480)"/><use xlink:href="#vvv-2" transform="translate(500)"/><use xlink:href="#vvv-2" transform="translate(520)"/><use xlink:href="#vvv-2" transform="translate(540)"/><use xlink:href="#vvv-2" transform="translate(560)"/><use xlink:href="#vvv-2" transform="translate(580)"/><use xlink:href="#vvv-2" transform="translate(600)"/><use xlink:href="#vvv-2" transform="translate(620)"/><use xlink:href="#vvv-2" transform="translate(640)"/><use xlink:href="#vvv-2" transform="translate(660)"/><use xlink:href="#vvv-2" transform="translate(680)"/><use xlink:href="#vvv-2" transform="translate(700)"/><use xlink:href="#vvv-2" transform="translate(720)"/><use xlink:href="#vvv-2" transform="translate(740)"/><use xlink:href="#vvv-2" transform="translate(760)"/><use xlink:href="#vvv-2" transform="translate(780)"/><use xlink:href="#vvv-2" transform="translate(800)"/><use xlink:href="#vvv-2" transform="translate(820)"/><use xlink:href="#vvv-2" transform="translate(840)"/><use xlink:href="#vvv-2" transform="translate(860)"/><use xlink:href="#vvv-2" transform="translate(880)"/><use xlink:href="#vvv-2" transform="translate(900)"/><use xlink:href="#vvv-2" transform="translate(920)"/><use xlink:href="#vvv-2" transform="translate(940)"/><use xlink:href="#vvv-2" transform="translate(960)"/><use xlink:href="#vvv-2" transform="translate(980)"/><use xlink:href="#vvv-2" transform="translate(1000)"/><use xlink:href="#vvv-2" transform="translate(1020)"/><use xlink:href="#vvv-2" transform="translate(1040)"/><use xlink:href="#vvv-2" transform="translate(1060)"/><use xlink:href="#vvv-2" transform="translate(1080)"/><use xlink:href="#vvv-2" transform="translate(1100)"/><use xlink:href="#vvv-2" transform="translate(1120)"/><use xlink:href="#vvv-2" transform="translate(1140)"/><use xlink:href="#vvv-2" transform="translate(1160)"/><use xlink:href="#vvv-2" transform="translate(1180)"/><use xlink:href="#vvv-2" transform="translate(1200)"/><use xlink:href="#vvv-2" transform="translate(1220)"/><use xlink:href="#vvv-2" transform="translate(1240)"/><use xlink:href="#vvv-2" transform="translate(1260)"/><use xlink:href="#vvv-2" transform="translate(1280)"/><use xlink:href="#vvv-2" transform="translate(1300)"/><use xlink:href="#vvv-2" transform="translate(1320)"/><use xlink:href="#vvv-2" transform="translate(1340)"/><use xlink:href="#vvv-2" transform="translate(1360)"/><use xlink:href="#vvv-2" transform="translate(1380)"/><use xlink:href="#vvv-2" transform="translate(1400)"/><use xlink:href="#vvv-2" transform="translate(1420)"/><use xlink:href="#vvv-2" transform="translate(1440)"/><use xlink:href="#vvv-2" transform="translate(1460)"/><use xlink:href="#vvv-2" transform="translate(1480)"/><use xlink:href="#vvv-2" transform="translate(1500)"/><use xlink:href="#vvv-2" transform="translate(1520)"/><use xlink:href="#vvv-2" transform="translate(1540)"/><use xlink:href="#vvv-2" transform="translate(1560)"/><use xlink:href="#vvv-2" transform="translate(1580)"/><text x="56" y="15" text-anchor="middle" xml:space="preserve"><tspan>0</tspan></text><text x="166" y="15" text-anchor="middle" xml:space="preserve"><tspan>1</tspan></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>2</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>3</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>4</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>5</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>6</tspan></text><text x="426" y="15" text-anchor="middle" xml:space="preserve"><tspan>7</tspan></text><text x="466" y="15" text-anchor="middle" xml:space="preserve"><tspan>8</tspan></text><text x="1046" y="15" text-anchor="middle" xml:space="preserve"><tspan>9</tspan></text></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_AWVALID</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#0m1" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#1m0" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#0m1" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#1m0" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#000" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#0m1" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#1m0" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/><use xlink:href="#000" transform="translate(1200)"/><use xlink:href="#000" transform="translate(1220)"/><use xlink:href="#000" transform="translate(1240)"/><use xlink:href="#000" transform="translate(1260)"/><use xlink:href="#000" transform="translate(1280)"/><use xlink:href="#000" transform="translate(1300)"/><use xlink:href="#000" transform="translate(1320)"/><use xlink:href="#000" transform="translate(1340)"/><use xlink:href="#000" transform="translate(1360)"/><use xlink:href="#000" transform="translate(1380)"/><use xlink:href="#000" transform="translate(1400)"/><use xlink:href="#000" transform="translate(1420)"/><use xlink:href="#0m1" transform="translate(1440)"/><use xlink:href="#111" transform="translate(1460)"/><use xlink:href="#1m0" transform="translate(1480)"/><use xlink:href="#000" transform="translate(1500)"/><use xlink:href="#000" transform="translate(1520)"/><use xlink:href="#000" transform="translate(1540)"/><use xlink:href="#000" transform="translate(1560)"/><use xlink:href="#000" transform="translate(1580)"/></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_WVALID</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#0mv-2" transform="translate(480)"/><use xlink:href="#vvv-2" transform="translate(500)"/><use xlink:href="#vmv-2-3" transform="translate(520)"/><use xlink:href="#vvv-3" transform="translate(540)"/><use xlink:href="#vmv-3-4" transform="translate(560)"/><use xlink:href="#vvv-4" transform="translate(580)"/><use xlink:href="#vmv-4-5" transform="translate(600)"/><use xlink:href="#vvv-5" transform="translate(620)"/><use xlink:href="#vmv-5-6" transform="translate(640)"/><use xlink:href="#vvv-6" transform="translate(660)"/><use xlink:href="#vmv-6-7" transform="translate(680)"/><use xlink:href="#vvv-7" transform="translate(700)"/><use xlink:href="#vmv-7-8" transform="translate(720)"/><use xlink:href="#vvv-8" transform="translate(740)"/><use xlink:href="#vmv-8-9" transform="translate(760)"/><use xlink:href="#vvv-9" transform="translate(780)"/><use xlink:href="#vmv-9-2" transform="translate(800)"/><use xlink:href="#vvv-2" transform="translate(820)"/><use xlink:href="#vmv-2-3" transform="translate(840)"/><use xlink:href="#vvv-3" transform="translate(860)"/><use xlink:href="#vmv-3-4" transform="translate(880)"/><use xlink:href="#vvv-4" transform="translate(900)"/><use xlink:href="#vmv-4-5" transform="translate(920)"/><use xlink:href="#vvv-5" transform="translate(940)"/><use xlink:href="#vmv-5-6" transform="translate(960)"/><use xlink:href="#vvv-6" transform="translate(980)"/><use xlink:href="#vmv-6-7" transform="translate(1000)"/><use xlink:href="#vvv-7" transform="translate(1020)"/><use xlink:href="#vmv-7-8" transform="translate(1040)"/><use xlink:href="#vvv-8" transform="translate(1060)"/><use xlink:href="#vmv-8-9" transform="translate(1080)"/><use xlink:href="#vvv-9" transform="translate(1100)"/><use xlink:href="#vmv-9-2" transform="translate(1120)"/><use xlink:href="#vvv-2" transform="translate(1140)"/><use xlink:href="#vmv-2-3" transform="translate(1160)"/><use xlink:href="#vvv-3" transform="translate(1180)"/><use xlink:href="#vmv-3-4" transform="translate(1200)"/><use xlink:href="#vvv-4" transform="translate(1220)"/><use xlink:href="#vmv-4-5" transform="translate(1240)"/><use xlink:href="#vvv-5" transform="translate(1260)"/><use xlink:href="#vmv-5-6" transform="translate(1280)"/><use xlink:href="#vvv-6" transform="translate(1300)"/><use xlink:href="#vmv-6-7" transform="translate(1320)"/><use xlink:href="#vvv-7" transform="translate(1340)"/><use xlink:href="#vmv-7-8" transform="translate(1360)"/><use xlink:href="#vvv-8" transform="translate(1380)"/><use xlink:href="#vmv-8-9" transform="translate(1400)"/><use xlink:href="#vvv-9" transform="translate(1420)"/><use xlink:href="#vmv-9-2" transform="translate(1440)"/><use xlink:href="#vvv-2" transform="translate(1460)"/><use xlink:href="#vmv-2-3" transform="translate(1480)"/><use xlink:href="#vvv-3" transform="translate(1500)"/><use xlink:href="#vmv-3-4" transform="translate(1520)"/><use xlink:href="#vvv-4" transform="translate(1540)"/><use xlink:href="#vmv-4-5" transform="translate(1560)"/><use xlink:href="#vvv-5" transform="translate(1580)"/></g></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_WLAST</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xxx" transform="translate(400)"/><use xlink:href="#xxx" transform="translate(420)"/><use xlink:href="#xxx" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xm0" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#0m1" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#1m0" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#0m1" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#1m0" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#000" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/><use xlink:href="#000" transform="translate(1200)"/><use xlink:href="#000" transform="translate(1220)"/><use xlink:href="#000" transform="translate(1240)"/><use xlink:href="#000" transform="translate(1260)"/><use xlink:href="#000" transform="translate(1280)"/><use xlink:href="#000" transform="translate(1300)"/><use xlink:href="#000" transform="translate(1320)"/><use xlink:href="#000" transform="translate(1340)"/><use xlink:href="#000" transform="translate(1360)"/><use xlink:href="#000" transform="translate(1380)"/><use xlink:href="#0m1" transform="translate(1400)"/><use xlink:href="#111" transform="translate(1420)"/><use xlink:href="#1m0" transform="translate(1440)"/><use xlink:href="#000" transform="translate(1460)"/><use xlink:href="#000" transform="translate(1480)"/><use xlink:href="#000" transform="translate(1500)"/><use xlink:href="#000" transform="translate(1520)"/><use xlink:href="#000" transform="translate(1540)"/><use xlink:href="#000" transform="translate(1560)"/><use xlink:href="#000" transform="translate(1580)"/></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_BVALID</tspan></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#0m1" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#1m0" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#000" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#0m1" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#1m0" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/><use xlink:href="#000" transform="translate(1200)"/><use xlink:href="#000" transform="translate(1220)"/><use xlink:href="#000" transform="translate(1240)"/><use xlink:href="#000" transform="translate(1260)"/><use xlink:href="#000" transform="translate(1280)"/><use xlink:href="#000" transform="translate(1300)"/><use xlink:href="#000" transform="translate(1320)"/><use xlink:href="#000" transform="translate(1340)"/><use xlink:href="#000" transform="translate(1360)"/><use xlink:href="#000" transform="translate(1380)"/><use xlink:href="#000" transform="translate(1400)"/><use xlink:href="#000" transform="translate(1420)"/><use xlink:href="#0m1" transform="translate(1440)"/><use xlink:href="#111" transform="translate(1460)"/><use xlink:href="#1m0" transform="translate(1480)"/><use xlink:href="#000" transform="translate(1500)"/><use xlink:href="#000" transform="translate(1520)"/><use xlink:href="#000" transform="translate(1540)"/><use xlink:href="#000" transform="translate(1560)"/><use xlink:href="#000" transform="translate(1580)"/></g></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"/></g><g id="wavelane_13_0" transform="translate(0,395)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_ARVALID</tspan></text><g id="wavelane_draw_13_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#0m1" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#1m0" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#000" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#000" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#0m1" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#1m0" transform="translate(1200)"/><use xlink:href="#000" transform="translate(1220)"/><use xlink:href="#000" transform="translate(1240)"/><use xlink:href="#000" transform="translate(1260)"/><use xlink:href="#000" transform="translate(1280)"/><use xlink:href="#000" transform="translate(1300)"/><use xlink:href="#000" transform="translate(1320)"/><use xlink:href="#000" transform="translate(1340)"/><use xlink:href="#000" transform="translate(1360)"/><use xlink:href="#000" transform="translate(1380)"/><use xlink:href="#000" transform="translate(1400)"/><use xlink:href="#000" transform="translate(1420)"/><use xlink:href="#000" transform="translate(1440)"/><use xlink:href="#000" transform="translate(1460)"/><use xlink:href="#0m1" transform="translate(1480)"/><use xlink:href="#111" transform="translate(1500)"/><use xlink:href="#1m0" transform="translate(1520)"/><use xlink:href="#000" transform="translate(1540)"/><use xlink:href="#000" transform="translate(1560)"/><use xlink:href="#000" transform="translate(1580)"/></g></g><g id="wavelane_14_0" transform="translate(0,425)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_RVALID</tspan></text><g id="wavelane_draw_14_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#0mv-2" transform="translate(880)"/><use xlink:href="#vvv-2" transform="translate(900)"/><use xlink:href="#vmv-2-3" transform="translate(920)"/><use xlink:href="#vvv-3" transform="translate(940)"/><use xlink:href="#vmv-3-4" transform="translate(960)"/><use xlink:href="#vvv-4" transform="translate(980)"/><use xlink:href="#vmv-4-5" transform="translate(1000)"/><use xlink:href="#vvv-5" transform="translate(1020)"/><use xlink:href="#vmv-5-6" transform="translate(1040)"/><use xlink:href="#vvv-6" transform="translate(1060)"/><use xlink:href="#vmv-6-7" transform="translate(1080)"/><use xlink:href="#vvv-7" transform="translate(1100)"/><use xlink:href="#vmv-7-8" transform="translate(1120)"/><use xlink:href="#vvv-8" transform="translate(1140)"/><use xlink:href="#vmv-8-9" transform="translate(1160)"/><use xlink:href="#vvv-9" transform="translate(1180)"/><use xlink:href="#vmv-9-2" transform="translate(1200)"/><use xlink:href="#vvv-2" transform="translate(1220)"/><use xlink:href="#vmv-2-3" transform="translate(1240)"/><use xlink:href="#vvv-3" transform="translate(1260)"/><use xlink:href="#vmv-3-4" transform="translate(1280)"/><use xlink:href="#vvv-4" transform="translate(1300)"/><use xlink:href="#vmv-4-5" transform="translate(1320)"/><use xlink:href="#vvv-5" transform="translate(1340)"/><use xlink:href="#vmv-5-6" transform="translate(1360)"/><use xlink:href="#vvv-6" transform="translate(1380)"/><use xlink:href="#vmv-6-7" transform="translate(1400)"/><use xlink:href="#vvv-7" transform="translate(1420)"/><use xlink:href="#vmv-7-8" transform="translate(1440)"/><use xlink:href="#vvv-8" transform="translate(1460)"/><use xlink:href="#vmv-8-9" transform="translate(1480)"/><use xlink:href="#vvv-9" transform="translate(1500)"/><use xlink:href="#vm0-9" transform="translate(1520)"/><use xlink:href="#000" transform="translate(1540)"/><use xlink:href="#000" transform="translate(1560)"/><use xlink:href="#000" transform="translate(1580)"/></g></g><g id="wavelane_15_0" transform="translate(0,455)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_RLAST</tspan></text><g id="wavelane_draw_15_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xxx" transform="translate(200)"/><use xlink:href="#xxx" transform="translate(220)"/><use xlink:href="#xxx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xxx" transform="translate(320)"/><use xlink:href="#xxx" transform="translate(340)"/><use xlink:href="#xxx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xxx" transform="translate(400)"/><use xlink:href="#xxx" transform="translate(420)"/><use xlink:href="#xxx" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/><use xlink:href="#xxx" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><use xlink:href="#xxx" transform="translate(520)"/><use xlink:href="#xxx" transform="translate(540)"/><use xlink:href="#xxx" transform="translate(560)"/><use xlink:href="#xxx" transform="translate(580)"/><use xlink:href="#xxx" transform="translate(600)"/><use xlink:href="#xxx" transform="translate(620)"/><use xlink:href="#xxx" transform="translate(640)"/><use xlink:href="#xxx" transform="translate(660)"/><use xlink:href="#xxx" transform="translate(680)"/><use xlink:href="#xxx" transform="translate(700)"/><use xlink:href="#xxx" transform="translate(720)"/><use xlink:href="#xxx" transform="translate(740)"/><use xlink:href="#xxx" transform="translate(760)"/><use xlink:href="#xxx" transform="translate(780)"/><use xlink:href="#xxx" transform="translate(800)"/><use xlink:href="#xxx" transform="translate(820)"/><use xlink:href="#xxx" transform="translate(840)"/><use xlink:href="#xxx" transform="translate(860)"/><use xlink:href="#xm0" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#000" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#000" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#0m1" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#1m0" transform="translate(1200)"/><use xlink:href="#000" transform="translate(1220)"/><use xlink:href="#000" transform="translate(1240)"/><use xlink:href="#000" transform="translate(1260)"/><use xlink:href="#000" transform="translate(1280)"/><use xlink:href="#000" transform="translate(1300)"/><use xlink:href="#000" transform="translate(1320)"/><use xlink:href="#000" transform="translate(1340)"/><use xlink:href="#000" transform="translate(1360)"/><use xlink:href="#000" transform="translate(1380)"/><use xlink:href="#000" transform="translate(1400)"/><use xlink:href="#000" transform="translate(1420)"/><use xlink:href="#000" transform="translate(1440)"/><use xlink:href="#000" transform="translate(1460)"/><use xlink:href="#0m1" transform="translate(1480)"/><use xlink:href="#111" transform="translate(1500)"/><use xlink:href="#1mx" transform="translate(1520)"/><use xlink:href="#xxx" transform="translate(1540)"/><use xlink:href="#xxx" transform="translate(1560)"/><use xlink:href="#xxx" transform="translate(1580)"/></g></g><g id="wavelane_16_0" transform="translate(0,485)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_16_0" transform="translate(0, 0)"/></g><g id="wavelane_17_0" transform="translate(0,515)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>ofifo_fill</tspan></text><g id="wavelane_draw_17_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#0mv-2" transform="translate(920)"/><use xlink:href="#vvv-2" transform="translate(940)"/><use xlink:href="#vvv-2" transform="translate(960)"/><use xlink:href="#vvv-2" transform="translate(980)"/><use xlink:href="#vvv-2" transform="translate(1000)"/><use xlink:href="#vvv-2" transform="translate(1020)"/><use xlink:href="#vvv-2" transform="translate(1040)"/><use xlink:href="#vvv-2" transform="translate(1060)"/><use xlink:href="#vvv-2" transform="translate(1080)"/><use xlink:href="#vvv-2" transform="translate(1100)"/><use xlink:href="#vvv-2" transform="translate(1120)"/><use xlink:href="#vvv-2" transform="translate(1140)"/><use xlink:href="#vvv-2" transform="translate(1160)"/><use xlink:href="#vvv-2" transform="translate(1180)"/><use xlink:href="#vvv-2" transform="translate(1200)"/><use xlink:href="#vvv-2" transform="translate(1220)"/><use xlink:href="#vvv-2" transform="translate(1240)"/><use xlink:href="#vvv-2" transform="translate(1260)"/><use xlink:href="#vvv-2" transform="translate(1280)"/><use xlink:href="#vvv-2" transform="translate(1300)"/><use xlink:href="#vvv-2" transform="translate(1320)"/><use xlink:href="#vvv-2" transform="translate(1340)"/><use xlink:href="#vvv-2" transform="translate(1360)"/><use xlink:href="#vvv-2" transform="translate(1380)"/><use xlink:href="#vvv-2" transform="translate(1400)"/><use xlink:href="#vvv-2" transform="translate(1420)"/><use xlink:href="#vvv-2" transform="translate(1440)"/><use xlink:href="#vvv-2" transform="translate(1460)"/><use xlink:href="#vvv-2" transform="translate(1480)"/><use xlink:href="#vvv-2" transform="translate(1500)"/><use xlink:href="#vvv-2" transform="translate(1520)"/><use xlink:href="#vvv-2" transform="translate(1540)"/><use xlink:href="#vm0-2" transform="translate(1560)"/><use xlink:href="#000" transform="translate(1580)"/><text x="1246" y="15" text-anchor="middle" xml:space="preserve"><tspan>1</tspan></text></g></g><g id="wavelane_18_0" transform="translate(0,545)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXI_TVALID</tspan></text><g id="wavelane_draw_18_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#0m1" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#1m1" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#1m1" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#1m1" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#1m1" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#1m1" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#1m1" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#1m1" transform="translate(1200)"/><use xlink:href="#111" transform="translate(1220)"/><use xlink:href="#1m1" transform="translate(1240)"/><use xlink:href="#111" transform="translate(1260)"/><use xlink:href="#1m1" transform="translate(1280)"/><use xlink:href="#111" transform="translate(1300)"/><use xlink:href="#1m1" transform="translate(1320)"/><use xlink:href="#111" transform="translate(1340)"/><use xlink:href="#1m1" transform="translate(1360)"/><use xlink:href="#111" transform="translate(1380)"/><use xlink:href="#1m1" transform="translate(1400)"/><use xlink:href="#111" transform="translate(1420)"/><use xlink:href="#1m1" transform="translate(1440)"/><use xlink:href="#111" transform="translate(1460)"/><use xlink:href="#1m1" transform="translate(1480)"/><use xlink:href="#111" transform="translate(1500)"/><use xlink:href="#1m1" transform="translate(1520)"/><use xlink:href="#111" transform="translate(1540)"/><use xlink:href="#1m0" transform="translate(1560)"/><use xlink:href="#000" transform="translate(1580)"/></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/><g id="wavegap_13_0" transform="translate(0,395)"/><g id="wavegap_14_0" transform="translate(0,425)"/><g id="wavegap_15_0" transform="translate(0,455)"/><g id="wavegap_16_0" transform="translate(0,485)"/><g id="wavegap_17_0" transform="translate(0,515)"/><g id="wavegap_18_0" transform="translate(0,545)"/></g></g><g id="groups_0"><g/></g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axixbar-latency.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axixbar-latency.png
new file mode 100644
index 0000000..edce91a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/axixbar-latency.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/brken-axilite.dia b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/brken-axilite.dia
new file mode 100644
index 0000000..13a6cb5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/brken-axilite.dia
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/brken-axilite.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/brken-axilite.png
new file mode 100644
index 0000000..2c5a1d9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/brken-axilite.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/demofull-rd-basic.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/demofull-rd-basic.png
new file mode 100644
index 0000000..f15a631
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/demofull-rd-basic.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/demofull-rd-double.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/demofull-rd-double.png
new file mode 100644
index 0000000..d00278a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/demofull-rd-double.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/demofull-wr-double.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/demofull-wr-double.png
new file mode 100644
index 0000000..c06a27f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/demofull-wr-double.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/demofull-write-cover-trace.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/demofull-write-cover-trace.png
new file mode 100644
index 0000000..cb75f01
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/demofull-write-cover-trace.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/fv-example10-axil.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/fv-example10-axil.png
new file mode 100644
index 0000000..7125137
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/fv-example10-axil.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/misbehaving-axi-slave.dia b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/misbehaving-axi-slave.dia
new file mode 100644
index 0000000..6255bc8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/misbehaving-axi-slave.dia
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/misbehaving-axi-slave.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/misbehaving-axi-slave.png
new file mode 100644
index 0000000..dcc45e7
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/misbehaving-axi-slave.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/safety-proofs.dia b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/safety-proofs.dia
new file mode 100644
index 0000000..037e5da
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/safety-proofs.dia
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/safety-proofs.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/safety-proofs.png
new file mode 100644
index 0000000..da5a2ec
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/safety-proofs.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/swerv_ar_w.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/swerv_ar_w.png
new file mode 100644
index 0000000..5b7f5ed
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/swerv_ar_w.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbaxi-bridge-rresp-fail-code.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbaxi-bridge-rresp-fail-code.png
new file mode 100644
index 0000000..662babd
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbaxi-bridge-rresp-fail-code.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbaxi-bridge-rresp-fail.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbaxi-bridge-rresp-fail.json
new file mode 100644
index 0000000..389ec0b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbaxi-bridge-rresp-fail.json
@@ -0,0 +1,15 @@
+{signal: [
+  {name: 'S_AXI_ACLK',    wave: 'P...........'},
+  {name: 'S_AXI_ARESETN', wave: '01..........'},
+  {},
+  {name: 'WB_CYC',        wave: '0.1.........'},
+  {name: 'WB_STB',        wave: '0.10.10.10..'},
+  {name: 'WB_WE',         wave: 'x.0x.0x.0x..'},
+  {name: 'WB_STALL',      wave: 'x.0xx0xx0xx.'},
+  {name: 'WB_ACK',        wave: '0...........'},
+  {name: 'WB_ERR',        wave: '0...........'},
+  {},
+  {name: 'S_AXI_ARVALID', wave: '0..10.10.10.'},
+  {name: 'S_AXI_RVALID',  wave: 'x0..10.10.10'},
+  {name: 'S_AXI_RRESP',   wave: 'x...2.......', data: ['2b11']},
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbaxi-bridge-rresp-fail.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbaxi-bridge-rresp-fail.png
new file mode 100644
index 0000000..cb916b4
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbaxi-bridge-rresp-fail.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbaxi-bridge-rresp-fail.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbaxi-bridge-rresp-fail.svg
new file mode 100644
index 0000000..3642876
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbaxi-bridge-rresp-fail.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="390" width="640" viewBox="0 0 640 390" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s7{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{fill:#000;fill-opacity:1;stroke:none}.s10{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{fill:#0041c4;fill-opacity:1;stroke:none}.s12{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s6"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s6"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s6"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s6"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s6"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s6"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s6"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s6"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s9"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s9"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s6"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s6"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s11"/><path d="M0,0 -15,0" class="s12"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(140.5, 0.5)"><g id="gmarks_0"><path id="gmark_0_0" d="m 0,0 0,390" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_1_0" d="m 40,0 0,390" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_2_0" d="m 80,0 0,390" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_3_0" d="m 120,0 0,390" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_4_0" d="m 160,0 0,390" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_5_0" d="m 200,0 0,390" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_6_0" d="m 240,0 0,390" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_7_0" d="m 280,0 0,390" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_8_0" d="m 320,0 0,390" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_9_0" d="m 360,0 0,390" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_10_0" d="m 400,0 0,390" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_11_0" d="m 440,0 0,390" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/><path id="gmark_12_0" d="m 480,0 0,390" style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"/></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#Pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#Pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#Pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#Pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#Pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/><use xlink:href="#Pclk" transform="translate(200)"/><use xlink:href="#nclk" transform="translate(220)"/><use xlink:href="#Pclk" transform="translate(240)"/><use xlink:href="#nclk" transform="translate(260)"/><use xlink:href="#Pclk" transform="translate(280)"/><use xlink:href="#nclk" transform="translate(300)"/><use xlink:href="#Pclk" transform="translate(320)"/><use xlink:href="#nclk" transform="translate(340)"/><use xlink:href="#Pclk" transform="translate(360)"/><use xlink:href="#nclk" transform="translate(380)"/><use xlink:href="#Pclk" transform="translate(400)"/><use xlink:href="#nclk" transform="translate(420)"/><use xlink:href="#Pclk" transform="translate(440)"/><use xlink:href="#nclk" transform="translate(460)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"/></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>WB_CYC</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>WB_STB</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1m0" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#0m1" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#1m0" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#0m1" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#1m0" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>WB_WE</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xm0" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0mx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xxx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xm0" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0mx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xxx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xm0" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#0mx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xxx" transform="translate(400)"/><use xlink:href="#xxx" transform="translate(420)"/><use xlink:href="#xxx" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>WB_STALL</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xm0" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0mx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xmx" transform="translate(160)"/><use xlink:href="#xxx" transform="translate(180)"/><use xlink:href="#xm0" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0mx" transform="translate(240)"/><use xlink:href="#xxx" transform="translate(260)"/><use xlink:href="#xmx" transform="translate(280)"/><use xlink:href="#xxx" transform="translate(300)"/><use xlink:href="#xm0" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#0mx" transform="translate(360)"/><use xlink:href="#xxx" transform="translate(380)"/><use xlink:href="#xmx" transform="translate(400)"/><use xlink:href="#xxx" transform="translate(420)"/><use xlink:href="#xxx" transform="translate(440)"/><use xlink:href="#xxx" transform="translate(460)"/></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>WB_ACK</tspan></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/></g></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>WB_ERR</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"/></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_ARVALID</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#0m1" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#1m0" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0m1" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#1m0" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#0m1" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#1m0" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RVALID</tspan></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xm0" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#0m1" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#1m0" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#0m1" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#1m0" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#0m1" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#1m0" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/></g></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>S_AXI_RRESP</tspan></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xxx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xmv-2" transform="translate(160)"/><use xlink:href="#vvv-2" transform="translate(180)"/><use xlink:href="#vvv-2" transform="translate(200)"/><use xlink:href="#vvv-2" transform="translate(220)"/><use xlink:href="#vvv-2" transform="translate(240)"/><use xlink:href="#vvv-2" transform="translate(260)"/><use xlink:href="#vvv-2" transform="translate(280)"/><use xlink:href="#vvv-2" transform="translate(300)"/><use xlink:href="#vvv-2" transform="translate(320)"/><use xlink:href="#vvv-2" transform="translate(340)"/><use xlink:href="#vvv-2" transform="translate(360)"/><use xlink:href="#vvv-2" transform="translate(380)"/><use xlink:href="#vvv-2" transform="translate(400)"/><use xlink:href="#vvv-2" transform="translate(420)"/><use xlink:href="#vvv-2" transform="translate(440)"/><use xlink:href="#vvv-2" transform="translate(460)"/><text x="326" y="15" text-anchor="middle" xml:space="preserve"><tspan>2b11</tspan></text></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/></g></g><g id="groups_0">g</g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbxclk-annotated.dia b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbxclk-annotated.dia
new file mode 100644
index 0000000..e1609a7
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbxclk-annotated.dia
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbxclk-annotated.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbxclk-annotated.png
new file mode 100644
index 0000000..715b889
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbxclk-annotated.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbxclk.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbxclk.json
new file mode 100644
index 0000000..01a78e0
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbxclk.json
@@ -0,0 +1,15 @@
+{signal: [
+  {name: 'i_reset',   wave: '1.0....................................................'},
+  {name: 'i_wb_clk',  wave: '0.1010101.0101010.1010101.0101010.1010101.0101010.10101'},
+  {name: 'i_wb_cyc',  wave: '0.....1.............................................0..'},
+  {name: 'i_wb_stb',  wave: '0.....1.1..1.1.1..1.0.1.0..1.1.1..0....................'},
+  {name: 'i_wb_addr', wave: '0.....3.4..5.6.7..8.0.9.0..3.4.5..0....................', data: ['A0','A1','A2','A3','A4','A5','A6','A7','A8','A9']},
+  {name: 'o_wb_ack',  wave: '0..........................1.1.1..1.0.1.1..1.1.1..1.0..'},
+  {name: 'o_wb_data', wave: '0..........................3.4.5..6.0.7.8..9.3.4..5.0..', data: ['D0','D1','D2','D3','D4','D5','D6','D7','D8','D9']},
+  {},
+  {name: 'i_xclk_clk',wave: '0.101.010.101.010.101.010.101.010.101.010.101.010.101.0'},
+  {name: 'o_xclk_cyc',wave: '0.................1....................................'},
+  {name: 'o_xclk_stb',wave: '0.................1.1..1..1.1..1..1.1..1..1.0..0..0.0..', data: ['D0','D1','D2','D3','d1','d2','d3','d4']},
+  {name: 'i_xclk_ack',wave: '0.................1.1..1..1.1..1..1.1..1..1.0..0..0.0..', data: ['D0','D1','D2','D3','d1','d2','d3','d4']},
+  {name: 'i_xclk_data',wave:'0.................3.4..5..6.7..8..9.3..4..5.0..0..0.0..', data: ['D0','D1','D2','D3','D4','D5','D6','D7','D8','D9']}
+]}
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbxclk.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbxclk.png
new file mode 100644
index 0000000..7db6b28
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbxclk.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbxclk.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbxclk.svg
new file mode 100644
index 0000000..618f634
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/wbxclk.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="390" width="2320" viewBox="0 0 2320 390" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{fill:#000;fill-opacity:1;stroke:none}.s7{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s10{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{color:#000;fill:#ccfdfe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s12{color:#000;fill:#cdfdc5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s13{color:#000;fill:#f0c1fb;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s14{color:#000;fill:#f5c2c0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s15{fill:#0041c4;fill-opacity:1;stroke:none}.s16{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s6"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s6"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s9"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s9"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s9"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s9"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s9"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s9"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-6"><path d="M2.875,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-6"><path d="M3,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-6"><path d="M20,20 0,20 0,0 20,0" class="s11"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-6"><path d="M0,20 0,0 3,0 9,20" class="s11"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-6"><path d="M0,0 0,20 3,20 9,0" class="s11"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-6"><path d="M0,0 0,20 3,20 6,10 3,0" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-6"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s11"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-6"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s11"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-6"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s11"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-7"><path d="M2.875,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-7"><path d="M3,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-7"><path d="M20,20 0,20 0,0 20,0" class="s12"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-7"><path d="M0,20 0,0 3,0 9,20" class="s12"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-7"><path d="M0,0 0,20 3,20 9,0" class="s12"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-7"><path d="M0,0 0,20 3,20 6,10 3,0" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-7"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s12"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-7"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s12"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-7"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s12"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-8"><path d="M2.875,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-8"><path d="M3,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-8"><path d="M20,20 0,20 0,0 20,0" class="s13"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-8"><path d="M0,20 0,0 3,0 9,20" class="s13"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-8"><path d="M0,0 0,20 3,20 9,0" class="s13"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-8"><path d="M0,0 0,20 3,20 6,10 3,0" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-8"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s13"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-8"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s13"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-8"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s13"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-9"><path d="M2.875,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-9"><path d="M3,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-9"><path d="M20,20 0,20 0,0 20,0" class="s14"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-9"><path d="M0,20 0,0 3,0 9,20" class="s14"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-9"><path d="M0,0 0,20 3,20 9,0" class="s14"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-9"><path d="M0,0 0,20 3,20 6,10 3,0" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-9"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s14"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-9"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s14"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-9"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s14"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s15"/><path d="M0,0 -15,0" class="s16"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(100.5, 0.5)"><g id="gmarks_0"><g style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"><line id="gmark_0_0" x1="0" y1="0" x2="0" y2="390"/><line id="gmark_1_0" x1="40" y1="0" x2="40" y2="390"/><line id="gmark_2_0" x1="80" y1="0" x2="80" y2="390"/><line id="gmark_3_0" x1="120" y1="0" x2="120" y2="390"/><line id="gmark_4_0" x1="160" y1="0" x2="160" y2="390"/><line id="gmark_5_0" x1="200" y1="0" x2="200" y2="390"/><line id="gmark_6_0" x1="240" y1="0" x2="240" y2="390"/><line id="gmark_7_0" x1="280" y1="0" x2="280" y2="390"/><line id="gmark_8_0" x1="320" y1="0" x2="320" y2="390"/><line id="gmark_9_0" x1="360" y1="0" x2="360" y2="390"/><line id="gmark_10_0" x1="400" y1="0" x2="400" y2="390"/><line id="gmark_11_0" x1="440" y1="0" x2="440" y2="390"/><line id="gmark_12_0" x1="480" y1="0" x2="480" y2="390"/><line id="gmark_13_0" x1="520" y1="0" x2="520" y2="390"/><line id="gmark_14_0" x1="560" y1="0" x2="560" y2="390"/><line id="gmark_15_0" x1="600" y1="0" x2="600" y2="390"/><line id="gmark_16_0" x1="640" y1="0" x2="640" y2="390"/><line id="gmark_17_0" x1="680" y1="0" x2="680" y2="390"/><line id="gmark_18_0" x1="720" y1="0" x2="720" y2="390"/><line id="gmark_19_0" x1="760" y1="0" x2="760" y2="390"/><line id="gmark_20_0" x1="800" y1="0" x2="800" y2="390"/><line id="gmark_21_0" x1="840" y1="0" x2="840" y2="390"/><line id="gmark_22_0" x1="880" y1="0" x2="880" y2="390"/><line id="gmark_23_0" x1="920" y1="0" x2="920" y2="390"/><line id="gmark_24_0" x1="960" y1="0" x2="960" y2="390"/><line id="gmark_25_0" x1="1000" y1="0" x2="1000" y2="390"/><line id="gmark_26_0" x1="1040" y1="0" x2="1040" y2="390"/><line id="gmark_27_0" x1="1080" y1="0" x2="1080" y2="390"/><line id="gmark_28_0" x1="1120" y1="0" x2="1120" y2="390"/><line id="gmark_29_0" x1="1160" y1="0" x2="1160" y2="390"/><line id="gmark_30_0" x1="1200" y1="0" x2="1200" y2="390"/><line id="gmark_31_0" x1="1240" y1="0" x2="1240" y2="390"/><line id="gmark_32_0" x1="1280" y1="0" x2="1280" y2="390"/><line id="gmark_33_0" x1="1320" y1="0" x2="1320" y2="390"/><line id="gmark_34_0" x1="1360" y1="0" x2="1360" y2="390"/><line id="gmark_35_0" x1="1400" y1="0" x2="1400" y2="390"/><line id="gmark_36_0" x1="1440" y1="0" x2="1440" y2="390"/><line id="gmark_37_0" x1="1480" y1="0" x2="1480" y2="390"/><line id="gmark_38_0" x1="1520" y1="0" x2="1520" y2="390"/><line id="gmark_39_0" x1="1560" y1="0" x2="1560" y2="390"/><line id="gmark_40_0" x1="1600" y1="0" x2="1600" y2="390"/><line id="gmark_41_0" x1="1640" y1="0" x2="1640" y2="390"/><line id="gmark_42_0" x1="1680" y1="0" x2="1680" y2="390"/><line id="gmark_43_0" x1="1720" y1="0" x2="1720" y2="390"/><line id="gmark_44_0" x1="1760" y1="0" x2="1760" y2="390"/><line id="gmark_45_0" x1="1800" y1="0" x2="1800" y2="390"/><line id="gmark_46_0" x1="1840" y1="0" x2="1840" y2="390"/><line id="gmark_47_0" x1="1880" y1="0" x2="1880" y2="390"/><line id="gmark_48_0" x1="1920" y1="0" x2="1920" y2="390"/><line id="gmark_49_0" x1="1960" y1="0" x2="1960" y2="390"/><line id="gmark_50_0" x1="2000" y1="0" x2="2000" y2="390"/><line id="gmark_51_0" x1="2040" y1="0" x2="2040" y2="390"/><line id="gmark_52_0" x1="2080" y1="0" x2="2080" y2="390"/><line id="gmark_53_0" x1="2120" y1="0" x2="2120" y2="390"/><line id="gmark_54_0" x1="2160" y1="0" x2="2160" y2="390"/><line id="gmark_55_0" x1="2200" y1="0" x2="2200" y2="390"/></g></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>i_reset</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#111" transform="translate(0)"/><use xlink:href="#111" transform="translate(20)"/><use xlink:href="#111" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#1m0" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#000" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#000" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#000" transform="translate(1160)"/><use xlink:href="#000" transform="translate(1180)"/><use xlink:href="#000" transform="translate(1200)"/><use xlink:href="#000" transform="translate(1220)"/><use xlink:href="#000" transform="translate(1240)"/><use xlink:href="#000" transform="translate(1260)"/><use xlink:href="#000" transform="translate(1280)"/><use xlink:href="#000" transform="translate(1300)"/><use xlink:href="#000" transform="translate(1320)"/><use xlink:href="#000" transform="translate(1340)"/><use xlink:href="#000" transform="translate(1360)"/><use xlink:href="#000" transform="translate(1380)"/><use xlink:href="#000" transform="translate(1400)"/><use xlink:href="#000" transform="translate(1420)"/><use xlink:href="#000" transform="translate(1440)"/><use xlink:href="#000" transform="translate(1460)"/><use xlink:href="#000" transform="translate(1480)"/><use xlink:href="#000" transform="translate(1500)"/><use xlink:href="#000" transform="translate(1520)"/><use xlink:href="#000" transform="translate(1540)"/><use xlink:href="#000" transform="translate(1560)"/><use xlink:href="#000" transform="translate(1580)"/><use xlink:href="#000" transform="translate(1600)"/><use xlink:href="#000" transform="translate(1620)"/><use xlink:href="#000" transform="translate(1640)"/><use xlink:href="#000" transform="translate(1660)"/><use xlink:href="#000" transform="translate(1680)"/><use xlink:href="#000" transform="translate(1700)"/><use xlink:href="#000" transform="translate(1720)"/><use xlink:href="#000" transform="translate(1740)"/><use xlink:href="#000" transform="translate(1760)"/><use xlink:href="#000" transform="translate(1780)"/><use xlink:href="#000" transform="translate(1800)"/><use xlink:href="#000" transform="translate(1820)"/><use xlink:href="#000" transform="translate(1840)"/><use xlink:href="#000" transform="translate(1860)"/><use xlink:href="#000" transform="translate(1880)"/><use xlink:href="#000" transform="translate(1900)"/><use xlink:href="#000" transform="translate(1920)"/><use xlink:href="#000" transform="translate(1940)"/><use xlink:href="#000" transform="translate(1960)"/><use xlink:href="#000" transform="translate(1980)"/><use xlink:href="#000" transform="translate(2000)"/><use xlink:href="#000" transform="translate(2020)"/><use xlink:href="#000" transform="translate(2040)"/><use xlink:href="#000" transform="translate(2060)"/><use xlink:href="#000" transform="translate(2080)"/><use xlink:href="#000" transform="translate(2100)"/><use xlink:href="#000" transform="translate(2120)"/><use xlink:href="#000" transform="translate(2140)"/><use xlink:href="#000" transform="translate(2160)"/><use xlink:href="#000" transform="translate(2180)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>i_wb_clk</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1m0" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#0m1" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#1m0" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0m1" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#1m0" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#0m1" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#1m0" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#0m1" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#1m0" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#0m1" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#1m0" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#0m1" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#1m0" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#0m1" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#1m0" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#0m1" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#1m0" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#0m1" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#1m0" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#0m1" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#111" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#1m0" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#0m1" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#1m0" transform="translate(1120)"/><use xlink:href="#000" transform="translate(1140)"/><use xlink:href="#0m1" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#1m0" transform="translate(1200)"/><use xlink:href="#000" transform="translate(1220)"/><use xlink:href="#0m1" transform="translate(1240)"/><use xlink:href="#111" transform="translate(1260)"/><use xlink:href="#1m0" transform="translate(1280)"/><use xlink:href="#000" transform="translate(1300)"/><use xlink:href="#000" transform="translate(1320)"/><use xlink:href="#000" transform="translate(1340)"/><use xlink:href="#0m1" transform="translate(1360)"/><use xlink:href="#111" transform="translate(1380)"/><use xlink:href="#1m0" transform="translate(1400)"/><use xlink:href="#000" transform="translate(1420)"/><use xlink:href="#0m1" transform="translate(1440)"/><use xlink:href="#111" transform="translate(1460)"/><use xlink:href="#1m0" transform="translate(1480)"/><use xlink:href="#000" transform="translate(1500)"/><use xlink:href="#0m1" transform="translate(1520)"/><use xlink:href="#111" transform="translate(1540)"/><use xlink:href="#1m0" transform="translate(1560)"/><use xlink:href="#000" transform="translate(1580)"/><use xlink:href="#0m1" transform="translate(1600)"/><use xlink:href="#111" transform="translate(1620)"/><use xlink:href="#111" transform="translate(1640)"/><use xlink:href="#111" transform="translate(1660)"/><use xlink:href="#1m0" transform="translate(1680)"/><use xlink:href="#000" transform="translate(1700)"/><use xlink:href="#0m1" transform="translate(1720)"/><use xlink:href="#111" transform="translate(1740)"/><use xlink:href="#1m0" transform="translate(1760)"/><use xlink:href="#000" transform="translate(1780)"/><use xlink:href="#0m1" transform="translate(1800)"/><use xlink:href="#111" transform="translate(1820)"/><use xlink:href="#1m0" transform="translate(1840)"/><use xlink:href="#000" transform="translate(1860)"/><use xlink:href="#0m1" transform="translate(1880)"/><use xlink:href="#111" transform="translate(1900)"/><use xlink:href="#1m0" transform="translate(1920)"/><use xlink:href="#000" transform="translate(1940)"/><use xlink:href="#000" transform="translate(1960)"/><use xlink:href="#000" transform="translate(1980)"/><use xlink:href="#0m1" transform="translate(2000)"/><use xlink:href="#111" transform="translate(2020)"/><use xlink:href="#1m0" transform="translate(2040)"/><use xlink:href="#000" transform="translate(2060)"/><use xlink:href="#0m1" transform="translate(2080)"/><use xlink:href="#111" transform="translate(2100)"/><use xlink:href="#1m0" transform="translate(2120)"/><use xlink:href="#000" transform="translate(2140)"/><use xlink:href="#0m1" transform="translate(2160)"/><use xlink:href="#111" transform="translate(2180)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>i_wb_cyc</tspan></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0m1" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#111" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#111" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#111" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#111" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#111" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#111" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#111" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#111" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#111" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#111" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#111" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#111" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#111" transform="translate(1200)"/><use xlink:href="#111" transform="translate(1220)"/><use xlink:href="#111" transform="translate(1240)"/><use xlink:href="#111" transform="translate(1260)"/><use xlink:href="#111" transform="translate(1280)"/><use xlink:href="#111" transform="translate(1300)"/><use xlink:href="#111" transform="translate(1320)"/><use xlink:href="#111" transform="translate(1340)"/><use xlink:href="#111" transform="translate(1360)"/><use xlink:href="#111" transform="translate(1380)"/><use xlink:href="#111" transform="translate(1400)"/><use xlink:href="#111" transform="translate(1420)"/><use xlink:href="#111" transform="translate(1440)"/><use xlink:href="#111" transform="translate(1460)"/><use xlink:href="#111" transform="translate(1480)"/><use xlink:href="#111" transform="translate(1500)"/><use xlink:href="#111" transform="translate(1520)"/><use xlink:href="#111" transform="translate(1540)"/><use xlink:href="#111" transform="translate(1560)"/><use xlink:href="#111" transform="translate(1580)"/><use xlink:href="#111" transform="translate(1600)"/><use xlink:href="#111" transform="translate(1620)"/><use xlink:href="#111" transform="translate(1640)"/><use xlink:href="#111" transform="translate(1660)"/><use xlink:href="#111" transform="translate(1680)"/><use xlink:href="#111" transform="translate(1700)"/><use xlink:href="#111" transform="translate(1720)"/><use xlink:href="#111" transform="translate(1740)"/><use xlink:href="#111" transform="translate(1760)"/><use xlink:href="#111" transform="translate(1780)"/><use xlink:href="#111" transform="translate(1800)"/><use xlink:href="#111" transform="translate(1820)"/><use xlink:href="#111" transform="translate(1840)"/><use xlink:href="#111" transform="translate(1860)"/><use xlink:href="#111" transform="translate(1880)"/><use xlink:href="#111" transform="translate(1900)"/><use xlink:href="#111" transform="translate(1920)"/><use xlink:href="#111" transform="translate(1940)"/><use xlink:href="#111" transform="translate(1960)"/><use xlink:href="#111" transform="translate(1980)"/><use xlink:href="#111" transform="translate(2000)"/><use xlink:href="#111" transform="translate(2020)"/><use xlink:href="#111" transform="translate(2040)"/><use xlink:href="#111" transform="translate(2060)"/><use xlink:href="#1m0" transform="translate(2080)"/><use xlink:href="#000" transform="translate(2100)"/><use xlink:href="#000" transform="translate(2120)"/><use xlink:href="#000" transform="translate(2140)"/><use xlink:href="#000" transform="translate(2160)"/><use xlink:href="#000" transform="translate(2180)"/></g></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>i_wb_stb</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0m1" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#1m1" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#1m1" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#1m1" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#111" transform="translate(560)"/><use xlink:href="#111" transform="translate(580)"/><use xlink:href="#1m1" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#111" transform="translate(640)"/><use xlink:href="#111" transform="translate(660)"/><use xlink:href="#111" transform="translate(680)"/><use xlink:href="#111" transform="translate(700)"/><use xlink:href="#1m1" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#1m0" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#0m1" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#111" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#1m0" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#0m1" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#111" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#1m1" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#111" transform="translate(1200)"/><use xlink:href="#111" transform="translate(1220)"/><use xlink:href="#1m1" transform="translate(1240)"/><use xlink:href="#111" transform="translate(1260)"/><use xlink:href="#111" transform="translate(1280)"/><use xlink:href="#111" transform="translate(1300)"/><use xlink:href="#111" transform="translate(1320)"/><use xlink:href="#111" transform="translate(1340)"/><use xlink:href="#1m0" transform="translate(1360)"/><use xlink:href="#000" transform="translate(1380)"/><use xlink:href="#000" transform="translate(1400)"/><use xlink:href="#000" transform="translate(1420)"/><use xlink:href="#000" transform="translate(1440)"/><use xlink:href="#000" transform="translate(1460)"/><use xlink:href="#000" transform="translate(1480)"/><use xlink:href="#000" transform="translate(1500)"/><use xlink:href="#000" transform="translate(1520)"/><use xlink:href="#000" transform="translate(1540)"/><use xlink:href="#000" transform="translate(1560)"/><use xlink:href="#000" transform="translate(1580)"/><use xlink:href="#000" transform="translate(1600)"/><use xlink:href="#000" transform="translate(1620)"/><use xlink:href="#000" transform="translate(1640)"/><use xlink:href="#000" transform="translate(1660)"/><use xlink:href="#000" transform="translate(1680)"/><use xlink:href="#000" transform="translate(1700)"/><use xlink:href="#000" transform="translate(1720)"/><use xlink:href="#000" transform="translate(1740)"/><use xlink:href="#000" transform="translate(1760)"/><use xlink:href="#000" transform="translate(1780)"/><use xlink:href="#000" transform="translate(1800)"/><use xlink:href="#000" transform="translate(1820)"/><use xlink:href="#000" transform="translate(1840)"/><use xlink:href="#000" transform="translate(1860)"/><use xlink:href="#000" transform="translate(1880)"/><use xlink:href="#000" transform="translate(1900)"/><use xlink:href="#000" transform="translate(1920)"/><use xlink:href="#000" transform="translate(1940)"/><use xlink:href="#000" transform="translate(1960)"/><use xlink:href="#000" transform="translate(1980)"/><use xlink:href="#000" transform="translate(2000)"/><use xlink:href="#000" transform="translate(2020)"/><use xlink:href="#000" transform="translate(2040)"/><use xlink:href="#000" transform="translate(2060)"/><use xlink:href="#000" transform="translate(2080)"/><use xlink:href="#000" transform="translate(2100)"/><use xlink:href="#000" transform="translate(2120)"/><use xlink:href="#000" transform="translate(2140)"/><use xlink:href="#000" transform="translate(2160)"/><use xlink:href="#000" transform="translate(2180)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>i_wb_addr</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#0mv-3" transform="translate(240)"/><use xlink:href="#vvv-3" transform="translate(260)"/><use xlink:href="#vvv-3" transform="translate(280)"/><use xlink:href="#vvv-3" transform="translate(300)"/><use xlink:href="#vmv-3-4" transform="translate(320)"/><use xlink:href="#vvv-4" transform="translate(340)"/><use xlink:href="#vvv-4" transform="translate(360)"/><use xlink:href="#vvv-4" transform="translate(380)"/><use xlink:href="#vvv-4" transform="translate(400)"/><use xlink:href="#vvv-4" transform="translate(420)"/><use xlink:href="#vmv-4-5" transform="translate(440)"/><use xlink:href="#vvv-5" transform="translate(460)"/><use xlink:href="#vvv-5" transform="translate(480)"/><use xlink:href="#vvv-5" transform="translate(500)"/><use xlink:href="#vmv-5-6" transform="translate(520)"/><use xlink:href="#vvv-6" transform="translate(540)"/><use xlink:href="#vvv-6" transform="translate(560)"/><use xlink:href="#vvv-6" transform="translate(580)"/><use xlink:href="#vmv-6-7" transform="translate(600)"/><use xlink:href="#vvv-7" transform="translate(620)"/><use xlink:href="#vvv-7" transform="translate(640)"/><use xlink:href="#vvv-7" transform="translate(660)"/><use xlink:href="#vvv-7" transform="translate(680)"/><use xlink:href="#vvv-7" transform="translate(700)"/><use xlink:href="#vmv-7-8" transform="translate(720)"/><use xlink:href="#vvv-8" transform="translate(740)"/><use xlink:href="#vvv-8" transform="translate(760)"/><use xlink:href="#vvv-8" transform="translate(780)"/><use xlink:href="#vm0-8" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#0mv-9" transform="translate(880)"/><use xlink:href="#vvv-9" transform="translate(900)"/><use xlink:href="#vvv-9" transform="translate(920)"/><use xlink:href="#vvv-9" transform="translate(940)"/><use xlink:href="#vm0-9" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#0mv-3" transform="translate(1080)"/><use xlink:href="#vvv-3" transform="translate(1100)"/><use xlink:href="#vvv-3" transform="translate(1120)"/><use xlink:href="#vvv-3" transform="translate(1140)"/><use xlink:href="#vmv-3-4" transform="translate(1160)"/><use xlink:href="#vvv-4" transform="translate(1180)"/><use xlink:href="#vvv-4" transform="translate(1200)"/><use xlink:href="#vvv-4" transform="translate(1220)"/><use xlink:href="#vmv-4-5" transform="translate(1240)"/><use xlink:href="#vvv-5" transform="translate(1260)"/><use xlink:href="#vvv-5" transform="translate(1280)"/><use xlink:href="#vvv-5" transform="translate(1300)"/><use xlink:href="#vvv-5" transform="translate(1320)"/><use xlink:href="#vvv-5" transform="translate(1340)"/><use xlink:href="#vm0-5" transform="translate(1360)"/><use xlink:href="#000" transform="translate(1380)"/><use xlink:href="#000" transform="translate(1400)"/><use xlink:href="#000" transform="translate(1420)"/><use xlink:href="#000" transform="translate(1440)"/><use xlink:href="#000" transform="translate(1460)"/><use xlink:href="#000" transform="translate(1480)"/><use xlink:href="#000" transform="translate(1500)"/><use xlink:href="#000" transform="translate(1520)"/><use xlink:href="#000" transform="translate(1540)"/><use xlink:href="#000" transform="translate(1560)"/><use xlink:href="#000" transform="translate(1580)"/><use xlink:href="#000" transform="translate(1600)"/><use xlink:href="#000" transform="translate(1620)"/><use xlink:href="#000" transform="translate(1640)"/><use xlink:href="#000" transform="translate(1660)"/><use xlink:href="#000" transform="translate(1680)"/><use xlink:href="#000" transform="translate(1700)"/><use xlink:href="#000" transform="translate(1720)"/><use xlink:href="#000" transform="translate(1740)"/><use xlink:href="#000" transform="translate(1760)"/><use xlink:href="#000" transform="translate(1780)"/><use xlink:href="#000" transform="translate(1800)"/><use xlink:href="#000" transform="translate(1820)"/><use xlink:href="#000" transform="translate(1840)"/><use xlink:href="#000" transform="translate(1860)"/><use xlink:href="#000" transform="translate(1880)"/><use xlink:href="#000" transform="translate(1900)"/><use xlink:href="#000" transform="translate(1920)"/><use xlink:href="#000" transform="translate(1940)"/><use xlink:href="#000" transform="translate(1960)"/><use xlink:href="#000" transform="translate(1980)"/><use xlink:href="#000" transform="translate(2000)"/><use xlink:href="#000" transform="translate(2020)"/><use xlink:href="#000" transform="translate(2040)"/><use xlink:href="#000" transform="translate(2060)"/><use xlink:href="#000" transform="translate(2080)"/><use xlink:href="#000" transform="translate(2100)"/><use xlink:href="#000" transform="translate(2120)"/><use xlink:href="#000" transform="translate(2140)"/><use xlink:href="#000" transform="translate(2160)"/><use xlink:href="#000" transform="translate(2180)"/><text x="286" y="15" text-anchor="middle" xml:space="preserve"><tspan>A0</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>A1</tspan></text><text x="486" y="15" text-anchor="middle" xml:space="preserve"><tspan>A2</tspan></text><text x="566" y="15" text-anchor="middle" xml:space="preserve"><tspan>A3</tspan></text><text x="666" y="15" text-anchor="middle" xml:space="preserve"><tspan>A4</tspan></text><text x="766" y="15" text-anchor="middle" xml:space="preserve"><tspan>A5</tspan></text><text x="926" y="15" text-anchor="middle" xml:space="preserve"><tspan>A6</tspan></text><text x="1126" y="15" text-anchor="middle" xml:space="preserve"><tspan>A7</tspan></text><text x="1206" y="15" text-anchor="middle" xml:space="preserve"><tspan>A8</tspan></text><text x="1306" y="15" text-anchor="middle" xml:space="preserve"><tspan>A9</tspan></text></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>o_wb_ack</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#0m1" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#111" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#1m1" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#111" transform="translate(1200)"/><use xlink:href="#111" transform="translate(1220)"/><use xlink:href="#1m1" transform="translate(1240)"/><use xlink:href="#111" transform="translate(1260)"/><use xlink:href="#111" transform="translate(1280)"/><use xlink:href="#111" transform="translate(1300)"/><use xlink:href="#111" transform="translate(1320)"/><use xlink:href="#111" transform="translate(1340)"/><use xlink:href="#1m1" transform="translate(1360)"/><use xlink:href="#111" transform="translate(1380)"/><use xlink:href="#111" transform="translate(1400)"/><use xlink:href="#111" transform="translate(1420)"/><use xlink:href="#1m0" transform="translate(1440)"/><use xlink:href="#000" transform="translate(1460)"/><use xlink:href="#000" transform="translate(1480)"/><use xlink:href="#000" transform="translate(1500)"/><use xlink:href="#0m1" transform="translate(1520)"/><use xlink:href="#111" transform="translate(1540)"/><use xlink:href="#111" transform="translate(1560)"/><use xlink:href="#111" transform="translate(1580)"/><use xlink:href="#1m1" transform="translate(1600)"/><use xlink:href="#111" transform="translate(1620)"/><use xlink:href="#111" transform="translate(1640)"/><use xlink:href="#111" transform="translate(1660)"/><use xlink:href="#111" transform="translate(1680)"/><use xlink:href="#111" transform="translate(1700)"/><use xlink:href="#1m1" transform="translate(1720)"/><use xlink:href="#111" transform="translate(1740)"/><use xlink:href="#111" transform="translate(1760)"/><use xlink:href="#111" transform="translate(1780)"/><use xlink:href="#1m1" transform="translate(1800)"/><use xlink:href="#111" transform="translate(1820)"/><use xlink:href="#111" transform="translate(1840)"/><use xlink:href="#111" transform="translate(1860)"/><use xlink:href="#1m1" transform="translate(1880)"/><use xlink:href="#111" transform="translate(1900)"/><use xlink:href="#111" transform="translate(1920)"/><use xlink:href="#111" transform="translate(1940)"/><use xlink:href="#111" transform="translate(1960)"/><use xlink:href="#111" transform="translate(1980)"/><use xlink:href="#1m1" transform="translate(2000)"/><use xlink:href="#111" transform="translate(2020)"/><use xlink:href="#111" transform="translate(2040)"/><use xlink:href="#111" transform="translate(2060)"/><use xlink:href="#1m0" transform="translate(2080)"/><use xlink:href="#000" transform="translate(2100)"/><use xlink:href="#000" transform="translate(2120)"/><use xlink:href="#000" transform="translate(2140)"/><use xlink:href="#000" transform="translate(2160)"/><use xlink:href="#000" transform="translate(2180)"/></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>o_wb_data</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#000" transform="translate(720)"/><use xlink:href="#000" transform="translate(740)"/><use xlink:href="#000" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#000" transform="translate(800)"/><use xlink:href="#000" transform="translate(820)"/><use xlink:href="#000" transform="translate(840)"/><use xlink:href="#000" transform="translate(860)"/><use xlink:href="#000" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#000" transform="translate(920)"/><use xlink:href="#000" transform="translate(940)"/><use xlink:href="#000" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#000" transform="translate(1040)"/><use xlink:href="#000" transform="translate(1060)"/><use xlink:href="#0mv-3" transform="translate(1080)"/><use xlink:href="#vvv-3" transform="translate(1100)"/><use xlink:href="#vvv-3" transform="translate(1120)"/><use xlink:href="#vvv-3" transform="translate(1140)"/><use xlink:href="#vmv-3-4" transform="translate(1160)"/><use xlink:href="#vvv-4" transform="translate(1180)"/><use xlink:href="#vvv-4" transform="translate(1200)"/><use xlink:href="#vvv-4" transform="translate(1220)"/><use xlink:href="#vmv-4-5" transform="translate(1240)"/><use xlink:href="#vvv-5" transform="translate(1260)"/><use xlink:href="#vvv-5" transform="translate(1280)"/><use xlink:href="#vvv-5" transform="translate(1300)"/><use xlink:href="#vvv-5" transform="translate(1320)"/><use xlink:href="#vvv-5" transform="translate(1340)"/><use xlink:href="#vmv-5-6" transform="translate(1360)"/><use xlink:href="#vvv-6" transform="translate(1380)"/><use xlink:href="#vvv-6" transform="translate(1400)"/><use xlink:href="#vvv-6" transform="translate(1420)"/><use xlink:href="#vm0-6" transform="translate(1440)"/><use xlink:href="#000" transform="translate(1460)"/><use xlink:href="#000" transform="translate(1480)"/><use xlink:href="#000" transform="translate(1500)"/><use xlink:href="#0mv-7" transform="translate(1520)"/><use xlink:href="#vvv-7" transform="translate(1540)"/><use xlink:href="#vvv-7" transform="translate(1560)"/><use xlink:href="#vvv-7" transform="translate(1580)"/><use xlink:href="#vmv-7-8" transform="translate(1600)"/><use xlink:href="#vvv-8" transform="translate(1620)"/><use xlink:href="#vvv-8" transform="translate(1640)"/><use xlink:href="#vvv-8" transform="translate(1660)"/><use xlink:href="#vvv-8" transform="translate(1680)"/><use xlink:href="#vvv-8" transform="translate(1700)"/><use xlink:href="#vmv-8-9" transform="translate(1720)"/><use xlink:href="#vvv-9" transform="translate(1740)"/><use xlink:href="#vvv-9" transform="translate(1760)"/><use xlink:href="#vvv-9" transform="translate(1780)"/><use xlink:href="#vmv-9-3" transform="translate(1800)"/><use xlink:href="#vvv-3" transform="translate(1820)"/><use xlink:href="#vvv-3" transform="translate(1840)"/><use xlink:href="#vvv-3" transform="translate(1860)"/><use xlink:href="#vmv-3-4" transform="translate(1880)"/><use xlink:href="#vvv-4" transform="translate(1900)"/><use xlink:href="#vvv-4" transform="translate(1920)"/><use xlink:href="#vvv-4" transform="translate(1940)"/><use xlink:href="#vvv-4" transform="translate(1960)"/><use xlink:href="#vvv-4" transform="translate(1980)"/><use xlink:href="#vmv-4-5" transform="translate(2000)"/><use xlink:href="#vvv-5" transform="translate(2020)"/><use xlink:href="#vvv-5" transform="translate(2040)"/><use xlink:href="#vvv-5" transform="translate(2060)"/><use xlink:href="#vm0-5" transform="translate(2080)"/><use xlink:href="#000" transform="translate(2100)"/><use xlink:href="#000" transform="translate(2120)"/><use xlink:href="#000" transform="translate(2140)"/><use xlink:href="#000" transform="translate(2160)"/><use xlink:href="#000" transform="translate(2180)"/><text x="1126" y="15" text-anchor="middle" xml:space="preserve"><tspan>D0</tspan></text><text x="1206" y="15" text-anchor="middle" xml:space="preserve"><tspan>D1</tspan></text><text x="1306" y="15" text-anchor="middle" xml:space="preserve"><tspan>D2</tspan></text><text x="1406" y="15" text-anchor="middle" xml:space="preserve"><tspan>D3</tspan></text><text x="1566" y="15" text-anchor="middle" xml:space="preserve"><tspan>D4</tspan></text><text x="1666" y="15" text-anchor="middle" xml:space="preserve"><tspan>D5</tspan></text><text x="1766" y="15" text-anchor="middle" xml:space="preserve"><tspan>D6</tspan></text><text x="1846" y="15" text-anchor="middle" xml:space="preserve"><tspan>D7</tspan></text><text x="1946" y="15" text-anchor="middle" xml:space="preserve"><tspan>D8</tspan></text><text x="2046" y="15" text-anchor="middle" xml:space="preserve"><tspan>D9</tspan></text></g></g><g id="wavelane_7_0" transform="translate(0,215)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_7_0" transform="translate(0, 0)"/></g><g id="wavelane_8_0" transform="translate(0,245)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>i_xclk_clk</tspan></text><g id="wavelane_draw_8_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#0m1" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#1m0" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#0m1" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#1m0" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#0m1" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#1m0" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#0m1" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#1m0" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#0m1" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/><use xlink:href="#111" transform="translate(520)"/><use xlink:href="#111" transform="translate(540)"/><use xlink:href="#1m0" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#0m1" transform="translate(600)"/><use xlink:href="#111" transform="translate(620)"/><use xlink:href="#1m0" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#0m1" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#1m0" transform="translate(760)"/><use xlink:href="#000" transform="translate(780)"/><use xlink:href="#0m1" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#111" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#1m0" transform="translate(880)"/><use xlink:href="#000" transform="translate(900)"/><use xlink:href="#0m1" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#1m0" transform="translate(960)"/><use xlink:href="#000" transform="translate(980)"/><use xlink:href="#000" transform="translate(1000)"/><use xlink:href="#000" transform="translate(1020)"/><use xlink:href="#0m1" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#1m0" transform="translate(1080)"/><use xlink:href="#000" transform="translate(1100)"/><use xlink:href="#0m1" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#111" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#1m0" transform="translate(1200)"/><use xlink:href="#000" transform="translate(1220)"/><use xlink:href="#0m1" transform="translate(1240)"/><use xlink:href="#111" transform="translate(1260)"/><use xlink:href="#1m0" transform="translate(1280)"/><use xlink:href="#000" transform="translate(1300)"/><use xlink:href="#000" transform="translate(1320)"/><use xlink:href="#000" transform="translate(1340)"/><use xlink:href="#0m1" transform="translate(1360)"/><use xlink:href="#111" transform="translate(1380)"/><use xlink:href="#1m0" transform="translate(1400)"/><use xlink:href="#000" transform="translate(1420)"/><use xlink:href="#0m1" transform="translate(1440)"/><use xlink:href="#111" transform="translate(1460)"/><use xlink:href="#111" transform="translate(1480)"/><use xlink:href="#111" transform="translate(1500)"/><use xlink:href="#1m0" transform="translate(1520)"/><use xlink:href="#000" transform="translate(1540)"/><use xlink:href="#0m1" transform="translate(1560)"/><use xlink:href="#111" transform="translate(1580)"/><use xlink:href="#1m0" transform="translate(1600)"/><use xlink:href="#000" transform="translate(1620)"/><use xlink:href="#000" transform="translate(1640)"/><use xlink:href="#000" transform="translate(1660)"/><use xlink:href="#0m1" transform="translate(1680)"/><use xlink:href="#111" transform="translate(1700)"/><use xlink:href="#1m0" transform="translate(1720)"/><use xlink:href="#000" transform="translate(1740)"/><use xlink:href="#0m1" transform="translate(1760)"/><use xlink:href="#111" transform="translate(1780)"/><use xlink:href="#111" transform="translate(1800)"/><use xlink:href="#111" transform="translate(1820)"/><use xlink:href="#1m0" transform="translate(1840)"/><use xlink:href="#000" transform="translate(1860)"/><use xlink:href="#0m1" transform="translate(1880)"/><use xlink:href="#111" transform="translate(1900)"/><use xlink:href="#1m0" transform="translate(1920)"/><use xlink:href="#000" transform="translate(1940)"/><use xlink:href="#000" transform="translate(1960)"/><use xlink:href="#000" transform="translate(1980)"/><use xlink:href="#0m1" transform="translate(2000)"/><use xlink:href="#111" transform="translate(2020)"/><use xlink:href="#1m0" transform="translate(2040)"/><use xlink:href="#000" transform="translate(2060)"/><use xlink:href="#0m1" transform="translate(2080)"/><use xlink:href="#111" transform="translate(2100)"/><use xlink:href="#111" transform="translate(2120)"/><use xlink:href="#111" transform="translate(2140)"/><use xlink:href="#1m0" transform="translate(2160)"/><use xlink:href="#000" transform="translate(2180)"/></g></g><g id="wavelane_9_0" transform="translate(0,275)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>o_xclk_cyc</tspan></text><g id="wavelane_draw_9_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#0m1" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#111" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#111" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#111" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#111" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#111" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#111" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#111" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#111" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#111" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#111" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#111" transform="translate(1200)"/><use xlink:href="#111" transform="translate(1220)"/><use xlink:href="#111" transform="translate(1240)"/><use xlink:href="#111" transform="translate(1260)"/><use xlink:href="#111" transform="translate(1280)"/><use xlink:href="#111" transform="translate(1300)"/><use xlink:href="#111" transform="translate(1320)"/><use xlink:href="#111" transform="translate(1340)"/><use xlink:href="#111" transform="translate(1360)"/><use xlink:href="#111" transform="translate(1380)"/><use xlink:href="#111" transform="translate(1400)"/><use xlink:href="#111" transform="translate(1420)"/><use xlink:href="#111" transform="translate(1440)"/><use xlink:href="#111" transform="translate(1460)"/><use xlink:href="#111" transform="translate(1480)"/><use xlink:href="#111" transform="translate(1500)"/><use xlink:href="#111" transform="translate(1520)"/><use xlink:href="#111" transform="translate(1540)"/><use xlink:href="#111" transform="translate(1560)"/><use xlink:href="#111" transform="translate(1580)"/><use xlink:href="#111" transform="translate(1600)"/><use xlink:href="#111" transform="translate(1620)"/><use xlink:href="#111" transform="translate(1640)"/><use xlink:href="#111" transform="translate(1660)"/><use xlink:href="#111" transform="translate(1680)"/><use xlink:href="#111" transform="translate(1700)"/><use xlink:href="#111" transform="translate(1720)"/><use xlink:href="#111" transform="translate(1740)"/><use xlink:href="#111" transform="translate(1760)"/><use xlink:href="#111" transform="translate(1780)"/><use xlink:href="#111" transform="translate(1800)"/><use xlink:href="#111" transform="translate(1820)"/><use xlink:href="#111" transform="translate(1840)"/><use xlink:href="#111" transform="translate(1860)"/><use xlink:href="#111" transform="translate(1880)"/><use xlink:href="#111" transform="translate(1900)"/><use xlink:href="#111" transform="translate(1920)"/><use xlink:href="#111" transform="translate(1940)"/><use xlink:href="#111" transform="translate(1960)"/><use xlink:href="#111" transform="translate(1980)"/><use xlink:href="#111" transform="translate(2000)"/><use xlink:href="#111" transform="translate(2020)"/><use xlink:href="#111" transform="translate(2040)"/><use xlink:href="#111" transform="translate(2060)"/><use xlink:href="#111" transform="translate(2080)"/><use xlink:href="#111" transform="translate(2100)"/><use xlink:href="#111" transform="translate(2120)"/><use xlink:href="#111" transform="translate(2140)"/><use xlink:href="#111" transform="translate(2160)"/><use xlink:href="#111" transform="translate(2180)"/></g></g><g id="wavelane_10_0" transform="translate(0,305)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>o_xclk_stb</tspan></text><g id="wavelane_draw_10_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#0m1" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#1m1" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#111" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#111" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#1m1" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#111" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#111" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#1m1" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#111" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#1m1" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#111" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#111" transform="translate(1200)"/><use xlink:href="#111" transform="translate(1220)"/><use xlink:href="#1m1" transform="translate(1240)"/><use xlink:href="#111" transform="translate(1260)"/><use xlink:href="#111" transform="translate(1280)"/><use xlink:href="#111" transform="translate(1300)"/><use xlink:href="#111" transform="translate(1320)"/><use xlink:href="#111" transform="translate(1340)"/><use xlink:href="#1m1" transform="translate(1360)"/><use xlink:href="#111" transform="translate(1380)"/><use xlink:href="#111" transform="translate(1400)"/><use xlink:href="#111" transform="translate(1420)"/><use xlink:href="#1m1" transform="translate(1440)"/><use xlink:href="#111" transform="translate(1460)"/><use xlink:href="#111" transform="translate(1480)"/><use xlink:href="#111" transform="translate(1500)"/><use xlink:href="#111" transform="translate(1520)"/><use xlink:href="#111" transform="translate(1540)"/><use xlink:href="#1m1" transform="translate(1560)"/><use xlink:href="#111" transform="translate(1580)"/><use xlink:href="#111" transform="translate(1600)"/><use xlink:href="#111" transform="translate(1620)"/><use xlink:href="#111" transform="translate(1640)"/><use xlink:href="#111" transform="translate(1660)"/><use xlink:href="#1m1" transform="translate(1680)"/><use xlink:href="#111" transform="translate(1700)"/><use xlink:href="#111" transform="translate(1720)"/><use xlink:href="#111" transform="translate(1740)"/><use xlink:href="#1m0" transform="translate(1760)"/><use xlink:href="#000" transform="translate(1780)"/><use xlink:href="#000" transform="translate(1800)"/><use xlink:href="#000" transform="translate(1820)"/><use xlink:href="#000" transform="translate(1840)"/><use xlink:href="#000" transform="translate(1860)"/><use xlink:href="#0m0" transform="translate(1880)"/><use xlink:href="#000" transform="translate(1900)"/><use xlink:href="#000" transform="translate(1920)"/><use xlink:href="#000" transform="translate(1940)"/><use xlink:href="#000" transform="translate(1960)"/><use xlink:href="#000" transform="translate(1980)"/><use xlink:href="#0m0" transform="translate(2000)"/><use xlink:href="#000" transform="translate(2020)"/><use xlink:href="#000" transform="translate(2040)"/><use xlink:href="#000" transform="translate(2060)"/><use xlink:href="#0m0" transform="translate(2080)"/><use xlink:href="#000" transform="translate(2100)"/><use xlink:href="#000" transform="translate(2120)"/><use xlink:href="#000" transform="translate(2140)"/><use xlink:href="#000" transform="translate(2160)"/><use xlink:href="#000" transform="translate(2180)"/></g></g><g id="wavelane_11_0" transform="translate(0,335)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>i_xclk_ack</tspan></text><g id="wavelane_draw_11_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#0m1" transform="translate(720)"/><use xlink:href="#111" transform="translate(740)"/><use xlink:href="#111" transform="translate(760)"/><use xlink:href="#111" transform="translate(780)"/><use xlink:href="#1m1" transform="translate(800)"/><use xlink:href="#111" transform="translate(820)"/><use xlink:href="#111" transform="translate(840)"/><use xlink:href="#111" transform="translate(860)"/><use xlink:href="#111" transform="translate(880)"/><use xlink:href="#111" transform="translate(900)"/><use xlink:href="#1m1" transform="translate(920)"/><use xlink:href="#111" transform="translate(940)"/><use xlink:href="#111" transform="translate(960)"/><use xlink:href="#111" transform="translate(980)"/><use xlink:href="#111" transform="translate(1000)"/><use xlink:href="#111" transform="translate(1020)"/><use xlink:href="#1m1" transform="translate(1040)"/><use xlink:href="#111" transform="translate(1060)"/><use xlink:href="#111" transform="translate(1080)"/><use xlink:href="#111" transform="translate(1100)"/><use xlink:href="#1m1" transform="translate(1120)"/><use xlink:href="#111" transform="translate(1140)"/><use xlink:href="#111" transform="translate(1160)"/><use xlink:href="#111" transform="translate(1180)"/><use xlink:href="#111" transform="translate(1200)"/><use xlink:href="#111" transform="translate(1220)"/><use xlink:href="#1m1" transform="translate(1240)"/><use xlink:href="#111" transform="translate(1260)"/><use xlink:href="#111" transform="translate(1280)"/><use xlink:href="#111" transform="translate(1300)"/><use xlink:href="#111" transform="translate(1320)"/><use xlink:href="#111" transform="translate(1340)"/><use xlink:href="#1m1" transform="translate(1360)"/><use xlink:href="#111" transform="translate(1380)"/><use xlink:href="#111" transform="translate(1400)"/><use xlink:href="#111" transform="translate(1420)"/><use xlink:href="#1m1" transform="translate(1440)"/><use xlink:href="#111" transform="translate(1460)"/><use xlink:href="#111" transform="translate(1480)"/><use xlink:href="#111" transform="translate(1500)"/><use xlink:href="#111" transform="translate(1520)"/><use xlink:href="#111" transform="translate(1540)"/><use xlink:href="#1m1" transform="translate(1560)"/><use xlink:href="#111" transform="translate(1580)"/><use xlink:href="#111" transform="translate(1600)"/><use xlink:href="#111" transform="translate(1620)"/><use xlink:href="#111" transform="translate(1640)"/><use xlink:href="#111" transform="translate(1660)"/><use xlink:href="#1m1" transform="translate(1680)"/><use xlink:href="#111" transform="translate(1700)"/><use xlink:href="#111" transform="translate(1720)"/><use xlink:href="#111" transform="translate(1740)"/><use xlink:href="#1m0" transform="translate(1760)"/><use xlink:href="#000" transform="translate(1780)"/><use xlink:href="#000" transform="translate(1800)"/><use xlink:href="#000" transform="translate(1820)"/><use xlink:href="#000" transform="translate(1840)"/><use xlink:href="#000" transform="translate(1860)"/><use xlink:href="#0m0" transform="translate(1880)"/><use xlink:href="#000" transform="translate(1900)"/><use xlink:href="#000" transform="translate(1920)"/><use xlink:href="#000" transform="translate(1940)"/><use xlink:href="#000" transform="translate(1960)"/><use xlink:href="#000" transform="translate(1980)"/><use xlink:href="#0m0" transform="translate(2000)"/><use xlink:href="#000" transform="translate(2020)"/><use xlink:href="#000" transform="translate(2040)"/><use xlink:href="#000" transform="translate(2060)"/><use xlink:href="#0m0" transform="translate(2080)"/><use xlink:href="#000" transform="translate(2100)"/><use xlink:href="#000" transform="translate(2120)"/><use xlink:href="#000" transform="translate(2140)"/><use xlink:href="#000" transform="translate(2160)"/><use xlink:href="#000" transform="translate(2180)"/></g></g><g id="wavelane_12_0" transform="translate(0,365)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>i_xclk_data</tspan></text><g id="wavelane_draw_12_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#000" transform="translate(440)"/><use xlink:href="#000" transform="translate(460)"/><use xlink:href="#000" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/><use xlink:href="#000" transform="translate(520)"/><use xlink:href="#000" transform="translate(540)"/><use xlink:href="#000" transform="translate(560)"/><use xlink:href="#000" transform="translate(580)"/><use xlink:href="#000" transform="translate(600)"/><use xlink:href="#000" transform="translate(620)"/><use xlink:href="#000" transform="translate(640)"/><use xlink:href="#000" transform="translate(660)"/><use xlink:href="#000" transform="translate(680)"/><use xlink:href="#000" transform="translate(700)"/><use xlink:href="#0mv-3" transform="translate(720)"/><use xlink:href="#vvv-3" transform="translate(740)"/><use xlink:href="#vvv-3" transform="translate(760)"/><use xlink:href="#vvv-3" transform="translate(780)"/><use xlink:href="#vmv-3-4" transform="translate(800)"/><use xlink:href="#vvv-4" transform="translate(820)"/><use xlink:href="#vvv-4" transform="translate(840)"/><use xlink:href="#vvv-4" transform="translate(860)"/><use xlink:href="#vvv-4" transform="translate(880)"/><use xlink:href="#vvv-4" transform="translate(900)"/><use xlink:href="#vmv-4-5" transform="translate(920)"/><use xlink:href="#vvv-5" transform="translate(940)"/><use xlink:href="#vvv-5" transform="translate(960)"/><use xlink:href="#vvv-5" transform="translate(980)"/><use xlink:href="#vvv-5" transform="translate(1000)"/><use xlink:href="#vvv-5" transform="translate(1020)"/><use xlink:href="#vmv-5-6" transform="translate(1040)"/><use xlink:href="#vvv-6" transform="translate(1060)"/><use xlink:href="#vvv-6" transform="translate(1080)"/><use xlink:href="#vvv-6" transform="translate(1100)"/><use xlink:href="#vmv-6-7" transform="translate(1120)"/><use xlink:href="#vvv-7" transform="translate(1140)"/><use xlink:href="#vvv-7" transform="translate(1160)"/><use xlink:href="#vvv-7" transform="translate(1180)"/><use xlink:href="#vvv-7" transform="translate(1200)"/><use xlink:href="#vvv-7" transform="translate(1220)"/><use xlink:href="#vmv-7-8" transform="translate(1240)"/><use xlink:href="#vvv-8" transform="translate(1260)"/><use xlink:href="#vvv-8" transform="translate(1280)"/><use xlink:href="#vvv-8" transform="translate(1300)"/><use xlink:href="#vvv-8" transform="translate(1320)"/><use xlink:href="#vvv-8" transform="translate(1340)"/><use xlink:href="#vmv-8-9" transform="translate(1360)"/><use xlink:href="#vvv-9" transform="translate(1380)"/><use xlink:href="#vvv-9" transform="translate(1400)"/><use xlink:href="#vvv-9" transform="translate(1420)"/><use xlink:href="#vmv-9-3" transform="translate(1440)"/><use xlink:href="#vvv-3" transform="translate(1460)"/><use xlink:href="#vvv-3" transform="translate(1480)"/><use xlink:href="#vvv-3" transform="translate(1500)"/><use xlink:href="#vvv-3" transform="translate(1520)"/><use xlink:href="#vvv-3" transform="translate(1540)"/><use xlink:href="#vmv-3-4" transform="translate(1560)"/><use xlink:href="#vvv-4" transform="translate(1580)"/><use xlink:href="#vvv-4" transform="translate(1600)"/><use xlink:href="#vvv-4" transform="translate(1620)"/><use xlink:href="#vvv-4" transform="translate(1640)"/><use xlink:href="#vvv-4" transform="translate(1660)"/><use xlink:href="#vmv-4-5" transform="translate(1680)"/><use xlink:href="#vvv-5" transform="translate(1700)"/><use xlink:href="#vvv-5" transform="translate(1720)"/><use xlink:href="#vvv-5" transform="translate(1740)"/><use xlink:href="#vm0-5" transform="translate(1760)"/><use xlink:href="#000" transform="translate(1780)"/><use xlink:href="#000" transform="translate(1800)"/><use xlink:href="#000" transform="translate(1820)"/><use xlink:href="#000" transform="translate(1840)"/><use xlink:href="#000" transform="translate(1860)"/><use xlink:href="#0m0" transform="translate(1880)"/><use xlink:href="#000" transform="translate(1900)"/><use xlink:href="#000" transform="translate(1920)"/><use xlink:href="#000" transform="translate(1940)"/><use xlink:href="#000" transform="translate(1960)"/><use xlink:href="#000" transform="translate(1980)"/><use xlink:href="#0m0" transform="translate(2000)"/><use xlink:href="#000" transform="translate(2020)"/><use xlink:href="#000" transform="translate(2040)"/><use xlink:href="#000" transform="translate(2060)"/><use xlink:href="#0m0" transform="translate(2080)"/><use xlink:href="#000" transform="translate(2100)"/><use xlink:href="#000" transform="translate(2120)"/><use xlink:href="#000" transform="translate(2140)"/><use xlink:href="#000" transform="translate(2160)"/><use xlink:href="#000" transform="translate(2180)"/><text x="766" y="15" text-anchor="middle" xml:space="preserve"><tspan>D0</tspan></text><text x="866" y="15" text-anchor="middle" xml:space="preserve"><tspan>D1</tspan></text><text x="986" y="15" text-anchor="middle" xml:space="preserve"><tspan>D2</tspan></text><text x="1086" y="15" text-anchor="middle" xml:space="preserve"><tspan>D3</tspan></text><text x="1186" y="15" text-anchor="middle" xml:space="preserve"><tspan>D4</tspan></text><text x="1306" y="15" text-anchor="middle" xml:space="preserve"><tspan>D5</tspan></text><text x="1406" y="15" text-anchor="middle" xml:space="preserve"><tspan>D6</tspan></text><text x="1506" y="15" text-anchor="middle" xml:space="preserve"><tspan>D7</tspan></text><text x="1626" y="15" text-anchor="middle" xml:space="preserve"><tspan>D8</tspan></text><text x="1726" y="15" text-anchor="middle" xml:space="preserve"><tspan>D9</tspan></text></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"/><g id="wavegap_1_0" transform="translate(0,35)"/><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"/><g id="wavegap_4_0" transform="translate(0,125)"/><g id="wavegap_5_0" transform="translate(0,155)"/><g id="wavegap_6_0" transform="translate(0,185)"/><g id="wavegap_7_0" transform="translate(0,215)"/><g id="wavegap_8_0" transform="translate(0,245)"/><g id="wavegap_9_0" transform="translate(0,275)"/><g id="wavegap_10_0" transform="translate(0,305)"/><g id="wavegap_11_0" transform="translate(0,335)"/><g id="wavegap_12_0" transform="translate(0,365)"/></g></g><g id="groups_0"><g/></g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/xilinx-axilite2axi.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/xilinx-axilite2axi.png
new file mode 100644
index 0000000..a0b1415
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/xilinx-axilite2axi.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/xlnxstream.json b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/xlnxstream.json
new file mode 100644
index 0000000..2383653
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/xlnxstream.json
@@ -0,0 +1,9 @@
+{signal: [
+  {name: 'M_AXIS_ACLK',    wave: 'P.|..........'},
+  {name: 'M_AXIS_ARESETN', wave: '01|..........'},
+  {},
+  {name: 'M_AXIS_TVALID', wave: '0.|.1.......0',   data: ['S1','S2']},
+  {name: 'M_AXIS_TREADY', wave: 'x.|x1.....010',  data: ['S1','S2']},
+  {name: 'M_AXIS_TDATA',  wave: 'x.|x3456723.x',  data: ['D1','D2','D3','D4','D5','D6','D7']},
+  {name: 'M_AXIS_TLAST',  wave: '0.|........10'},
+]}
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/xlnxstream.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/xlnxstream.png
new file mode 100644
index 0000000..e275ebb
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/xlnxstream.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/xlnxstream.svg b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/xlnxstream.svg
new file mode 100644
index 0000000..a1bdb13
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/xlnxstream.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with WaveDrom -->
+<svg id="svgcontent_0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="210" width="700" viewBox="0 0 700 210" overflow="hidden" class="WaveDrom"><style type="text/css">text{font-size:11pt;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;fill-opacity:1;font-family:Helvetica}.muted{fill:#aaa}.warning{fill:#f6b900}.error{fill:#f60000}.info{fill:#0041c4}.success{fill:#00ab00}.h1{font-size:33pt;font-weight:bold}.h2{font-size:27pt;font-weight:bold}.h3{font-size:20pt;font-weight:bold}.h4{font-size:14pt;font-weight:bold}.h5{font-size:11pt;font-weight:bold}.h6{font-size:8pt;font-weight:bold}.s1{fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s2{fill:none;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}.s3{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s4{color:#000;fill:none;stroke:#000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible}.s5{fill:#fff;stroke:none}.s6{fill:#000;fill-opacity:1;stroke:none}.s7{color:#000;fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s8{color:#000;fill:#ffffb4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s9{color:#000;fill:#ffe0b9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s10{color:#000;fill:#b9e0ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s11{color:#000;fill:#ccfdfe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s12{color:#000;fill:#cdfdc5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s13{color:#000;fill:#f0c1fb;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s14{color:#000;fill:#f5c2c0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate}.s15{fill:#0041c4;fill-opacity:1;stroke:none}.s16{fill:none;stroke:#0041c4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none}</style><defs><g id="socket"><rect y="15" x="6" height="20" width="20"/></g><g id="pclk"><path d="M0,20 0,0 20,0" class="s1"/></g><g id="nclk"><path d="m0,0 0,20 20,0" class="s1"/></g><g id="000"><path d="m0,20 20,0" class="s1"/></g><g id="0m0"><path d="m0,20 3,0 3,-10 3,10 11,0" class="s1"/></g><g id="0m1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="0mx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="0md"><path d="m8,20 10,0" class="s3"/><path d="m0,20 5,0" class="s1"/></g><g id="0mu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="0mz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="111"><path d="M0,0 20,0" class="s1"/></g><g id="1m0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="1m1"><path d="M0,0 3,0 6,10 9,0 20,0" class="s1"/></g><g id="1mx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="1md"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="1mu"><path d="M0,0 5,0" class="s1"/><path d="M8,0 18,0" class="s3"/></g><g id="1mz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/></g><g id="xxx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xm0"><path d="M0,0 4,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5,5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 7,13" class="s2"/><path d="M5,20 8,17" class="s2"/></g><g id="xm1"><path d="M0,0 20,0" class="s1"/><path d="M0,20 4,20 9,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 9,1" class="s2"/><path d="M0,15 7,8" class="s2"/><path d="M0,20 5,15" class="s2"/></g><g id="xmx"><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 15,0" class="s2"/><path d="M0,20 20,0" class="s2"/><path d="M5,20 20,5" class="s2"/><path d="M10,20 20,10" class="s2"/><path d="m15,20 5,-5" class="s2"/></g><g id="xmd"><path d="m0,0 4,0 c 3,10 6,20 16,20" class="s1"/><path d="m0,20 20,0" class="s1"/><path d="M0,5 4,1" class="s2"/><path d="M0,10 5.5,4.5" class="s2"/><path d="M0,15 6.5,8.5" class="s2"/><path d="M0,20 8,12" class="s2"/><path d="m5,20 5,-5" class="s2"/><path d="m10,20 2.5,-2.5" class="s2"/></g><g id="xmu"><path d="M0,0 20,0" class="s1"/><path d="m0,20 4,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,5 5,0" class="s2"/><path d="M0,10 10,0" class="s2"/><path d="M0,15 10,5" class="s2"/><path d="M0,20 6,14" class="s2"/></g><g id="xmz"><path d="m0,0 4,0 c 6,10 11,10 16,10" class="s1"/><path d="m0,20 4,0 C 10,10 15,10 20,10" class="s1"/><path d="M0,5 4.5,0.5" class="s2"/><path d="M0,10 6.5,3.5" class="s2"/><path d="M0,15 8.5,6.5" class="s2"/><path d="M0,20 11.5,8.5" class="s2"/></g><g id="ddd"><path d="m0,20 20,0" class="s3"/></g><g id="dm0"><path d="m0,20 10,0" class="s3"/><path d="m12,20 8,0" class="s1"/></g><g id="dm1"><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="dmx"><path d="M3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 5,20" class="s2"/><path d="M20,0 4,16" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 9,1" class="s2"/><path d="m0,20 20,0" class="s1"/></g><g id="dmd"><path d="m0,20 20,0" class="s3"/></g><g id="dmu"><path d="m0,20 3,0 C 7,10 10.107603,0 20,0" class="s1"/></g><g id="dmz"><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="uuu"><path d="M0,0 20,0" class="s3"/></g><g id="um0"><path d="m0,0 3,0 6,20 11,0" class="s1"/></g><g id="um1"><path d="M0,0 10,0" class="s3"/><path d="m12,0 8,0" class="s1"/></g><g id="umx"><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6,9" class="s2"/><path d="M10,0 5,5" class="s2"/><path d="M3.5,1.5 5,0" class="s2"/></g><g id="umd"><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/></g><g id="umu"><path d="M0,0 20,0" class="s3"/></g><g id="umz"><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s4"/></g><g id="zzz"><path d="m0,10 20,0" class="s1"/></g><g id="zm0"><path d="m0,10 6,0 3,10 11,0" class="s1"/></g><g id="zm1"><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="zmx"><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 6.5,8.5" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="zmd"><path d="m0,10 7,0 c 3,5 8,10 13,10" class="s1"/></g><g id="zmu"><path d="m0,10 7,0 C 10,5 15,0 20,0" class="s1"/></g><g id="zmz"><path d="m0,10 20,0" class="s1"/></g><g id="gap"><path d="m7,-2 -4,0 c -5,0 -5,24 -10,24 l 4,0 C 2,22 2,-2 7,-2 z" class="s5"/><path d="M-7,22 C -2,22 -2,-2 3,-2" class="s1"/><path d="M-3,22 C 2,22 2,-2 7,-2" class="s1"/></g><g id="Pclk"><path d="M-3,12 0,3 3,12 C 1,11 -1,11 -3,12 z" class="s6"/><path d="M0,20 0,0 20,0" class="s1"/></g><g id="Nclk"><path d="M-3,8 0,17 3,8 C 1,9 -1,9 -3,8 z" class="s6"/><path d="m0,0 0,20 20,0" class="s1"/></g><g id="0mv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-2"><path d="M2.875,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-2"><path d="M9,0 20,0 20,20 3,20 z" class="s7"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-2"><path d="M3,0 20,0 20,20 9,20 z" class="s7"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-2"><path d="M20,20 0,20 0,0 20,0" class="s7"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-2"><path d="M0,20 0,0 3,0 9,20" class="s7"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-2"><path d="M0,0 0,20 3,20 9,0" class="s7"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-2"><path d="M0,0 0,20 3,20 6,10 3,0" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-2"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s7"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-2"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s7"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-2"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s7"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-3"><path d="M2.875,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-3"><path d="M9,0 20,0 20,20 3,20 z" class="s8"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-3"><path d="M3,0 20,0 20,20 9,20 z" class="s8"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-3"><path d="M20,20 0,20 0,0 20,0" class="s8"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-3"><path d="M0,20 0,0 3,0 9,20" class="s8"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-3"><path d="M0,0 0,20 3,20 9,0" class="s8"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-3"><path d="M0,0 0,20 3,20 6,10 3,0" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-3"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s8"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-3"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s8"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-3"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s8"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-4"><path d="M2.875,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-4"><path d="M9,0 20,0 20,20 3,20 z" class="s9"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-4"><path d="M3,0 20,0 20,20 9,20 z" class="s9"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-4"><path d="M20,20 0,20 0,0 20,0" class="s9"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-4"><path d="M0,20 0,0 3,0 9,20" class="s9"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-4"><path d="M0,0 0,20 3,20 9,0" class="s9"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-4"><path d="M0,0 0,20 3,20 6,10 3,0" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-4"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s9"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-4"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s9"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-4"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s9"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-5"><path d="M2.875,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-5"><path d="M9,0 20,0 20,20 3,20 z" class="s10"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-5"><path d="M3,0 20,0 20,20 9,20 z" class="s10"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-5"><path d="M20,20 0,20 0,0 20,0" class="s10"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-5"><path d="M0,20 0,0 3,0 9,20" class="s10"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-5"><path d="M0,0 0,20 3,20 9,0" class="s10"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-5"><path d="M0,0 0,20 3,20 6,10 3,0" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-5"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s10"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-5"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s10"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-5"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s10"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-6"><path d="M2.875,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-6"><path d="M9,0 20,0 20,20 3,20 z" class="s11"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-6"><path d="M3,0 20,0 20,20 9,20 z" class="s11"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-6"><path d="M20,20 0,20 0,0 20,0" class="s11"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-6"><path d="M0,20 0,0 3,0 9,20" class="s11"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-6"><path d="M0,0 0,20 3,20 9,0" class="s11"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-6"><path d="M0,0 0,20 3,20 6,10 3,0" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-6"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s11"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-6"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s11"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-6"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s11"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-7"><path d="M2.875,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-7"><path d="M9,0 20,0 20,20 3,20 z" class="s12"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-7"><path d="M3,0 20,0 20,20 9,20 z" class="s12"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-7"><path d="M20,20 0,20 0,0 20,0" class="s12"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-7"><path d="M0,20 0,0 3,0 9,20" class="s12"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-7"><path d="M0,0 0,20 3,20 9,0" class="s12"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-7"><path d="M0,0 0,20 3,20 6,10 3,0" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-7"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s12"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-7"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s12"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-7"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s12"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-8"><path d="M2.875,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-8"><path d="M9,0 20,0 20,20 3,20 z" class="s13"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-8"><path d="M3,0 20,0 20,20 9,20 z" class="s13"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-8"><path d="M20,20 0,20 0,0 20,0" class="s13"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-8"><path d="M0,20 0,0 3,0 9,20" class="s13"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-8"><path d="M0,0 0,20 3,20 9,0" class="s13"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-8"><path d="M0,0 0,20 3,20 6,10 3,0" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-8"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s13"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-8"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s13"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-8"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s13"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="0mv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="1mv-9"><path d="M2.875,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="xmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,5 3.5,1.5" class="s2"/><path d="M0,10 4.5,5.5" class="s2"/><path d="M0,15 6,9" class="s2"/><path d="M0,20 4,16" class="s2"/></g><g id="dmv-9"><path d="M9,0 20,0 20,20 3,20 z" class="s14"/><path d="M3,20 9,0 20,0" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="umv-9"><path d="M3,0 20,0 20,20 9,20 z" class="s14"/><path d="m3,0 6,20 11,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="zmv-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="m6,10 3,10 11,0" class="s1"/><path d="M0,10 6,10 9,0 20,0" class="s1"/></g><g id="vvv-9"><path d="M20,20 0,20 0,0 20,0" class="s14"/><path d="m0,20 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vm0-9"><path d="M0,20 0,0 3,0 9,20" class="s14"/><path d="M0,0 3,0 9,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vm1-9"><path d="M0,0 0,20 3,20 9,0" class="s14"/><path d="M0,0 20,0" class="s1"/><path d="M0,20 3,20 9,0" class="s1"/></g><g id="vmx-9"><path d="M0,0 0,20 3,20 6,10 3,0" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/><path d="m20,15 -5,5" class="s2"/><path d="M20,10 10,20" class="s2"/><path d="M20,5 8,17" class="s2"/><path d="M20,0 7,13" class="s2"/><path d="M15,0 7,8" class="s2"/><path d="M10,0 9,1" class="s2"/></g><g id="vmd-9"><path d="m0,0 0,20 20,0 C 10,20 7,10 3,0" class="s14"/><path d="m0,0 3,0 c 4,10 7,20 17,20" class="s1"/><path d="m0,20 20,0" class="s1"/></g><g id="vmu-9"><path d="m0,0 0,20 3,0 C 7,10 10,0 20,0" class="s14"/><path d="m0,20 3,0 C 7,10 10,0 20,0" class="s1"/><path d="M0,0 20,0" class="s1"/></g><g id="vmz-9"><path d="M0,0 3,0 C 10,10 15,10 20,10 15,10 10,10 3,20 L 0,20" class="s14"/><path d="m0,0 3,0 c 7,10 12,10 17,10" class="s1"/><path d="m0,20 3,0 C 10,10 15,10 20,10" class="s1"/></g><g id="vmv-2-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-2"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s7"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-3"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s8"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-4"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s9"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-5"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s10"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-6"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s11"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-7"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s12"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-8"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s13"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-2-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s7"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-3-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s8"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-4-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s9"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-5-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s10"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-6-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s11"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-7-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s12"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-8-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s13"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="vmv-9-9"><path d="M9,0 20,0 20,20 9,20 6,10 z" class="s14"/><path d="M3,0 0,0 0,20 3,20 6,10 z" class="s14"/><path d="m0,0 3,0 6,20 11,0" class="s1"/><path d="M0,20 3,20 9,0 20,0" class="s1"/></g><g id="arrow0"><path d="m-12,-3 9,3 -9,3 c 1,-2 1,-4 0,-6 z" class="s15"/><path d="M0,0 -15,0" class="s16"/></g><marker id="arrowhead" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="0 -4 11 8" refX="15" refY="0" orient="auto"><path d="M0 -4 11 0 0 4z"/></marker><marker id="arrowtail" style="fill:#0041c4" markerHeight="7" markerWidth="10" markerUnits="strokeWidth" viewBox="-11 -4 11 8" refX="-15" refY="0" orient="auto"><path d="M0 -4 -11 0 0 4z"/></marker></defs><g id="waves_0"><g id="lanes_0" transform="translate(160.5, 0.5)"><g id="gmarks_0"><g style="stroke:#888;stroke-width:0.5;stroke-dasharray:1,3"><line id="gmark_0_0" x1="0" y1="0" x2="0" y2="210"/><line id="gmark_1_0" x1="40" y1="0" x2="40" y2="210"/><line id="gmark_2_0" x1="80" y1="0" x2="80" y2="210"/><line id="gmark_3_0" x1="120" y1="0" x2="120" y2="210"/><line id="gmark_4_0" x1="160" y1="0" x2="160" y2="210"/><line id="gmark_5_0" x1="200" y1="0" x2="200" y2="210"/><line id="gmark_6_0" x1="240" y1="0" x2="240" y2="210"/><line id="gmark_7_0" x1="280" y1="0" x2="280" y2="210"/><line id="gmark_8_0" x1="320" y1="0" x2="320" y2="210"/><line id="gmark_9_0" x1="360" y1="0" x2="360" y2="210"/><line id="gmark_10_0" x1="400" y1="0" x2="400" y2="210"/><line id="gmark_11_0" x1="440" y1="0" x2="440" y2="210"/><line id="gmark_12_0" x1="480" y1="0" x2="480" y2="210"/><line id="gmark_13_0" x1="520" y1="0" x2="520" y2="210"/></g></g><g id="wavelane_0_0" transform="translate(0,5)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIS_ACLK</tspan></text><g id="wavelane_draw_0_0" transform="translate(0, 0)"><use xlink:href="#Pclk" transform="translate(0)"/><use xlink:href="#nclk" transform="translate(20)"/><use xlink:href="#Pclk" transform="translate(40)"/><use xlink:href="#nclk" transform="translate(60)"/><use xlink:href="#Pclk" transform="translate(80)"/><use xlink:href="#nclk" transform="translate(100)"/><use xlink:href="#Pclk" transform="translate(120)"/><use xlink:href="#nclk" transform="translate(140)"/><use xlink:href="#Pclk" transform="translate(160)"/><use xlink:href="#nclk" transform="translate(180)"/><use xlink:href="#Pclk" transform="translate(200)"/><use xlink:href="#nclk" transform="translate(220)"/><use xlink:href="#Pclk" transform="translate(240)"/><use xlink:href="#nclk" transform="translate(260)"/><use xlink:href="#Pclk" transform="translate(280)"/><use xlink:href="#nclk" transform="translate(300)"/><use xlink:href="#Pclk" transform="translate(320)"/><use xlink:href="#nclk" transform="translate(340)"/><use xlink:href="#Pclk" transform="translate(360)"/><use xlink:href="#nclk" transform="translate(380)"/><use xlink:href="#Pclk" transform="translate(400)"/><use xlink:href="#nclk" transform="translate(420)"/><use xlink:href="#Pclk" transform="translate(440)"/><use xlink:href="#nclk" transform="translate(460)"/><use xlink:href="#Pclk" transform="translate(480)"/><use xlink:href="#nclk" transform="translate(500)"/></g></g><g id="wavelane_1_0" transform="translate(0,35)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIS_ARESETN</tspan></text><g id="wavelane_draw_1_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#0m1" transform="translate(40)"/><use xlink:href="#111" transform="translate(60)"/><use xlink:href="#111" transform="translate(80)"/><use xlink:href="#111" transform="translate(100)"/><use xlink:href="#111" transform="translate(120)"/><use xlink:href="#111" transform="translate(140)"/><use xlink:href="#111" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#111" transform="translate(480)"/><use xlink:href="#111" transform="translate(500)"/></g></g><g id="wavelane_2_0" transform="translate(0,65)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan/></text><g id="wavelane_draw_2_0" transform="translate(0, 0)"/></g><g id="wavelane_3_0" transform="translate(0,95)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIS_TVALID</tspan></text><g id="wavelane_draw_3_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#0m1" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#111" transform="translate(400)"/><use xlink:href="#111" transform="translate(420)"/><use xlink:href="#111" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#1m0" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/></g></g><g id="wavelane_4_0" transform="translate(0,125)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIS_TREADY</tspan></text><g id="wavelane_draw_4_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xmx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xm1" transform="translate(160)"/><use xlink:href="#111" transform="translate(180)"/><use xlink:href="#111" transform="translate(200)"/><use xlink:href="#111" transform="translate(220)"/><use xlink:href="#111" transform="translate(240)"/><use xlink:href="#111" transform="translate(260)"/><use xlink:href="#111" transform="translate(280)"/><use xlink:href="#111" transform="translate(300)"/><use xlink:href="#111" transform="translate(320)"/><use xlink:href="#111" transform="translate(340)"/><use xlink:href="#111" transform="translate(360)"/><use xlink:href="#111" transform="translate(380)"/><use xlink:href="#1m0" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#0m1" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#1m0" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/></g></g><g id="wavelane_5_0" transform="translate(0,155)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIS_TDATA</tspan></text><g id="wavelane_draw_5_0" transform="translate(0, 0)"><use xlink:href="#xxx" transform="translate(0)"/><use xlink:href="#xxx" transform="translate(20)"/><use xlink:href="#xxx" transform="translate(40)"/><use xlink:href="#xxx" transform="translate(60)"/><use xlink:href="#xxx" transform="translate(80)"/><use xlink:href="#xxx" transform="translate(100)"/><use xlink:href="#xmx" transform="translate(120)"/><use xlink:href="#xxx" transform="translate(140)"/><use xlink:href="#xmv-3" transform="translate(160)"/><use xlink:href="#vvv-3" transform="translate(180)"/><use xlink:href="#vmv-3-4" transform="translate(200)"/><use xlink:href="#vvv-4" transform="translate(220)"/><use xlink:href="#vmv-4-5" transform="translate(240)"/><use xlink:href="#vvv-5" transform="translate(260)"/><use xlink:href="#vmv-5-6" transform="translate(280)"/><use xlink:href="#vvv-6" transform="translate(300)"/><use xlink:href="#vmv-6-7" transform="translate(320)"/><use xlink:href="#vvv-7" transform="translate(340)"/><use xlink:href="#vmv-7-2" transform="translate(360)"/><use xlink:href="#vvv-2" transform="translate(380)"/><use xlink:href="#vmv-2-3" transform="translate(400)"/><use xlink:href="#vvv-3" transform="translate(420)"/><use xlink:href="#vvv-3" transform="translate(440)"/><use xlink:href="#vvv-3" transform="translate(460)"/><use xlink:href="#vmx-3" transform="translate(480)"/><use xlink:href="#xxx" transform="translate(500)"/><text x="186" y="15" text-anchor="middle" xml:space="preserve"><tspan>D1</tspan></text><text x="226" y="15" text-anchor="middle" xml:space="preserve"><tspan>D2</tspan></text><text x="266" y="15" text-anchor="middle" xml:space="preserve"><tspan>D3</tspan></text><text x="306" y="15" text-anchor="middle" xml:space="preserve"><tspan>D4</tspan></text><text x="346" y="15" text-anchor="middle" xml:space="preserve"><tspan>D5</tspan></text><text x="386" y="15" text-anchor="middle" xml:space="preserve"><tspan>D6</tspan></text><text x="446" y="15" text-anchor="middle" xml:space="preserve"><tspan>D7</tspan></text></g></g><g id="wavelane_6_0" transform="translate(0,185)"><text x="-10" y="15" class="info" text-anchor="end" xml:space="preserve"><tspan>M_AXIS_TLAST</tspan></text><g id="wavelane_draw_6_0" transform="translate(0, 0)"><use xlink:href="#000" transform="translate(0)"/><use xlink:href="#000" transform="translate(20)"/><use xlink:href="#000" transform="translate(40)"/><use xlink:href="#000" transform="translate(60)"/><use xlink:href="#000" transform="translate(80)"/><use xlink:href="#000" transform="translate(100)"/><use xlink:href="#000" transform="translate(120)"/><use xlink:href="#000" transform="translate(140)"/><use xlink:href="#000" transform="translate(160)"/><use xlink:href="#000" transform="translate(180)"/><use xlink:href="#000" transform="translate(200)"/><use xlink:href="#000" transform="translate(220)"/><use xlink:href="#000" transform="translate(240)"/><use xlink:href="#000" transform="translate(260)"/><use xlink:href="#000" transform="translate(280)"/><use xlink:href="#000" transform="translate(300)"/><use xlink:href="#000" transform="translate(320)"/><use xlink:href="#000" transform="translate(340)"/><use xlink:href="#000" transform="translate(360)"/><use xlink:href="#000" transform="translate(380)"/><use xlink:href="#000" transform="translate(400)"/><use xlink:href="#000" transform="translate(420)"/><use xlink:href="#0m1" transform="translate(440)"/><use xlink:href="#111" transform="translate(460)"/><use xlink:href="#1m0" transform="translate(480)"/><use xlink:href="#000" transform="translate(500)"/></g></g><g id="wavearcs_0"/><g id="wavegaps_0"><g id="wavegap_0_0" transform="translate(0,5)"><use xlink:href="#gap" transform="translate(100)"/></g><g id="wavegap_1_0" transform="translate(0,35)"><use xlink:href="#gap" transform="translate(100)"/></g><g id="wavegap_2_0" transform="translate(0,65)"/><g id="wavegap_3_0" transform="translate(0,95)"><use xlink:href="#gap" transform="translate(100)"/></g><g id="wavegap_4_0" transform="translate(0,125)"><use xlink:href="#gap" transform="translate(100)"/></g><g id="wavegap_5_0" transform="translate(0,155)"><use xlink:href="#gap" transform="translate(100)"/></g><g id="wavegap_6_0" transform="translate(0,185)"><use xlink:href="#gap" transform="translate(100)"/></g></g></g><g id="groups_0"><g/></g></g></svg>
\ No newline at end of file
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/xlnxstream_trace.png b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/xlnxstream_trace.png
new file mode 100644
index 0000000..f81c24c
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gfx/xlnxstream_trace.png
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/gpl-3.0.pdf b/verilog/rtl/softshell/third_party/wb2axip/doc/gpl-3.0.pdf
new file mode 100644
index 0000000..2f28d9f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/gpl-3.0.pdf
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/orconf2019.pdf b/verilog/rtl/softshell/third_party/wb2axip/doc/orconf2019.pdf
new file mode 100644
index 0000000..c51a662
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/orconf2019.pdf
Binary files differ
diff --git a/verilog/rtl/softshell/third_party/wb2axip/doc/src/gpl-3.0.tex b/verilog/rtl/softshell/third_party/wb2axip/doc/src/gpl-3.0.tex
new file mode 100644
index 0000000..acb8a38
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/doc/src/gpl-3.0.tex
@@ -0,0 +1,719 @@
+\documentclass[11pt]{article}
+
+\title{GNU GENERAL PUBLIC LICENSE}
+\date{Version 3, 29 June 2007}
+
+\begin{document}
+\maketitle
+
+\begin{center}
+{\parindent 0in
+
+Copyright \copyright\  2007 Free Software Foundation, Inc. \texttt{http://fsf.org/}
+
+\bigskip
+Everyone is permitted to copy and distribute verbatim copies of this
+
+license document, but changing it is not allowed.}
+
+\end{center}
+
+\renewcommand{\abstractname}{Preamble}
+\begin{abstract}
+The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+The precise terms and conditions for copying, distribution and
+modification follow.
+\end{abstract}
+
+\begin{center}
+{\Large \sc Terms and Conditions}
+\end{center}
+
+
+\begin{enumerate}
+
+\addtocounter{enumi}{-1}
+
+\item Definitions.
+
+``This License'' refers to version 3 of the GNU General Public License.
+
+``Copyright'' also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+``The Program'' refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as ``you''.  ``Licensees'' and
+``recipients'' may be individuals or organizations.
+
+To ``modify'' a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a ``modified version'' of the
+earlier work or a work ``based on'' the earlier work.
+
+A ``covered work'' means either the unmodified Program or a work based
+on the Program.
+
+To ``propagate'' a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+To ``convey'' a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+An interactive user interface displays ``Appropriate Legal Notices''
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+\item Source Code.
+
+The ``source code'' for a work means the preferred form of the work
+for making modifications to it.  ``Object code'' means any non-source
+form of a work.
+
+A ``Standard Interface'' means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+The ``System Libraries'' of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+``Major Component'', in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+The ``Corresponding Source'' for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+The Corresponding Source for a work in source code form is that
+same work.
+
+\item Basic Permissions.
+
+All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+\item Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+\item Conveying Verbatim Copies.
+
+You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+\item Conveying Modified Source Versions.
+
+You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+  \begin{enumerate}
+  \item The work must carry prominent notices stating that you modified
+  it, and giving a relevant date.
+
+  \item The work must carry prominent notices stating that it is
+  released under this License and any conditions added under section
+  7.  This requirement modifies the requirement in section 4 to
+  ``keep intact all notices''.
+
+  \item You must license the entire work, as a whole, under this
+  License to anyone who comes into possession of a copy.  This
+  License will therefore apply, along with any applicable section 7
+  additional terms, to the whole of the work, and all its parts,
+  regardless of how they are packaged.  This License gives no
+  permission to license the work in any other way, but it does not
+  invalidate such permission if you have separately received it.
+
+  \item If the work has interactive user interfaces, each must display
+  Appropriate Legal Notices; however, if the Program has interactive
+  interfaces that do not display Appropriate Legal Notices, your
+  work need not make them do so.
+\end{enumerate}
+A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+``aggregate'' if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+\item Conveying Non-Source Forms.
+
+You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+  \begin{enumerate}
+  \item Convey the object code in, or embodied in, a physical product
+  (including a physical distribution medium), accompanied by the
+  Corresponding Source fixed on a durable physical medium
+  customarily used for software interchange.
+
+  \item Convey the object code in, or embodied in, a physical product
+  (including a physical distribution medium), accompanied by a
+  written offer, valid for at least three years and valid for as
+  long as you offer spare parts or customer support for that product
+  model, to give anyone who possesses the object code either (1) a
+  copy of the Corresponding Source for all the software in the
+  product that is covered by this License, on a durable physical
+  medium customarily used for software interchange, for a price no
+  more than your reasonable cost of physically performing this
+  conveying of source, or (2) access to copy the
+  Corresponding Source from a network server at no charge.
+
+  \item Convey individual copies of the object code with a copy of the
+  written offer to provide the Corresponding Source.  This
+  alternative is allowed only occasionally and noncommercially, and
+  only if you received the object code with such an offer, in accord
+  with subsection 6b.
+
+  \item Convey the object code by offering access from a designated
+  place (gratis or for a charge), and offer equivalent access to the
+  Corresponding Source in the same way through the same place at no
+  further charge.  You need not require recipients to copy the
+  Corresponding Source along with the object code.  If the place to
+  copy the object code is a network server, the Corresponding Source
+  may be on a different server (operated by you or a third party)
+  that supports equivalent copying facilities, provided you maintain
+  clear directions next to the object code saying where to find the
+  Corresponding Source.  Regardless of what server hosts the
+  Corresponding Source, you remain obligated to ensure that it is
+  available for as long as needed to satisfy these requirements.
+
+  \item Convey the object code using peer-to-peer transmission, provided
+  you inform other peers where the object code and Corresponding
+  Source of the work are being offered to the general public at no
+  charge under subsection 6d.
+  \end{enumerate}
+
+A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+A ``User Product'' is either (1) a ``consumer product'', which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, ``normally used'' refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+``Installation Information'' for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+\item Additional Terms.
+
+``Additional permissions'' are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+  \begin{enumerate}
+  \item Disclaiming warranty or limiting liability differently from the
+  terms of sections 15 and 16 of this License; or
+
+  \item Requiring preservation of specified reasonable legal notices or
+  author attributions in that material or in the Appropriate Legal
+  Notices displayed by works containing it; or
+
+  \item Prohibiting misrepresentation of the origin of that material, or
+  requiring that modified versions of such material be marked in
+  reasonable ways as different from the original version; or
+
+  \item Limiting the use for publicity purposes of names of licensors or
+  authors of the material; or
+
+  \item Declining to grant rights under trademark law for use of some
+  trade names, trademarks, or service marks; or
+
+  \item Requiring indemnification of licensors and authors of that
+  material by anyone who conveys the material (or modified versions of
+  it) with contractual assumptions of liability to the recipient, for
+  any liability that these contractual assumptions directly impose on
+  those licensors and authors.
+  \end{enumerate}
+
+All other non-permissive additional terms are considered ``further
+restrictions'' within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+\item Termination.
+
+You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+\item Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+\item Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+An ``entity transaction'' is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+\item Patents.
+
+A ``contributor'' is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's ``contributor version''.
+
+A contributor's ``essential patent claims'' are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, ``control'' includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+In the following three paragraphs, a ``patent license'' is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To ``grant'' such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  ``Knowingly relying'' means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+A patent license is ``discriminatory'' if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+\item No Surrender of Others' Freedom.
+
+If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+\item Use with the GNU Affero General Public License.
+
+Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+\item Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License ``or any later version'' applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+\item Disclaimer of Warranty.
+
+\begin{sloppypar}
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+ APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE
+ COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ``AS IS''
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE
+ RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.
+ SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+ NECESSARY SERVICING, REPAIR OR CORRECTION.
+\end{sloppypar}
+
+\item Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+ WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES
+ AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
+ DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
+ DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM
+ (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
+ INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE
+ OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH
+ HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+\item Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+\begin{center}
+{\Large\sc End of Terms and Conditions}
+
+\bigskip
+How to Apply These Terms to Your New Programs
+\end{center}
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the ``copyright'' line and a pointer to where the full notice is found.
+
+{\footnotesize
+\begin{verbatim}
+<one line to give the program's name and a brief idea of what it does.>
+
+Copyright (C) <textyear>  <name of author>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+\end{verbatim}
+}
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+{\footnotesize
+\begin{verbatim}
+<program>  Copyright (C) <year>  <name of author>
+
+This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+This is free software, and you are welcome to redistribute it
+under certain conditions; type `show c' for details.
+\end{verbatim}
+}
+
+The hypothetical commands {\tt show w} and {\tt show c} should show
+the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an ``about box''.
+
+You should also get your employer (if you work as a programmer) or
+school, if any, to sign a ``copyright disclaimer'' for the program, if
+necessary.  For more information on this, and how to apply and follow
+the GNU GPL, see \texttt{http://www.gnu.org/licenses/}.
+
+The GNU General Public License does not permit incorporating your
+program into proprietary programs.  If your program is a subroutine
+library, you may consider it more useful to permit linking proprietary
+applications with the library.  If this is what you want to do, use
+the GNU Lesser General Public License instead of this License.  But
+first, please read \texttt{http://www.gnu.org/philosophy/why-not-lgpl.html}.
+
+\end{enumerate}
+
+\end{document}
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/.gitignore b/verilog/rtl/softshell/third_party/wb2axip/rtl/.gitignore
new file mode 100644
index 0000000..e1cd503
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/.gitignore
@@ -0,0 +1,2 @@
+*.ys
+ivcheck
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/Makefile b/verilog/rtl/softshell/third_party/wb2axip/rtl/Makefile
new file mode 100644
index 0000000..dc60bed
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/Makefile
@@ -0,0 +1,274 @@
+################################################################################
+##
+## Filename:	Makefile
+##
+## Project:	WB2AXIPSP: bus bridges and other odds and ends
+##
+## Purpose:	To describe how to build the Verilator libraries from the
+##		RTL, for the purposes of trying to discover if they work.
+##	Any actual testing will be done from the code within the bench/cpp
+##	directory.
+##
+## Targets:	The default target, all, builds the target test, which includes
+##		the libraries necessary for Verilator testing.
+##
+## Creator:	Dan Gisselquist, Ph.D.
+##		Gisselquist Technology, LLC
+##
+################################################################################
+##
+## Copyright (C) 2016-2020, Gisselquist Technology, LLC
+##
+## This file is part of the WB2AXIP project.
+##
+## The WB2AXIP project contains free software and gateware, licensed under the
+## Apache License, Version 2.0 (the "License").  You may not use this project,
+## or this file, except in compliance with the License.  You may obtain a copy
+## of the License at
+##
+##	http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+## WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+## License for the specific language governing permissions and limitations
+## under the License.
+##
+################################################################################
+##
+##
+all:	test
+YYMMDD=`date +%Y%m%d`
+CXX   := g++
+IVCHECK  := ivcheck
+IVERILOG := iverilog
+FBDIR := .
+VDIRFB:= $(FBDIR)/obj_dir
+VERILATOR := verilator
+VFLAGS    := -MMD -O3 -Wall -Wpedantic -cc
+.DELETE_ON_ERROR:
+.PHONY: test
+test: testwb testaxi testaxil testapb
+
+.PHONY: testwb testaxi testaxil testapb
+
+.PHONY: axim2wbsp axim2wbsp wbm2axilite axilrd2wbsp axilwr2wbsp axlite2wbsp
+.PHONY: axixbar axilxbar wbxbar axis2mm aximm2s axidma axim2wbsp aximrd2wbsp
+.PHONY: aximwr2wbsp axixclk axiperf demoaxi demofull easyaxil sfifo skidbuffer
+.PHONY: axilsafety axisafety wbsafety axivfifo axil2apb apbslave
+
+axim2wbsp:   $(VDIRFB)/Vwbm2axisp__ALL.a    $(IVCHECK)/axim2wbsp
+axim2wbsp:   $(VDIRFB)/Vaxim2wbsp__ALL.a
+wbm2axilite: $(VDIRFB)/Vwbm2axilite__ALL.a  $(IVCHECK)/wbm2axilite
+axilrd2wbsp: $(VDIRFB)/Vaxilrd2wbsp__ALL.a  $(IVCHECK)/axilrd2wbsp
+axilwr2wbsp: $(VDIRFB)/Vaxilwr2wbsp__ALL.a  $(IVCHECK)/axilwr2wbsp
+axlite2wbsp: $(VDIRFB)/Vaxlite2wbsp__ALL.a  $(IVCHECK)/axlite2wbsp
+axivfifo:    $(VDIRFB)/Vaxivfifo__ALL.a     $(IVCHECK)/axivfifo
+axixbar:     $(VDIRFB)/Vaxixbar__ALL.a      $(IVCHECK)/axixbar
+axilxbar:    $(VDIRFB)/Vaxilxbar__ALL.a     $(IVCHECK)/axilxbar
+wbxbar:      $(VDIRFB)/Vwbxbar__ALL.a       $(IVCHECK)/wbxbar
+axis2mm:     $(VDIRFB)/Vaxis2mm__ALL.a      $(IVCHECK)/axis2mm
+aximm2s:     $(VDIRFB)/Vaximm2s__ALL.a      $(IVCHECK)/aximm2s
+axidma:      $(VDIRFB)/Vaxidma__ALL.a       $(IVCHECK)/axidma
+axim2wbsp:   $(VDIRFB)/Vaxim2wbsp__ALL.a    $(IVCHECK)/axim2wbsp
+aximrd2wbsp: $(VDIRFB)/Vaximrd2wbsp__ALL.a  $(IVCHECK)/aximrd2wbsp
+aximwr2wbsp: $(VDIRFB)/Vaximwr2wbsp__ALL.a  $(IVCHECK)/aximwr2wbsp
+axiperf:     $(VDIRFB)/Vaxiperf__ALL.a      $(IVCHECK)/axiperf
+axixclk:     $(VDIRFB)/Vaxixclk__ALL.a      $(IVCHECK)/axixclk
+demoaxi:     $(VDIRFB)/Vdemoaxi__ALL.a      $(IVCHECK)/demoaxi
+demofull:    $(VDIRFB)/Vdemofull__ALL.a     $(IVCHECK)/demofull
+easyaxil:    $(VDIRFB)/Veasyaxil__ALL.a     $(IVCHECK)/easyaxil
+sfifo:       $(VDIRFB)/Vsfifo__ALL.a        $(IVCHECK)/sfifo
+skidbuffer:  $(VDIRFB)/Vskidbuffer__ALL.a   $(IVCHECK)/skidbuffer
+axisafety:   $(VDIRFB)/Vaxisafety__ALL.a    $(IVCHECK)/axisafety
+axilsafety:  $(VDIRFB)/Vaxilsafety__ALL.a   $(IVCHECK)/axilsafety
+wbsafety:    $(VDIRFB)/Vwbsafety__ALL.a     $(IVCHECK)/wbsafety
+axil2apb:    $(VDIRFB)/Vaxil2apb__ALL.a     $(IVCHECK)/axil2apb
+apbslave:    $(VDIRFB)/Vapbslave__ALL.a     $(IVCHECK)/apbslave
+
+testwb: wbsafety wbm2axilite wbxbar sfifo wbsafety wbxbar wbsafety
+testaxi: axim2wbsp axixbar axixclk demofull
+testaxi: aximrd2wbsp axim2wbsp aximwr2wbsp axisafety
+testaxi: axis2mm aximm2s axidma axivfifo
+testaxil: axilrd2wbsp axilwr2wbsp axlite2wbsp axilxbar demoaxi easyaxil
+testaxil: skidbuffer axiperf
+testapb: axil2apb apbslave
+
+.PHONY: wbm2axisp
+wbm2axisp: $(VDIRFB)/Vwbm2axisp__ALL.a
+$(VDIRFB)/Vwbm2axisp__ALL.a: $(VDIRFB)/Vwbm2axisp.h $(VDIRFB)/Vwbm2axisp.cpp
+$(VDIRFB)/Vwbm2axisp__ALL.a: $(VDIRFB)/Vwbm2axisp.mk
+$(VDIRFB)/Vwbm2axisp.h $(VDIRFB)/Vwbm2axisp.cpp $(VDIRFB)/Vwbm2axisp.mk: wbm2axisp.v
+
+.PHONY: wbm2axilite
+wbm2axilite: $(VDIRFB)/Vwbm2axilite__ALL.a
+$(VDIRFB)/Vwbm2axilite__ALL.a: $(VDIRFB)/Vwbm2axilite.h $(VDIRFB)/Vwbm2axilite.cpp
+$(VDIRFB)/Vwbm2axilite__ALL.a: $(VDIRFB)/Vwbm2axilite.mk
+$(VDIRFB)/Vwbm2axilite.h $(VDIRFB)/Vwbm2axilite.cpp $(VDIRFB)/Vwbm2axilite.mk: wbm2axilite.v
+
+.PHONY: axilrd2wbsp
+axilrd2wbsp: $(VDIRFB)/Vaxilrd2wbsp__ALL.a
+$(VDIRFB)/Vaxilrd2wbsp__ALL.a: $(VDIRFB)/Vaxilrd2wbsp.h $(VDIRFB)/Vaxilrd2wbsp.cpp
+$(VDIRFB)/Vaxilrd2wbsp__ALL.a: $(VDIRFB)/Vaxilrd2wbsp.mk
+$(VDIRFB)/Vaxilrd2wbsp.h $(VDIRFB)/Vaxilrd2wbsp.cpp $(VDIRFB)/Vaxilrd2wbsp.mk: axilrd2wbsp.v
+
+.PHONY: axilwr2wbsp
+axilwr2wbsp: $(VDIRFB)/Vaxilwr2wbsp__ALL.a
+$(VDIRFB)/Vaxilwr2wbsp__ALL.a: $(VDIRFB)/Vaxilwr2wbsp.h $(VDIRFB)/Vaxilwr2wbsp.cpp
+$(VDIRFB)/Vaxilwr2wbsp__ALL.a: $(VDIRFB)/Vaxilwr2wbsp.mk
+$(VDIRFB)/Vaxilwr2wbsp.h $(VDIRFB)/Vaxilwr2wbsp.cpp $(VDIRFB)/Vaxilwr2wbsp.mk: axilwr2wbsp.v
+
+$(VDIRFB)/Vaxlite2wbsp__ALL.a: $(VDIRFB)/Vaxlite2wbsp.h $(VDIRFB)/Vaxlite2wbsp.cpp
+$(VDIRFB)/Vaxlite2wbsp__ALL.a: $(VDIRFB)/Vaxlite2wbsp.mk
+$(VDIRFB)/Vaxlite2wbsp.h $(VDIRFB)/Vaxlite2wbsp.cpp $(VDIRFB)/Vaxlite2wbsp.mk: axlite2wbsp.v
+
+$(VDIRFB)/Vaxim2wbsp__ALL.a: $(VDIRFB)/Vaxim2wbsp.h $(VDIRFB)/Vaxim2wbsp.cpp
+$(VDIRFB)/Vaxim2wbsp__ALL.a: $(VDIRFB)/Vaxim2wbsp.mk
+$(VDIRFB)/Vaxim2wbsp.h $(VDIRFB)/Vaxim2wbsp.cpp $(VDIRFB)/Vaxim2wbsp.mk: \
+	axim2wbsp.v aximrd2wbsp.v aximwr2wbsp.v wbarbiter.v
+
+$(VDIRFB)/Vaxivfifo__ALL.a: $(VDIRFB)/Vaxivfifo.h $(VDIRFB)/Vaxivfifo.cpp
+$(VDIRFB)/Vaxivfifo__ALL.a: $(VDIRFB)/Vaxivfifo.mk
+$(VDIRFB)/Vaxivfifo.h $(VDIRFB)/Vaxivfifo.cpp $(VDIRFB)/Vaxivfifo.mk: \
+	axivfifo.v aximrd2wbsp.v aximwr2wbsp.v wbarbiter.v
+
+$(VDIRFB)/V%.cpp $(VDIRFB)/V%.h $(VDIRFB)/V%.mk: $(FBDIR)/%.v
+	$(VERILATOR) $(VFLAGS) $*.v
+
+$(VDIRFB)/V%__ALL.a: $(VDIRFB)/V%.mk
+	cd $(VDIRFB); make -f V$*.mk
+
+##
+## Run Icarus Verilog (iverilog) on each of these cores for a lint check
+##
+$(IVCHECK)/axi2axilite: axi2axilite.v sfifo.v skidbuffer.v axi_addr.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axil2axis: axil2axis.v sfifo.v skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axildouble: axildouble.v sfifo.v skidbuffer.v addrdecode.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axilrd2wbsp: axilrd2wbsp.v sfifo.v skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axilsafety: axilsafety.v sfifo.v skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axilsingle: axilsingle.v sfifo.v skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axilwr2wbsp: axilwr2wbsp.v sfifo.v skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axilxbar: axilxbar.v skidbuffer.v addrdecode.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axidma: axidma.v sfifo.v skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/aximm2s: aximm2s.v sfifo.v skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axim2wbsp: axim2wbsp.v sfifo.v skidbuffer.v aximrd2wbsp.v aximwr2wbsp.v axi_addr.v wbarbiter.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/aximrd2wbsp: aximrd2wbsp.v sfifo.v skidbuffer.v axi_addr.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/aximwr2wbsp: aximwr2wbsp.v sfifo.v skidbuffer.v axi_addr.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axiperf: axiperf.v skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axisafety: axisafety.v skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axis2mm: axis2mm.v sfifo.v skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axivfifo: axivfifo.v sfifo.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axixbar: axixbar.v skidbuffer.v addrdecode.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axixclk: axixclk.v afifo.v skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axlite2wbsp: axlite2wbsp.v axilrd2wbsp.v axilwr2wbsp.v wbarbiter.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/demoaxi: demoaxi.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/demofull: demofull.v axi_addr.v skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/easyaxil: easyaxil.v skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/sfifo: sfifo.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/skidbuffer: skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/wbm2axilite: wbm2axilite.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/wbsafety: wbsafety.v skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/wbxbar: wbxbar.v skidbuffer.v addrdecode.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/axil2apb: axil2apb.v skidbuffer.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+$(IVCHECK)/apbslave: apbslave.v
+	$(mk-ivcheck)
+	$(IVERILOG) -g2012 $^ -o $@
+
+define	mk-ivcheck
+	@bash -c "if [ ! -e $(IVCHECK) ]; then mkdir -p $(IVCHECK); fi"
+endef
+
+.PHONY: clean
+clean:
+	rm -rf $(VDIRFB)/*.mk
+	rm -rf $(VDIRFB)/*.cpp
+	rm -rf $(VDIRFB)/*.h
+	rm -rf $(VDIRFB)/
+	rm -rf $(IVCHECK)/
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/README.md b/verilog/rtl/softshell/third_party/wb2axip/rtl/README.md
new file mode 100644
index 0000000..36644c2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/README.md
@@ -0,0 +1,151 @@
+## Demo designs
+
+- [Demonstration AXI4-lite slave](demoaxi.v)
+- [Demonstration APB slave](apbslave.v)
+- [Demonstration AXI4(Full) slave](demofull.v)
+  -- [AXI Addr](axi_addr.v) is a helper core used for calculating the "next" address in a burst sequence.  It's based upon [the algorithm discussed here](https://zipcpu.com/blog/2019/04/27/axi-addr.html).
+- [A simplified AXI-lite slave](easyaxil.v)
+
+- [Skidbuffer](skidbuffer.v)
+
+## Crossbars
+
+See [this post for a discussion of these
+crossbars](https://zipcpu.com/blog/2019/07/17/crossbars.html).
+
+- [AXI4](axixbar.v)
+- [AXI4-Lite](axilxbar.v)
+- [Wishbone](wbxbar.v)
+
+These cores rely not only on the [skidbuffer](skidbuffer.v) listed above, but
+also upon a separate [address decoder](addrdecode.v) that is common to all of
+them.
+
+All three cores are supported by the (dev branch of)
+[AutoFPGA](https://github.com/ZipCPU/autofpga).
+
+## Data movers/DMA engines
+
+- [AXIMM2S](aximm2s.v).  Supports unaligned transfers, but only fully aligned
+  stream words.
+- [AXIS2MM](axis2mm.v).  Doesn't yet support unaligned transfers.  It may
+  eventually, but it will also only ever support full word transfers
+  through the stream.
+- [AXIDMA](axidma.v).  Supports unaligned transfers.
+- [AXIVFIFO](axivfifo.v).  A virtual FIFO, using an external AXI device for
+  memory backing--perhaps even an SDRAM.  It doesn't really matter--it just
+  needs to be AXI.
+- [AXIVCAMERA](axivcamera.v).  Writes a video stream to a memory frame buffer.
+- [AXIVDISPLAY](axivdisplay.v).  Reads a frame buffer from memory to generate
+  a continuous AXI-stream video source output.
+
+- [Synchronous FIFO](sfifo.v)
+- [Synchronous FIFO with threshold](sfifothresh.v)
+
+## Bus Bridges
+
+- [AXI to AXI-lite](axi2axilite.v).  Supports 100% throughput even across burst
+  boundaries, unlike other (similar) bridges of this type you might come across.
+
+- [AXI-lite to AXI](axilite2axi.v).  A "no-cost" bridge.
+
+- [AXI-lite to AXI stream](axil2axis.v)
+
+- [AXI-Lite to Wishbone](axlite2wbsp.v)
+
+  -- [Read side](axilrd2wbsp.v)
+
+  -- [Write side](axilwr2wbsp.v)
+
+  -- A following (optional) [arbiter](wbarbiter.v) will connect read and write sides together into the same WB bus.  Alternatively, each of the two sides can be submitted separately into a [WB Crossbar](wbxbar.v).
+
+- [AXI-Lite to APB](axil2apb.v)
+
+- [AXI4 Master to Wishbone](axim2wbsp.v)
+
+  -- [Read side](aximrd2wbsp.v)
+
+  -- [AXI4 Master to Wishbone](aximwr2wbsp.v)
+
+- [Wishbone classic to pipelined](wbc2pipeline.v)
+
+- [Wishbone pipelined to classic](wbp2classic.v)
+
+- [Wishbone master to AXI4-Litejk slave](wbm2axilite.v)
+
+- [Wishbone master to AXI4 slave](wbm2axisp.v)
+
+  This core, together with its sister core, [migsdram](migsdram.v), form the
+  basis for my approach to accessing DDR3 SDRAM memory through an AXI
+  interface using Xilinx's MIG controller.  Other than the lag in going
+  through the bridge, this solution works quite well--achieving full (nearly
+  100%) bus throughput when loaded.
+
+- [AXI3 to AXI4](axi32axi.v).  See the internal documentation of the
+  [AXI3 write deinterleaver](axi3reorder.v) for the details of the write
+  deinterleaving algorithm.
+
+- The AXI4 to AXI3 bridge is still missing.
+  This will be more difficult than its [AXI3 to AXI4 sister](axi32axi.v) above,
+  since it will need to break apart large AXI4 burst requests into smaller AXI3
+  bursts, sort of like the [AXI4 to AXI4-lite bridge](axi2axilite.v) does.
+
+## AXI Simplifiers
+
+These follow from the discussion in [this article about how to simplify
+a bus interconnect](https://zipcpu.com/zipcpu/2019/08/30/subbus.html) into
+something allowing easier integration of multiple slaves into a design.  They
+work by aggregating the signaling logic across many slaves together.  See the
+headers for each of the cores for the specifics of the standard subsets
+they support.
+
+- AXI Single, the companion to the [AXI Double](axidouble.v) core has not yet
+  been written.  The design for it should be nearly identical.  The big
+  difference between single and double AXI slaves is that single slaves can have
+  only one address, and that address must always be available for reading.
+
+- [AXI Double](axidouble.v).
+
+- [AXI-Lite Single](axilsingle.v)
+
+- [AXI-Lite Double](axildouble.v)
+
+## Firewalls
+
+The goal of these firewall(s) is to create a core that, when placed between the
+bus master and slave, will guarantee that the slave responds appropriately to
+the bus master---even in the presence of a broken slave.  If the slave is
+broken, the firewall will raise a flag that can then be used to trigger a
+logic analyzer of some type so you can dig deeper into what's going on.
+
+As a bonus, the firewall may also have the capability of resetting the
+downstream core upon any error, so that it might be reintegrated later into
+the rest of the design for additional testing.
+
+- [AXI-lite](axilsafety.v)
+
+- [AXI4](axisafety.v)
+
+- [AXI-stream](axissafety.v)
+
+- [Wishbone](wbsafety.v)
+
+## Empty slaves
+
+These are used to simplify interconnect generation.  When there are no slaves
+connected to an interconnect, the interconnect generator can automatically
+connect one of these slaves (depending on the protocol) and be guaranteed
+that the protocol will still be followed.  All requests, however, will return
+bus errors.
+
+- [AXIEMPTY](axiempty.v) - the AXI4 empty slave
+
+- [AXILEMPTY](axilempty.v) - the AXI4-lite empty slave
+
+## Clock domain crossing bridges
+
+- [Wishbone cross-clock domains](wbxclk.v)
+
+- [AXI4 cross-clock domains](axixclk.v)
+
+- [Asynchronous FIFO](afifo.v) -- support function
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/addrdecode.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/addrdecode.v
new file mode 100644
index 0000000..c5c5902
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/addrdecode.v
@@ -0,0 +1,394 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	addrdecode.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module	addrdecode(i_clk, i_reset, i_valid, o_stall, i_addr, i_data,
+			o_valid, i_stall, o_decode, o_addr, o_data);
+	parameter	NS=8;
+	parameter	AW = 32, DW=32+32/8+1+1;
+	//
+	// SLAVE_ADDR contains address assignments for each of the various
+	// slaves we are adjudicating between.
+	parameter	[NS*AW-1:0]	SLAVE_ADDR = {
+				{ 3'b111, {(AW-3){1'b0}}},
+				{ 3'b110, {(AW-3){1'b0}}},
+				{ 3'b101, {(AW-3){1'b0}}},
+				{ 3'b100, {(AW-3){1'b0}}},
+				{ 3'b011, {(AW-3){1'b0}}},
+				{ 3'b010, {(AW-3){1'b0}}},
+				{ 4'b0010, {(AW-4){1'b0}}},
+				{ 4'b0000, {(AW-4){1'b0}}} };
+	//
+	// SLAVE_MASK contains a mask of those address bits in SLAVE_ADDR
+	// which are relevant.  It shall be true that if
+	//	!SLAVE_MASK[k] then !SLAVE_ADDR[k], for any bits of k
+	parameter	[NS*AW-1:0]	SLAVE_MASK = (NS <= 1) ? 0
+		: { {(NS-2){ 3'b111, {(AW-3){1'b0}}}},
+			{(2){ 4'b1111, {(AW-4){1'b0}} }} };
+	//
+	// ACCESS_ALLOWED is a bit-wise mask indicating which slaves may get
+	// access to the bus.  If ACCESS_ALLOWED[slave] is true, then a master
+	// can connect to the slave via this method.  This parameter is
+	// primarily here to support AXI (or other similar buses) which may have
+	// separate accesses for both read and write.  By using this, a
+	// read-only slave can be connected, which would also naturally create
+	// an error on any attempt to write to it.
+	parameter	[NS-1:0]	ACCESS_ALLOWED = -1;
+	//
+	// If OPT_REGISTERED is set, address decoding will take an extra clock,
+	// and will register the results of the decoding operation.
+	parameter [0:0]	OPT_REGISTERED = 0;
+	//
+	// If OPT_LOWPOWER is set, then whenever the output is not valid, any
+	// respective data linse will also be forced to zero in an effort
+	// to minimize power.
+	parameter [0:0]	OPT_LOWPOWER = 0;
+	//
+	// OPT_NONESEL controls whether or not the address lines are fully
+	// proscribed, or whether or not a "no-slave identified" slave should
+	// be created.  To avoid a "no-slave selected" output, slave zero must
+	// have no mask bits set (and therefore no address bits set), and it
+	// must also allow access.
+	localparam [0:0] OPT_NONESEL = (!ACCESS_ALLOWED[0])
+					|| (SLAVE_MASK[AW-1:0] != 0);
+	//
+	input	wire			i_clk, i_reset;
+	//
+	input	wire			i_valid;
+	output	reg			o_stall;
+	input	wire	[AW-1:0]	i_addr;
+	input	wire	[DW-1:0]	i_data;
+	//
+	output	reg			o_valid;
+	input	wire			i_stall;
+	output	reg	[NS:0]		o_decode;
+	output	reg	[AW-1:0]	o_addr;
+	output	reg	[DW-1:0]	o_data;
+
+	reg	[NS:0]		request;
+	reg	[NS-1:0]	prerequest;
+	reg			none_sel;
+	integer			iM;
+
+	always @(*)
+	for(iM=0; iM<NS; iM=iM+1)
+		prerequest[iM] = (((i_addr ^ SLAVE_ADDR[iM*AW +: AW])
+				&SLAVE_MASK[iM*AW +: AW])==0)
+			&&(ACCESS_ALLOWED[iM]);
+
+	generate if (OPT_NONESEL)
+	begin : NO_DEFAULT_REQUEST
+
+		// Need to create a slave to describe when nothing is selected
+		//
+		always @(*)
+		begin
+			for(iM=0; iM<NS; iM=iM+1)
+				request[iM] = i_valid && prerequest[iM];
+			if (!OPT_NONESEL && (NS > 1 && |prerequest[NS-1:1]))
+				request[0] = 1'b0;
+		end
+
+	end else if (NS == 1)
+	begin
+
+		always @(*)
+			request = { 1'b0, i_valid };
+
+	end else begin
+
+		always @(*)
+		begin
+			for(iM=0; iM<NS; iM=iM+1)
+				request[iM] = i_valid && prerequest[iM];
+			if (!OPT_NONESEL && (NS > 1 && |prerequest[NS-1:1]))
+				request[0] = 1'b0;
+		end
+
+	end endgenerate
+
+	generate if (OPT_NONESEL)
+	begin
+		always @(*)
+		begin
+			// Let's assume nothing's been selected, and then check
+			// to prove ourselves wrong.
+			//
+			// Note that none_sel will be considered an error
+			// condition in the follow-on processing.  Therefore
+			// it's important to clear it if no request is pending.
+			none_sel = i_valid && (prerequest == 0);
+			//
+			// request[NS] indicates a request for a non-existent
+			// slave.  A request that should (eventually) return a
+			// bus error
+			//
+			request[NS] = none_sel;
+		end
+	end else begin
+		always @(*)
+			{ request[NS], none_sel } = 2'b00;
+
+		// Verilator lint_off UNUSED
+		wire	all_assigned_unused = none_sel;
+		// Verilator lint_on  UNUSED
+	end endgenerate
+
+	generate if (OPT_REGISTERED)
+	begin
+		initial	o_valid = 0;
+		always @(posedge i_clk)
+		if (i_reset)
+			o_valid <= 0;
+		else if (!o_stall)
+			o_valid <= i_valid;
+
+
+		initial	o_addr   = 0;
+		initial	o_data   = 0;
+		always @(posedge i_clk)
+		if (i_reset && OPT_LOWPOWER)
+		begin
+			o_addr   <= 0;
+			o_data   <= 0;
+		end else if ((!o_valid || !i_stall)
+				 && (i_valid || !OPT_LOWPOWER))
+		begin
+			o_addr   <= i_addr;
+			o_data   <= i_data;
+		end else if (OPT_LOWPOWER && !i_stall)
+		begin
+			o_addr   <= 0;
+			o_data   <= 0;
+		end
+
+		initial	o_decode = 0;
+		always @(posedge i_clk)
+		if (i_reset)
+			o_decode <= 0;
+		else if ((!o_valid || !i_stall)
+				 && (i_valid || !OPT_LOWPOWER))
+			o_decode <= request;
+		else if (OPT_LOWPOWER && !i_stall)
+			o_decode <= 0;
+
+		always @(*)
+			o_stall = (o_valid && i_stall);
+	end else begin
+
+		always @(*)
+		begin
+			o_valid = i_valid;
+			o_stall = i_stall;
+			o_addr  = i_addr;
+			o_data  = i_data;
+
+			o_decode = request;
+		end
+
+		// verilator lint_off UNUSED
+		wire	unused;
+		assign	unused = &{ 1'b0,
+`ifdef	VERILATOR
+				// Can't declare the clock as unused for formal,
+				// lest it not be recognized as *the* clock
+				i_clk,
+`endif
+				i_reset };
+		// verilator lint_on UNUSED
+	end endgenerate
+
+`ifdef	FORMAL
+	reg	f_past_valid;
+	initial	f_past_valid = 0;
+	always @(posedge i_clk)
+		f_past_valid <= 1;
+
+	reg	[AW+DW-1:0]	f_idata;
+	always @(*)
+		f_idata = { i_addr, i_data };
+
+`ifdef	ADDRDECODE
+	always @(posedge i_clk)
+	if (!f_past_valid)
+		assume(i_reset);
+
+	/*
+	always @(posedge i_clk)
+	if (!f_past_valid || $past(i_reset))
+		assume(!i_valid);
+	else if ($past(i_valid && o_stall))
+	begin
+		assume(i_valid);
+		// assume($stable(f_idata));
+	end
+	*/
+`else
+	always @(posedge i_clk)
+	if (!f_past_valid)
+		assert(i_reset);
+
+/*
+	always @(posedge i_clk)
+	if (!f_past_valid || $past(i_reset))
+		assert(!i_valid);
+	else if ($past(i_valid && o_stall))
+	begin
+		assert(i_valid);
+		// assert($stable(f_idata) || (!OPT_REGISTERED && i_reset));
+	end
+*/
+`endif	// ADDRDECODE
+	always @(posedge i_clk)
+	if (OPT_REGISTERED && (!f_past_valid || $past(i_reset)))
+	begin
+		assert(!o_valid);
+		assert(o_decode == 0);
+	end else if ($past(o_valid && i_stall) && OPT_REGISTERED)
+	begin
+		assert($stable(o_addr));
+		assert($stable(o_decode));
+		assert($stable(o_data));
+	end
+
+	// If the output is ever valid, there must be at least one
+	// decoded output
+	always @(*)
+		assert(o_valid == (o_decode != 0));
+
+	always @(*)
+	for(iM=0; iM<NS; iM=iM+1)
+	if (o_decode[iM])
+	begin
+		// The address must match
+		assert((((o_addr ^ SLAVE_ADDR[iM*AW +: AW])
+				& SLAVE_MASK[iM*AW +: AW])==0)
+			&& ACCESS_ALLOWED[iM]);
+		//
+		// And nothing else must match
+		assert(o_decode == (1<<iM));
+	end
+
+	always @(*)
+	for(iM=0; iM<NS; iM=iM+1)
+	if (!ACCESS_ALLOWED[iM])
+		assert(!o_decode[iM]);
+
+	generate if (OPT_LOWPOWER && OPT_REGISTERED)
+	begin
+		always @(*)
+		if (!o_valid)
+		begin
+			assert(o_addr   == 0);
+			assert(o_decode == 0);
+			assert(o_data   == 0);
+		end
+	end endgenerate
+
+	//
+	// The output decoded value may only ever have one value high,
+	// never more--i.e. $onehot0
+	//
+`ifdef	VERIFIC
+	always @(*)
+		assert($onehot0(request));
+`else
+	reg	onehot_request;
+	always @(*)
+	begin
+		onehot_request = 0;
+		for(iM=0; iM<NS+1; iM=iM+1)
+		if ((request ^ (1<<iM))==0)
+			onehot_request = 1;
+	end
+
+	always @(*)
+	if (request != 0)
+		assert(onehot_request);
+`endif
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover properties
+	//
+	// Make sure all addresses are reachable
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	[NS:0]	f_reached;
+
+	always @(posedge i_clk)
+		cover(i_valid);
+
+	always @(posedge i_clk)
+		cover(o_valid);
+
+	always @(posedge i_clk)
+		cover(o_valid && !i_stall);
+
+	initial	f_reached = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		f_reached = 0;
+	else if (o_valid)
+		f_reached = f_reached | o_decode;
+
+	generate if (!OPT_NONESEL && ACCESS_ALLOWED[0]
+			&& SLAVE_MASK == 0 && NS == 1)
+	begin
+		
+		always @(*)
+			cover(f_reached[0]);
+
+		always @(posedge i_clk)
+		if (f_past_valid && $stable(o_valid))
+			assert($stable(o_decode));
+
+	end else begin
+
+		always @(*)
+			cover(&f_reached);
+
+		always @(posedge i_clk)
+		if (f_past_valid && $stable(o_valid))
+			cover($changed(o_decode));
+
+	end endgenerate
+
+`endif	// FORMAL
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/afifo.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/afifo.v
new file mode 100644
index 0000000..0391837
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/afifo.v
@@ -0,0 +1,742 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename:	afifo.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	A basic asynchronous FIFO.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// }}}
+module afifo #(
+		// {{{
+		// LGFIFO is the log based-two of the number of entries
+		//	in the FIFO, log_2(fifo size)
+		parameter	LGFIFO = 3,
+		//
+		// WIDTH is the number of data bits in each entry
+		parameter	WIDTH  = 16,
+		//
+		// NFF is the number of flip flops used to cross clock domains.
+		// 2 is a minimum.  Some applications appreciate the better
+		parameter	NFF    = 2,
+		//
+		// This core can either write on the positive edge of the clock
+		// or the negative edge.  Set WRITE_ON_POSEDGE (the default)
+		// to write on the positive edge of the clock.
+		parameter [0:0]	WRITE_ON_POSEDGE = 1'b1,
+		//
+		// Many  logic elements can read from memory asynchronously.
+		// This burdens any following logic.  By setting
+		// OPT_REGISTER_READS, we force all reads to be synchronous and
+		// not burdened by any logic.  You can spare a clock of latency
+		// by clearing this register.
+		parameter [0:0]	OPT_REGISTER_READS = 1'b1,
+		//
+		// MSB = most significant bit of the FIFO address vector.  It's
+		// just short-hand for LGFIFO, and won't work any other way.
+		parameter	MSB = LGFIFO
+		// }}}
+	) (
+		// {{{
+		//
+		// The (incoming) write data interface
+		input	wire			i_wclk, i_wr_reset_n, i_wr,
+		input	wire	[WIDTH-1:0]	i_wr_data,
+		output	reg			o_wr_full,
+		//
+		// The (incoming) write data interface
+		input	wire			i_rclk, i_rd_reset_n, i_rd,
+		output	reg	[WIDTH-1:0]	o_rd_data,
+		output	reg			o_rd_empty
+`ifdef	FORMAL
+		, output reg	[LGFIFO:0]	f_fill
+`endif
+		// }}}
+	);
+
+	// Register/net declarations
+	// {{{
+
+	reg	[WIDTH-1:0]		mem	[(1<<LGFIFO)-1:0];
+	reg	[LGFIFO:0]		rd_addr, wr_addr,
+					rd_wgray, wr_rgray;
+	wire	[LGFIFO:0]		next_rd_addr, next_wr_addr;
+	reg	[LGFIFO:0]		rgray, wgray;
+	(* ASYNC_REG = "TRUE" *) reg	[(LGFIFO+1)*(NFF-1)-1:0]
+					rgray_cross, wgray_cross;
+	wire				wclk;
+	reg	[WIDTH-1:0]		lcl_rd_data;
+	reg				lcl_read, lcl_rd_empty;
+	// }}}
+
+	// wclk - Write clock generation
+	// {{{
+	generate if (WRITE_ON_POSEDGE)
+	begin
+
+		assign	wclk = i_wclk;
+
+	end else begin
+
+		assign	wclk = !i_wclk;
+
+	end endgenerate
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write to and read from memory
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// wr_addr, wgray
+	// {{{
+	assign	next_wr_addr = wr_addr + 1;
+	always @(posedge wclk or negedge i_wr_reset_n)
+	if (!i_wr_reset_n)
+	begin
+		wr_addr <= 0;
+		wgray   <= 0;
+	end else if (i_wr && !o_wr_full)
+	begin
+		wr_addr <= next_wr_addr;
+		wgray   <= next_wr_addr ^ (next_wr_addr >> 1);
+	end
+	// }}}
+
+	// Write to memory
+	// {{{
+	always @(posedge wclk)
+	if (i_wr && !o_wr_full)
+		mem[wr_addr[LGFIFO-1:0]] <= i_wr_data;
+	// }}}
+
+	// rd_addr, rgray
+	// {{{
+	assign	next_rd_addr = rd_addr + 1;
+	always @(posedge i_rclk or negedge i_rd_reset_n)
+	if (!i_rd_reset_n)
+	begin
+		rd_addr <= 0;
+		rgray   <= 0;
+	end else if (lcl_read && !lcl_rd_empty)
+	begin
+		rd_addr <= next_rd_addr;
+		rgray   <= next_rd_addr ^ (next_rd_addr >> 1);
+	end
+	// }}}
+
+	// Read from memory
+	// {{{
+	always @(*)
+		lcl_rd_data = mem[rd_addr[LGFIFO-1:0]];
+	// }}}
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cross clock domains
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// read pointer -> wr_rgray
+	// {{{
+	always @(posedge wclk or negedge i_wr_reset_n)
+	if (!i_wr_reset_n)
+		{ wr_rgray, rgray_cross } <= 0;
+	else
+		{ wr_rgray, rgray_cross } <= { rgray_cross, rgray };
+	// }}}
+
+	// write pointer -> rd_wgray
+	// {{{
+	always @(posedge i_rclk or negedge i_rd_reset_n)
+	if (!i_rd_reset_n)
+		{ rd_wgray, wgray_cross } <= 0;
+	else
+		{ rd_wgray, wgray_cross } <= { wgray_cross, wgray };
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Flag generation
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	always @(*)
+		o_wr_full = (wr_rgray == { ~wgray[MSB:MSB-1], wgray[MSB-2:0] });
+
+	always @(*)
+		lcl_rd_empty = (rd_wgray == rgray);
+
+	// o_rd_empty, o_rd_data
+	// {{{
+	generate if (OPT_REGISTER_READS)
+	begin
+		// {{{
+		always @(*)
+			lcl_read = (o_rd_empty || i_rd);
+
+		always @(posedge i_rclk or negedge i_rd_reset_n)
+		if (!i_rd_reset_n)
+			o_rd_empty <= 1'b1;
+		else if (lcl_read)
+			o_rd_empty <= lcl_rd_empty;
+
+		always @(posedge i_rclk)
+		if (lcl_read)
+			o_rd_data <= lcl_rd_data;
+		// }}}
+	end else begin
+		// {{{
+		always @(*)
+			lcl_read = i_rd;
+
+		always @(*)
+			o_rd_empty = lcl_rd_empty;
+
+		always @(*)
+			o_rd_data = lcl_rd_data;
+		// }}}
+	end endgenerate
+	// }}}
+	// }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	// Start out with some register/net/macro declarations, f_past_valid,etc
+	// {{{
+`ifdef	AFIFO
+`define	ASSERT	assert
+`define	ASSUME	assume
+`else
+`define	ASSERT	assert
+`define	ASSUME	assert
+`endif
+	(* gclk *)	reg	gbl_clk;
+	reg			f_past_valid_gbl, f_past_valid_rd,
+				f_rd_in_reset, f_wr_in_reset;
+	reg	[WIDTH-1:0]	past_rd_data, past_wr_data;
+	reg			past_wr_reset_n, past_rd_reset_n,
+				past_rd_empty, past_wclk, past_rclk, past_rd;
+	reg	[(LGFIFO+1)*(NFF-1)-1:0]	f_wcross, f_rcross;
+	reg	[LGFIFO:0]	f_rd_waddr, f_wr_raddr;
+	reg	[LGFIFO:0]	f_rdcross_fill	[NFF-1:0];
+	reg	[LGFIFO:0]	f_wrcross_fill	[NFF-1:0];
+
+
+	initial	f_past_valid_gbl = 1'b0;
+	always @(posedge gbl_clk)
+		f_past_valid_gbl <= 1'b1;
+
+	initial	f_past_valid_rd = 1'b0;
+	always @(posedge i_rclk)
+		f_past_valid_rd <= 1'b1;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Reset checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	initial	f_wr_in_reset = 1'b1;
+	always @(posedge wclk or negedge i_wr_reset_n)
+	if (!i_wr_reset_n)
+		f_wr_in_reset <= 1'b1;
+	else
+		f_wr_in_reset <= 1'b0;
+
+	initial	f_rd_in_reset = 1'b1;
+	always @(posedge i_rclk or negedge i_rd_reset_n)
+	if (!i_rd_reset_n)
+		f_rd_in_reset <= 1'b1;
+	else
+		f_rd_in_reset <= 1'b0;
+
+	//
+	// Resets are ...
+	//	1. Asserted always initially, and ...
+	always @(*)
+	if (!f_past_valid_gbl)
+	begin
+		`ASSUME(!i_wr_reset_n);
+		`ASSUME(!i_rd_reset_n);
+	end
+
+	//	2. They only ever become active together
+	always @(*)
+	if (past_wr_reset_n && !i_wr_reset_n)
+		`ASSUME(!i_rd_reset_n);
+
+	always @(*)
+	if (past_rd_reset_n && !i_rd_reset_n)
+		`ASSUME(!i_wr_reset_n);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Synchronous signal assumptions
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	always @(posedge gbl_clk)
+	begin
+		past_wr_reset_n <= i_wr_reset_n;
+		past_rd_reset_n <= i_rd_reset_n;
+
+		past_wclk  <= wclk;
+		past_rclk  <= i_rclk;
+
+		past_rd      <= i_rd;
+		past_rd_data <= lcl_rd_data;
+		past_wr_data <= i_wr_data;
+
+		past_rd_empty<= lcl_rd_empty;
+	end
+
+	//
+	// Read side may be assumed to be synchronous
+	always @(*)
+	if (f_past_valid_gbl && i_rd_reset_n && (past_rclk || !i_rclk))
+		// i.e. if (!$rose(i_rclk))
+		`ASSUME(i_rd == past_rd);
+
+	always @(*)
+	if (f_past_valid_rd && !f_rd_in_reset && !lcl_rd_empty
+		&&(past_rclk || !i_rclk))
+	begin
+		`ASSERT(lcl_rd_data == past_rd_data);
+		`ASSERT(lcl_rd_empty == past_rd_empty);
+	end
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Fill checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(*)
+		f_fill = wr_addr - rd_addr;
+
+	always @(*)
+	if (!f_wr_in_reset)
+		`ASSERT(f_fill <= { 1'b1, {(MSB){1'b0}} });
+
+	always @(*)
+	if (wr_addr == rd_addr)
+		`ASSERT(lcl_rd_empty);
+
+	always @(*)
+	if ((!f_wr_in_reset && !f_rd_in_reset)
+			&& wr_addr == { ~rd_addr[MSB], rd_addr[MSB-1:0] })
+		`ASSERT(o_wr_full);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Induction checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// f_wr_in_reset -- write logic is in its reset state
+	// {{{
+	always @(*)
+	if (f_wr_in_reset)
+	begin
+		`ASSERT(wr_addr == 0);
+		`ASSERT(wgray_cross == 0);
+
+		`ASSERT(rd_addr == 0);
+		`ASSERT(rgray_cross == 0);
+		`ASSERT(rd_wgray == 0);
+
+		`ASSERT(lcl_rd_empty);
+		`ASSERT(!o_wr_full);
+	end
+	// }}}
+
+	// f_rd_in_reset -- read logic is in its reset state
+	// {{{
+	always @(*)
+	if (f_rd_in_reset)
+	begin
+		`ASSERT(rd_addr == 0);
+		`ASSERT(rgray_cross == 0);
+		`ASSERT(rd_wgray == 0);
+
+		`ASSERT(lcl_rd_empty);
+	end
+	// }}}
+
+	// f_wr_raddr -- a read address to match the gray values
+	// {{{
+	always @(posedge wclk or negedge i_wr_reset_n)
+	if (!i_wr_reset_n)
+		{ f_wr_raddr, f_rcross } <= 0;
+	else
+		{ f_wr_raddr, f_rcross } <= { f_rcross, rd_addr };
+	// }}}
+
+	// f_rd_waddr -- a write address to match the gray values
+	// {{{
+	always @(posedge i_rclk or negedge i_rd_reset_n)
+	if (!i_rd_reset_n)
+		{ f_rd_waddr, f_wcross } <= 0;
+	else
+		{ f_rd_waddr, f_wcross } <= { f_wcross, wr_addr };
+	// }}}
+
+	integer	k;
+
+	// wgray check
+	// {{{
+	always @(*)
+		`ASSERT((wr_addr ^ (wr_addr >> 1)) == wgray);
+	// }}}
+
+	// wgray_cross check
+	// {{{
+	always @(*)
+	for(k=0; k<NFF-1; k=k+1)
+		`ASSERT((f_wcross[k*(LGFIFO+1) +: LGFIFO+1]
+			^ (f_wcross[k*(LGFIFO+1)+: LGFIFO+1]>>1))
+			== wgray_cross[k*(LGFIFO+1) +: LGFIFO+1]);
+	// }}}
+
+	// rgray check
+	// {{{
+	always @(*)
+		`ASSERT((rd_addr ^ (rd_addr >> 1)) == rgray);
+	// }}}
+
+	// rgray_cross check
+	// {{{
+	always @(*)
+	for(k=0; k<NFF-1; k=k+1)
+		`ASSERT((f_rcross[k*(LGFIFO+1) +: LGFIFO+1]
+			^ (f_rcross[k*(LGFIFO+1) +: LGFIFO+1]>>1))
+			== rgray_cross[k*(LGFIFO+1) +: LGFIFO+1]);
+	// }}}
+
+	// wr_rgray
+	// {{{
+	always @(*)
+		`ASSERT((f_wr_raddr ^ (f_wr_raddr >> 1)) == wr_rgray);
+	// }}}
+
+	// rd_wgray
+	// {{{
+	always @(*)
+		`ASSERT((f_rd_waddr ^ (f_rd_waddr >> 1)) == rd_wgray);
+	// }}}
+
+	// f_rdcross_fill
+	// {{{
+	always @(*)
+	for(k=0; k<NFF-1; k=k+1)
+		f_rdcross_fill[k] = f_wcross[k*(LGFIFO+1) +: LGFIFO+1]
+				- rd_addr;
+
+	always @(*)
+		f_rdcross_fill[NFF-1] = f_rd_waddr - rd_addr;
+
+	always @(*)
+	for(k=0; k<NFF; k=k+1)
+		`ASSERT(f_rdcross_fill[k] <= { 1'b1, {(LGFIFO){1'b0}} });
+
+	always @(*)
+	for(k=1; k<NFF; k=k+1)
+		`ASSERT(f_rdcross_fill[k] <= f_rdcross_fill[k-1]);
+	always @(*)
+		`ASSERT(f_rdcross_fill[0] <= f_fill);
+	// }}}
+
+	// f_wrcross_fill
+	// {{{
+	always @(*)
+	for(k=0; k<NFF-1; k=k+1)
+		f_wrcross_fill[k] = wr_addr -
+			f_rcross[k*(LGFIFO+1) +: LGFIFO+1];
+
+	always @(*)
+		f_wrcross_fill[NFF-1] = wr_addr - f_wr_raddr;
+
+	always @(*)
+	for(k=0; k<NFF; k=k+1)
+		`ASSERT(f_wrcross_fill[k] <= { 1'b1, {(LGFIFO){1'b0}} });
+
+	always @(*)
+	for(k=1; k<NFF; k=k+1)
+		`ASSERT(f_wrcross_fill[k] >= f_wrcross_fill[k-1]);
+	always @(*)
+		`ASSERT(f_wrcross_fill[0] >= f_fill);
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Clock generation
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// Here's the challenge: if we use $past with any of our clocks, such
+	// as to determine stability or any such, the proof takes forever, and
+	// we need to guarantee a minimum number of transitions within the
+	// depth of the proof.  If, on the other hand, we build our own $past
+	// primitives--we can then finish much faster and be successful on
+	// any depth of proof.
+
+	// pre_xclk is what the clock will become on the next global clock edge.
+	// By using it here, we can check things @(*) instead of
+	// @(posedge gbl_clk).  Further, we can check $rose(pre_xclk) (or $fell)
+	// and essentially check things @(*) but while using @(global_clk).
+	// In other words, we can transition on @(posedge gbl_clk), but stay
+	// in sync with the data--rather than being behind by a clock.
+	// now_xclk is what the clock is currently.
+	//
+	(* anyseq *)	reg	pre_wclk, pre_rclk;
+			reg	now_wclk, now_rclk;
+	always @(posedge gbl_clk)
+	begin
+		now_wclk <= pre_wclk;
+		now_rclk <= pre_rclk;
+	end
+
+	always @(*)
+	begin
+		assume(i_wclk == now_wclk);
+		assume(i_rclk == now_rclk);
+	end
+
+	always @(posedge gbl_clk)
+		assume(i_rclk == $past(pre_rclk));
+
+	// Assume both clocks start idle
+	// {{{
+	always @(*)
+	if (!f_past_valid_gbl)
+	begin
+		assume(!pre_wclk && !wclk);
+		assume(!pre_rclk && !i_rclk);
+	end
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Formal contract check --- the twin write test
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// Tracking register declarations
+	// {{{
+			reg	[WIDTH-1:0]	f_first, f_next;
+	(* anyconst *)	reg	[LGFIFO:0]	f_addr;
+			reg	[LGFIFO:0]	f_next_addr;
+	reg			f_first_in_fifo, f_next_in_fifo;
+	reg	[LGFIFO:0]	f_to_first, f_to_next;
+	reg	[1:0]	f_state;
+
+	always @(*)
+		f_next_addr = f_addr + 1;
+	// }}}
+
+	// distance_to*, *_in_fifo
+	// {{{
+	always @(*)
+	begin
+		f_to_first = f_addr - rd_addr;
+
+		f_first_in_fifo = 1'b1;
+		if ((f_to_first >= f_fill)||(f_fill == 0))
+			f_first_in_fifo = 1'b0;
+
+		if (mem[f_addr] != f_first)
+			f_first_in_fifo = 1'b0;
+
+		//
+		// Check the second item
+		//
+
+		f_to_next  = f_next_addr - rd_addr;
+		f_next_in_fifo = 1'b1;
+		if ((f_to_next >= f_fill)||(f_fill == 0))
+			f_next_in_fifo = 1'b0;
+
+		if (mem[f_next_addr] != f_next)
+			f_next_in_fifo = 1'b0;
+	end
+	// }}}
+
+	// f_state -- generate our state variable
+	// {{{
+	initial	f_state = 0;
+	always @(posedge gbl_clk)
+	if (!i_wr_reset_n)
+		f_state <= 0;
+	else case(f_state)
+	2'b00: if (($rose(pre_wclk))&& i_wr && !o_wr_full &&(wr_addr == f_addr))
+		begin
+			f_state <= 2'b01;
+			f_first <= i_wr_data;
+		end
+	2'b01: if ($rose(pre_rclk)&& lcl_read && rd_addr == f_addr)
+			f_state <= 2'b00;
+		else if ($rose(pre_wclk) && i_wr && !o_wr_full )
+		begin
+			f_state <= 2'b10;
+			f_next  <= i_wr_data;
+		end
+	2'b10: if ($rose(pre_rclk) && lcl_read && !lcl_rd_empty && rd_addr == f_addr)
+		f_state <= 2'b11;
+	2'b11: if ($rose(pre_rclk) && lcl_read && !lcl_rd_empty && rd_addr == f_next_addr)
+		f_state <= 2'b00;
+	endcase
+	// }}}
+
+	// f_state invariants
+	// {{{
+	always @(*)
+	if (i_wr_reset_n) case(f_state)
+	2'b00: begin end
+	2'b01: begin
+		`ASSERT(f_first_in_fifo);
+		`ASSERT(wr_addr == f_next_addr);
+		`ASSERT(f_fill >= 1);
+		end
+	2'b10: begin
+		`ASSERT(f_first_in_fifo);
+		`ASSERT(f_next_in_fifo);
+		if (!lcl_rd_empty && (rd_addr == f_addr))
+			`ASSERT(lcl_rd_data == f_first);
+		`ASSERT(f_fill >= 2);
+		end
+	2'b11: begin
+		`ASSERT(rd_addr == f_next_addr);
+		`ASSERT(f_next_in_fifo);
+		`ASSERT(f_fill >= 1);
+		if (!lcl_rd_empty)
+			`ASSERT(lcl_rd_data == f_next);
+		end
+	endcase
+	// }}}
+
+	generate if (OPT_REGISTER_READS)
+	begin
+		reg	past_o_rd_empty;
+
+		always @(posedge gbl_clk)
+			past_o_rd_empty <= o_rd_empty;
+
+		always @(posedge gbl_clk)
+		if (f_past_valid_gbl && i_rd_reset_n)
+		begin
+			if ($past(!o_rd_empty && !i_rd && i_rd_reset_n))
+				`ASSERT($stable(o_rd_data));
+		end
+
+		always @(posedge gbl_clk)
+		if (!f_rd_in_reset && i_rd_reset_n && i_rclk && !past_rclk)
+		begin
+			if (past_o_rd_empty)
+				`ASSERT(o_rd_data == past_rd_data);
+			if (past_rd)
+				`ASSERT(o_rd_data == past_rd_data);
+		end
+
+	end endgenerate
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	cvr_full;
+
+
+	always @(*)
+	if (i_wr_reset_n && i_rd_reset_n)
+	begin
+		cover(o_rd_empty);
+		cover(!o_rd_empty);
+		cover(f_state == 2'b01);
+		cover(f_state == 2'b10);
+		cover(f_state == 2'b11);
+		cover(&f_fill[MSB-1:0]);
+
+		cover(i_rd);
+		cover(i_rd && !o_rd_empty);
+	end
+
+	initial	cvr_full = 1'b0;
+	always @(posedge gbl_clk)
+	if (!i_wr_reset_n)
+		cvr_full <= 1'b0;
+	else if (o_wr_full)
+		cvr_full <= 1'b1;
+
+
+	always @(*)
+	if (f_past_valid_gbl)
+	begin
+		cover(o_wr_full);
+		cover(o_rd_empty && cvr_full);
+		cover(o_rd_empty && f_fill == 0 && cvr_full);
+	end
+
+	// }}}
+`endif
+// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/apbslave.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/apbslave.v
new file mode 100644
index 0000000..173f311
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/apbslave.v
@@ -0,0 +1,217 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	apbslave.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Just a simple demonstration APB slave
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// }}}
+`default_nettype	none
+//
+module	apbslave #(
+		// {{{
+		parameter	C_APB_ADDR_WIDTH = 12,
+		parameter	C_APB_DATA_WIDTH = 32,
+		localparam	AW = C_APB_ADDR_WIDTH,
+		localparam	DW = C_APB_DATA_WIDTH,
+		localparam	APBLSB = $clog2(C_APB_DATA_WIDTH)-3
+		// }}}
+	) (
+		// {{{
+		input	wire			PCLK, PRESETn,
+		input	wire			PSEL,
+		input	wire			PENABLE,
+		output	reg			PREADY,
+		input	wire	[AW-1:0]	PADDR,
+		input	wire			PWRITE,
+		input	wire	[DW-1:0]	PWDATA,
+		input	wire	[DW/8-1:0]	PWSTRB,
+		input	wire	[2:0]		PPROT,
+		output	reg	[DW-1:0]	PRDATA,
+		output	reg			PSLVERR
+		// }}}
+	);
+
+	// Register declarations
+	// {{{
+	// Just our demonstration "memory" here
+	reg	[DW-1:0]	mem	[0:(1<<(AW-APBLSB))-1];
+	integer			ik;
+	// }}}
+
+	// PREADY
+	// {{{
+	initial	PREADY = 1'b0;
+	always @(posedge PCLK)
+	if (!PRESETn)
+		PREADY <= 1'b0;
+	else if (PSEL && !PENABLE)
+		PREADY <= 1'b1;
+	else
+		PREADY <= 1'b0;
+	// }}}
+
+	// mem writes
+	// {{{
+	always @(posedge PCLK)
+	if (PRESETn && PSEL && !PENABLE && PWRITE)
+	begin
+		for(ik=0; ik<DW/8; ik=ik+1)
+		if (PWSTRB[ik])
+			mem[PADDR[AW-1:APBLSB]][8*ik +: 8] <= PWDATA[8*ik +: 8];
+	end
+	// }}}
+
+	// PRDATA, memory reads
+	// {{{
+	always @(posedge PCLK)
+	if (PSEL && !PENABLE && !PWRITE)
+		PRDATA <= mem[PADDR[AW-1:APBLSB]];
+	// }}}
+
+	// PSLVERR -- unused in this design, and so kept at zero
+	// {{{
+	always @(*)
+		PSLVERR = 1'b0;
+	// }}}
+
+	// Make Verilator happy
+	// {{{
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, PADDR[APBLSB-1:0], PPROT };
+	// Verilator lint_on  UNUSED
+	// }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Interface properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	fapb_slave #(.AW(C_APB_ADDR_WIDTH), .DW(C_APB_DATA_WIDTH),
+		.F_OPT_MAXSTALL(1)
+	) fapb (PCLK, PRESETn,
+		PSEL, PENABLE, PREADY, PADDR, PWRITE, PWDATA, PWSTRB,
+		PPROT, PRDATA, PSLVERR);
+
+	always @(*)
+	if (PRESETn && PSEL && PENABLE)
+		assert(PREADY);
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Contract check
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	(* anyconst *)	reg [AW-1:0]	f_addr;
+	reg	[DW-1:0]		f_data;
+
+	initial for(ik=0; ik<(1<<AW); ik=ik+1)
+		mem[ik] = 0;
+
+	initial	f_data = 0;
+	always @(posedge PCLK)
+	if (PRESETn && PSEL && !PENABLE && PWRITE && PADDR[AW-1:APBLSB] == f_addr[AW-1:APBLSB])
+	begin
+		for(ik=0; ik<DW/8; ik=ik+1)
+		if (PWSTRB[ik])
+			f_data[ik*8 +: 8] <= PWDATA[ik*8 +: 8];
+	end
+
+	always @(posedge PCLK)
+	if (PSEL && PENABLE && PREADY && !PWRITE && PADDR[AW-1:APBLSB] == f_addr[AW-1:APBLSB])
+		assert(PRDATA == f_data);
+
+	always @(*)
+		assert(f_data == mem[f_addr[AW-1:APBLSB]]);
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	reg	[2:0]	cvr_reads, cvr_writes, cvr_seq;
+
+	initial	cvr_writes = 0;
+	always @(posedge PCLK)
+	if (!PRESETn)
+		cvr_writes <= 0;
+	else if (PSEL && PENABLE && PREADY && PWRITE && !cvr_writes[2])
+		cvr_writes <= cvr_writes + 1;
+
+	initial	cvr_reads = 0;
+	always @(posedge PCLK)
+	if (!PRESETn)
+		cvr_reads <= 0;
+	else if (PSEL && PENABLE && PREADY && !PWRITE && !cvr_reads[2])
+		cvr_reads <= cvr_reads + 1;
+
+	always @(*)
+		cover(cvr_writes[2]);
+
+	always @(*)
+		cover(cvr_reads[2]);
+
+	initial	cvr_seq = 0;
+	always @(posedge PCLK)
+	if (!PRESETn)
+		cvr_seq <= 0;
+	else if (PSEL && PENABLE && PREADY && !PWRITE && PADDR == f_addr)
+	begin
+		if (cvr_seq == 0 && PRDATA == 32'h12345678)
+			cvr_seq[0] <= 1'b1;
+		if (cvr_seq[0] && PRDATA == 32'h87654321)
+			cvr_seq[1] <= 1'b1;
+		if (cvr_seq[1] && PRDATA == 32'h0)
+			cvr_seq[2] <= 1'b1;
+	end
+
+	always @(*)
+		cover(PRESETn && !PSEL && !PENABLE && cvr_seq[2]);
+	// }}}
+`endif
+// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axi2axi3.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axi2axi3.v
new file mode 100644
index 0000000..aeeb6a3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axi2axi3.v
@@ -0,0 +1,893 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axi2axi3.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Bridge from an AXI4 slave to an AXI3 master
+//
+//	The goal here is to not lose bus resolution, capacity or capability,
+//	while bridging from AXI4 to AXI3.  The biggest problem with such
+//	a bridge is that we'll need to break large requests (AxLEN>15) up
+//	into smaller packets.  After that, everything should work as normal
+//	with only minor modifications for AxCACHE.
+//
+// Opportunity:
+//	The cost of this core is very much determined by the number of ID's
+//	supported.  It should be possible, with little extra cost or effort,
+//	to reduce the ID space herein.  This should be a topic for future
+//	exploration.
+//
+// Status:
+//	This core is an unverified first draft.  It has past neither formal
+//	nor simulation testing.  Therefore, it is almost certain to have bugs
+//	within it.  Use it at your own risk.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+//
+module	axi2axi3 #(
+		parameter	C_AXI_ID_WIDTH = 1,
+		parameter	C_AXI_ADDR_WIDTH = 32,
+		parameter	C_AXI_DATA_WIDTH = 32,
+		//
+		localparam	ADDRLSB= $clog2(C_AXI_DATA_WIDTH)-3
+	) (
+		input	wire				S_AXI_ACLK,
+		input	wire				S_AXI_ARESETN,
+		//
+		// The AXI4 incoming/slave interface
+		input	reg				S_AXI_AWVALID,
+		output	wire				S_AXI_AWREADY,
+		input	reg	[C_AXI_ID_WIDTH-1:0]	S_AXI_AWID,
+		input	reg	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_AWADDR,
+		input	reg	[7:0]			S_AXI_AWLEN,
+		input	reg	[2:0]			S_AXI_AWSIZE,
+		input	reg	[1:0]			S_AXI_AWBURST,
+		input	reg				S_AXI_AWLOCK,
+		input	reg	[3:0]			S_AXI_AWCACHE,
+		input	reg	[2:0]			S_AXI_AWPROT,
+		input	reg	[3:0]			S_AXI_AWQOS,
+		//
+		//
+		input	wire				S_AXI_WVALID,
+		output	wire				S_AXI_WREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]	S_AXI_WDATA,
+		input	wire [C_AXI_DATA_WIDTH/8-1:0]	S_AXI_WSTRB,
+		input	wire				S_AXI_WLAST,
+		//
+		//
+		output	wire				S_AXI_BVALID,
+		input	wire				S_AXI_BREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_BID,
+		output	wire	[1:0]			S_AXI_BRESP,
+		//
+		//
+		input	wire				S_AXI_ARVALID,
+		output	wire				S_AXI_ARREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_ARID,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_ARADDR,
+		input	wire	[7:0]			S_AXI_ARLEN,
+		input	wire	[2:0]			S_AXI_ARSIZE,
+		input	wire	[1:0]			S_AXI_ARBURST,
+		input	wire				S_AXI_ARLOCK,
+		input	wire	[3:0]			S_AXI_ARCACHE,
+		input	wire	[2:0]			S_AXI_ARPROT,
+		input	wire	[3:0]			S_AXI_ARQOS,
+		//
+		output	wire				S_AXI_RVALID,
+		input	wire				S_AXI_RREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_RID,
+		output	wire	[C_AXI_DATA_WIDTH-1:0]	S_AXI_RDATA,
+		output	wire				S_AXI_RLAST,
+		output	wire	[1:0]			S_AXI_RRESP,
+		//
+		//
+		// The AXI3 Master (outgoing) interface
+		output	wire				M_AXI_AWVALID,
+		input	wire				M_AXI_AWREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_AWID,
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_AWADDR,
+		output	wire	[3:0]			M_AXI_AWLEN,
+		output	wire	[2:0]			M_AXI_AWSIZE,
+		output	wire	[1:0]			M_AXI_AWBURST,
+		output	wire	[1:0]			M_AXI_AWLOCK,
+		output	wire	[3:0]			M_AXI_AWCACHE,
+		output	wire	[2:0]			M_AXI_AWPROT,
+		output	wire	[3:0]			M_AXI_AWQOS,
+		//
+		//
+		output	wire				M_AXI_WVALID,
+		input	wire				M_AXI_WREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_WID,
+		output	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_WDATA,
+		output	wire [C_AXI_DATA_WIDTH/8-1:0]	M_AXI_WSTRB,
+		output	wire				M_AXI_WLAST,
+		//
+		//
+		input	wire				M_AXI_BVALID,
+		output	wire				M_AXI_BREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_BID,
+		input	wire	[1:0]			M_AXI_BRESP,
+		//
+		//
+		output	wire				M_AXI_ARVALID,
+		input	wire				M_AXI_ARREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_ARID,
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_ARADDR,
+		output	wire	[3:0]			M_AXI_ARLEN,
+		output	wire	[2:0]			M_AXI_ARSIZE,
+		output	wire	[1:0]			M_AXI_ARBURST,
+		output	wire	[1:0]			M_AXI_ARLOCK,
+		output	wire	[3:0]			M_AXI_ARCACHE,
+		output	wire	[2:0]			M_AXI_ARPROT,
+		output	wire	[3:0]			M_AXI_ARQOS,
+		//
+		input	wire				M_AXI_RVALID,
+		output	wire				M_AXI_RREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_RID,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_RDATA,
+		input	wire				M_AXI_RLAST,
+		input	wire	[1:0]			M_AXI_RRESP
+	);
+
+	localparam	[0:0]	OPT_LOWPOWER = 1'b0;
+	localparam		LGWFIFO = 4;
+	localparam		NID = (1<<C_AXI_ID_WIDTH);
+	parameter		LGFIFO = 8;
+
+	genvar	ID;
+
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	//
+	// WRITE SIDE
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write address channel
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	[7:0]			r_awlen;
+	reg	[3:0]			next_wlen;
+	wire				awskd_valid;
+	reg				awskd_ready;
+	wire	[C_AXI_ID_WIDTH-1:0]	awskd_id;
+	wire	[C_AXI_ADDR_WIDTH-1:0]	awskd_addr;
+	wire	[7:0]			awskd_len;
+	wire	[2:0]			awskd_size;
+	wire	[1:0]			awskd_burst;
+	wire				awskd_lock;
+	wire	[3:0]			awskd_cache;
+	wire	[2:0]			awskd_prot;
+	wire	[3:0]			awskd_qos;
+	reg				axi_awvalid;
+	reg	[C_AXI_ID_WIDTH-1:0]	axi_awid;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	axi_awaddr;
+	reg	[3:0]			axi_awlen;
+	reg	[2:0]			axi_awsize;
+	reg	[1:0]			axi_awburst;
+	reg	[1:0]			axi_awlock;
+	reg	[3:0]			axi_awcache;
+	reg	[2:0]			axi_awprot;
+	reg	[3:0]			axi_awqos;
+
+	skidbuffer #(
+		.DW(C_AXI_ADDR_WIDTH + C_AXI_ID_WIDTH + 8 + 3 + 2 + 1+4+3+4),
+		.OPT_OUTREG(1'b0)
+	) awskid (
+		.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_valid(S_AXI_AWVALID), .o_ready(S_AXI_AWREADY),
+			.i_data({ S_AXI_AWID, S_AXI_AWADDR,  S_AXI_AWLEN,
+				S_AXI_AWSIZE, S_AXI_AWBURST, S_AXI_AWLOCK,
+				S_AXI_AWCACHE,  S_AXI_AWPROT,  S_AXI_AWQOS }),
+		.o_valid(awskd_valid), .i_ready(awskd_ready),
+			.o_data({ awskd_id,  awskd_addr,  awskd_len,
+				awskd_size,  awskd_burst, awskd_lock,
+				awskd_cache, awskd_prot,  awskd_qos })
+	);
+
+	always @(*)
+	begin
+		awskd_ready = 1;
+		if (r_awlen > 0)
+			awskd_ready = 0;
+		if (M_AXI_AWVALID && M_AXI_AWREADY)
+			awskd_ready = 0;
+		if (|wfifo_fill[LGWFIFO:LGWFIFO-1])
+			awskd_ready = 0;
+	end
+
+	initial	axi_awvalid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_awvalid <= 0;
+	else if (awskd_valid || r_awlen > 0)
+		axi_awvalid <= 1;
+	else if (M_AXI_AWREADY)
+		axi_awvalid <= 0;
+
+	initial	r_awlen = 0;
+	initial	axi_awlen = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		r_awlen <= 0;
+		axi_awlen <= 0;
+	end else if (!M_AXI_AWVALID || M_AXI_AWREADY)
+	begin
+		if (r_awlen > 15)
+		begin
+			axi_awlen <= 4'd15;
+			r_awlen <= r_awlen - 8'd16;
+		end else if (r_awlen > 0)
+		begin
+			axi_awlen[3:0] <= r_awlen[3:0] - 1;
+			r_awlen <= 0;
+		end else if (awskd_valid)
+		begin
+			if (awskd_len > 15)
+			begin
+				r_awlen <= awskd_len + 1'b1 - 8'd16;
+				axi_awlen <= 4'd15;
+			end else begin
+				r_awlen <= 0;
+				axi_awlen <= awskd_len[3:0];
+			end
+		end else begin
+			r_awlen <= 0;
+			axi_awlen <= 0;
+		end
+	end
+
+
+	always @(posedge S_AXI_ACLK)
+	if (awskd_valid && awskd_ready)
+		axi_awaddr <= awskd_addr;
+	else if (M_AXI_AWVALID && M_AXI_AWREADY)
+	begin
+		// Verilator lint_off WIDTH
+		axi_awaddr <= axi_awaddr + ((M_AXI_AWLEN + 1) << M_AXI_AWSIZE);
+		// Verilator lint_on  WIDTH
+
+		case(M_AXI_AWSIZE)
+		3'b000: begin end
+		3'b001: axi_awaddr[  0] <= 0;
+		3'b010: axi_awaddr[1:0] <= 0;
+		3'b011: axi_awaddr[2:0] <= 0;
+		3'b100: axi_awaddr[3:0] <= 0;
+		3'b101: axi_awaddr[4:0] <= 0;
+		3'b110: axi_awaddr[5:0] <= 0;
+		3'b111: axi_awaddr[6:0] <= 0;
+		endcase
+	end
+
+
+	initial	M_AXI_AWSIZE = ADDRLSB[2:0];
+	always @(posedge S_AXI_ACLK)
+	begin
+		if (awskd_valid && awskd_ready)
+		begin
+			axi_awid     <= awskd_id;
+			axi_awsize   <= awskd_size;
+			axi_awburst  <= awskd_burst;
+			axi_awlock[0]<=awskd_lock;
+			axi_awcache  <= awskd_cache;
+			axi_awprot   <= awskd_prot;
+			axi_awqos    <= awskd_qos;
+		end
+
+		if (C_AXI_DATA_WIDTH < 16)
+			axi_awsize <= 3'b000;
+		else if (C_AXI_DATA_WIDTH < 32)
+			axi_awsize[2:1] <= 2'b00;
+		else if (C_AXI_DATA_WIDTH < 128)
+			axi_awsize[2] <= 1'b0;
+
+		axi_awlock[1] <= 1'b0;
+	end
+
+	assign	M_AXI_AWVALID = axi_awvalid;
+	assign	M_AXI_AWID    = axi_awid;
+	assign	M_AXI_AWADDR  = axi_awaddr;
+	assign	M_AXI_AWLEN   = axi_awlen;
+	assign	M_AXI_AWSIZE  = axi_awsize;
+	assign	M_AXI_AWBURST = axi_awburst;
+	assign	M_AXI_AWLOCK  = axi_awlock;
+	assign	M_AXI_AWCACHE = axi_awcache;
+	assign	M_AXI_AWPROT  = axi_awprot;
+	assign	M_AXI_AWQOS   = axi_awqos;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write data channel
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	wire				wskd_valid;
+	reg				wskd_ready, write_idle;
+	wire	[C_AXI_DATA_WIDTH-1:0]	wskd_data;
+	wire [C_AXI_DATA_WIDTH/8-1:0]	wskd_strb;
+	wire 				wskd_last;
+	reg	[4:0]			r_wlen;
+	wire	[C_AXI_ID_WIDTH-1:0]	wfifo_id,   raw_wfifo_id;
+	wire	[3:0]			wfifo_wlen, raw_wfifo_wlen;
+	reg				next_wlast, r_wlast;
+	wire				raw_wfifo_last;
+	wire				wfifo_empty, wfifo_full;
+	wire	[LGWFIFO:0]		wfifo_fill;
+	reg				axi_wvalid;
+	reg	[C_AXI_DATA_WIDTH-1:0]	axi_wdata;
+	reg [C_AXI_DATA_WIDTH/8-1:0]	axi_wstrb;
+	reg	[C_AXI_ID_WIDTH-1:0]	axi_wid;
+	reg				axi_wlast;
+
+	skidbuffer #(
+		.DW(C_AXI_DATA_WIDTH + (C_AXI_DATA_WIDTH/8) + 1),
+		.OPT_OUTREG(1'b0)
+	) wskid (
+		.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_valid(S_AXI_WVALID), .o_ready(S_AXI_WREADY),
+			.i_data({ S_AXI_WDATA, S_AXI_WSTRB,  S_AXI_WLAST }),
+		.o_valid(wskd_valid), .i_ready(wskd_ready),
+			.o_data({ wskd_data,  wskd_strb,  wskd_last })
+	);
+
+	always @(*)
+		wskd_ready = !M_AXI_WVALID || M_AXI_WREADY;
+
+	initial	axi_wvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_wvalid <= 0;
+	else if (wskd_valid)
+		axi_wvalid <= 1;
+	else if (M_AXI_WREADY)
+		axi_wvalid <= 0;
+
+	initial	write_idle = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		write_idle <= 1;
+	else if (M_AXI_WVALID && M_AXI_WREADY && M_AXI_WLAST && !wskd_valid)
+		write_idle <= 1;
+	else if (wskd_valid && wskd_ready)
+		write_idle <= 0;
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN && OPT_LOWPOWER)
+	begin
+		axi_wdata <= 0;
+		axi_wstrb <= 0;
+	end else if (!M_AXI_WVALID || M_AXI_WREADY)
+	begin
+		axi_wdata <= wskd_data;
+		axi_wstrb <= wskd_strb;
+
+		if (OPT_LOWPOWER && !wskd_valid)
+		begin
+			axi_wdata <= 0;
+			axi_wstrb <= 0;
+		end
+	end
+
+	always @(*)
+	begin
+		if (r_awlen[7:4] != 0)
+			next_wlen = 4'd15;
+		else if (r_awlen[3:0] != 0)
+			next_wlen = r_awlen[3:0];
+		else if (awskd_len[7:4] != 0)
+			next_wlen = 4'd15;
+		else
+			next_wlen = awskd_len[3:0];
+
+		if (r_awlen != 0)
+			next_wlast = (r_awlen[7:4] == 0);
+		else
+			next_wlast = (awskd_len[7:4] == 0);
+	end
+
+	sfifo #(.BW(C_AXI_ID_WIDTH+4+1), .LGFLEN(LGWFIFO))
+	wfifo(S_AXI_ACLK, !S_AXI_ARESETN,
+		(!M_AXI_AWVALID || M_AXI_AWREADY)&&(awskd_valid||(r_awlen > 0))
+			&& !write_idle,
+		// The length of the next burst
+		{ ((r_awlen != 0) ? M_AXI_AWID : awskd_id),
+						next_wlen, next_wlast },
+		wfifo_full, wfifo_fill,
+		//
+		(!M_AXI_WVALID || M_AXI_WREADY),
+		{ raw_wfifo_id, raw_wfifo_wlen, raw_wfifo_last },
+		wfifo_empty);
+
+	assign	wfifo_id   = (wfifo_empty) ? awskd_id  : raw_wfifo_id;
+	assign	wfifo_wlen = (wfifo_empty) ? next_wlen : raw_wfifo_wlen;
+
+	initial	r_wlen = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN && OPT_LOWPOWER)
+		r_wlen <= 0;
+	else if (!M_AXI_WVALID || M_AXI_WREADY)
+	begin
+		if (r_wlen > 1)
+			r_wlen <= r_wlen - 1;
+		else if (!wfifo_empty)
+			r_wlen <= raw_wfifo_wlen + 1;
+		else if (awskd_valid && awskd_ready)
+			r_wlen <= next_wlen + 1;
+	end
+
+	initial	r_wlast = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN && OPT_LOWPOWER)
+		r_wlast <= 0;
+	else if (!M_AXI_WVALID || M_AXI_WREADY)
+	begin
+		if (r_wlen > 0)
+			r_wlast <= (r_wlen <= 1);
+		else
+			r_wlast <= raw_wfifo_last;
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN && OPT_LOWPOWER)
+	begin
+		axi_wid   <= 0;
+		axi_wlast <= 0;
+	end else if (!M_AXI_WVALID || M_AXI_WREADY)
+	begin
+		axi_wid   <= wfifo_id;
+		axi_wlast <= r_wlast;
+
+		if (OPT_LOWPOWER && !wskd_valid)
+		begin
+			axi_wid   <= 0;
+			axi_wlast <= 0;
+		end
+	end
+
+	assign	M_AXI_WVALID = axi_wvalid;
+	assign	M_AXI_WDATA  = axi_wdata;
+	assign	M_AXI_WSTRB  = axi_wstrb;
+	assign	M_AXI_WID    = axi_wid;
+	assign	M_AXI_WLAST  = axi_wlast;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write return channel
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	wire				bskd_valid;
+	reg				bskd_ready;
+	wire	[C_AXI_ID_WIDTH-1:0]	bskd_id;
+	wire	[1:0]			bskd_resp;
+	reg	[1:0]			bburst_err	[0:NID-1];
+	reg	[NID-1:0]		wbfifo_valid;
+	reg	[NID-1:0]		wbfifo_last;
+	reg				axi_bvalid;
+	reg	[C_AXI_ID_WIDTH-1:0]	axi_bid;
+	reg	[1:0]			axi_bresp;
+
+	skidbuffer #(.DW(C_AXI_ID_WIDTH + 2), .OPT_OUTREG(1'b0)
+	) bskid (
+		.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_valid(M_AXI_BVALID), .o_ready(M_AXI_BREADY),
+			.i_data({ M_AXI_BID, M_AXI_BRESP }),
+		.o_valid(bskd_valid), .i_ready(bskd_ready),
+			.o_data({ bskd_id, bskd_resp })
+	);
+
+	generate for(ID=0; ID < NID; ID = ID + 1)
+	begin : WRITE_BURST_TRACKING
+		wire			wbfifo_empty, wbfifo_full;
+		wire	[LGFIFO:0]	wbfifo_fill;
+
+		initial	wbfifo_valid[ID] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			wbfifo_valid[ID] <= 0;
+		else if (!wbfifo_valid[ID] && !wbfifo_empty)
+			wbfifo_valid[ID] <= 1;
+		else if (bskd_valid && bskd_ready && bskd_id==ID)
+			wbfifo_valid[ID] <= !wbfifo_empty;
+
+		sfifo #(.BW(1), .LGFLEN(LGFIFO))
+		wbfifo(S_AXI_ACLK, !S_AXI_ARESETN,
+			(M_AXI_WVALID && M_AXI_WREADY && M_AXI_WLAST)
+				&& (M_AXI_WID == ID),
+			(r_wlen == 0) ? 1'b1 : 1'b0,
+			wbfifo_full, wbfifo_fill,
+			//
+			(!wbfifo_valid[ID] || (M_AXI_BVALID && M_AXI_BREADY
+					&& M_AXI_BID == ID)),
+			wbfifo_last[ID], wbfifo_empty
+		);
+
+		// Verilator lint_off UNUSED
+		wire	unused;
+		assign	unused = &{ 1'b0, wbfifo_full, wbfifo_fill };
+		// Verilator lint_on  UNUSED
+
+	end endgenerate
+
+	always @(*)
+		bskd_ready = (!S_AXI_BVALID || S_AXI_BREADY);
+
+	initial	axi_bvalid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_bvalid <= 1'b0;
+	else if (bskd_valid && bskd_ready)
+		axi_bvalid <= wbfifo_last[bskd_id];
+	else if (M_AXI_BREADY)
+		axi_bvalid <= 1'b0;
+
+	generate for(ID=0; ID < NID; ID = ID + 1)
+	begin : WRITE_ERR_BY_ID
+
+		initial	bburst_err[ID] = 2'b0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			bburst_err[ID] <= 2'b0;
+		else if (S_AXI_BVALID && S_AXI_BREADY && S_AXI_BID == ID
+				&& wbfifo_last[ID])
+			bburst_err[ID] <= 2'b0;
+		else if (bskd_valid && bskd_id == ID)
+			bburst_err[ID] <= bburst_err[ID] | bskd_resp;
+
+	end endgenerate
+
+	initial	axi_bid   = 0;
+	initial	axi_bresp = 0;
+	always @(posedge S_AXI_ACLK)
+	if (OPT_LOWPOWER && !S_AXI_ARESETN)
+	begin
+		axi_bid   <= 0;
+		axi_bresp <= 0;
+	end else if (!S_AXI_BVALID || S_AXI_BREADY)
+	begin
+		axi_bid   <= bskd_id;
+		axi_bresp <= bskd_resp | bburst_err[bskd_id];
+
+		if (OPT_LOWPOWER && !bskd_valid)
+		begin
+			axi_bid   <= 0;
+			axi_bresp <= 0;
+		end
+	end
+
+	assign	S_AXI_BVALID = axi_bvalid;
+	assign	S_AXI_BID    = axi_bid;
+	assign	S_AXI_BRESP  = axi_bresp;
+	// }}}
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	//
+	// READ SIDE
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read address channel
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	[7:0]			r_arlen;
+	wire				arskd_valid;
+	reg				arskd_ready;
+	wire	[C_AXI_ID_WIDTH-1:0]	arskd_id;
+	wire	[C_AXI_ADDR_WIDTH-1:0]	arskd_addr;
+	wire	[7:0]			arskd_len;
+	wire	[2:0]			arskd_size;
+	wire	[1:0]			arskd_burst;
+	wire				arskd_lock;
+	wire	[3:0]			arskd_cache;
+	wire	[2:0]			arskd_prot;
+	wire	[3:0]			arskd_qos;
+	reg				axi_arvalid;
+	reg	[C_AXI_ID_WIDTH-1:0]	axi_arid;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	axi_araddr;
+	reg	[3:0]			axi_arlen;
+	reg	[2:0]			axi_arsize;
+	reg	[1:0]			axi_arburst;
+	reg	[1:0]			axi_arlock;
+	reg	[3:0]			axi_arcache;
+	reg	[2:0]			axi_arprot;
+	reg	[3:0]			axi_arqos;
+
+	skidbuffer #(
+		.DW(C_AXI_ADDR_WIDTH + C_AXI_ID_WIDTH + 8 + 3 + 2 + 1+4+3+4),
+		.OPT_OUTREG(1'b0)
+	) arskid (
+		.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_valid(S_AXI_ARVALID), .o_ready(S_AXI_ARREADY),
+			.i_data({ S_AXI_ARID, S_AXI_ARADDR,  S_AXI_ARLEN,
+				S_AXI_ARSIZE, S_AXI_ARBURST, S_AXI_ARLOCK,
+				S_AXI_ARCACHE,  S_AXI_ARPROT,  S_AXI_ARQOS }),
+		.o_valid(arskd_valid), .i_ready(arskd_ready),
+			.o_data({ arskd_id,  arskd_addr,  arskd_len,
+				arskd_size,  arskd_burst, arskd_lock,
+				arskd_cache, arskd_prot,  arskd_qos })
+	);
+
+	always @(*)
+	begin
+		arskd_ready = 1;
+		if (r_arlen > 0)
+			arskd_ready = 0;
+		if (M_AXI_ARVALID && M_AXI_ARREADY)
+			arskd_ready = 0;
+	end
+
+	initial	axi_arvalid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_arvalid <= 1'b0;
+	else if (r_arlen > 0)
+		axi_arvalid <= 1'b1;
+	else if (arskd_ready)
+		axi_arvalid <= 1'b1;
+	else if (M_AXI_ARREADY)
+		axi_arvalid <= 1'b0;
+
+	initial	r_arlen = 0;
+	initial	M_AXI_ARLEN = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		r_arlen   <= 0;
+		axi_arlen <= 0;
+	end else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+	begin
+		if (r_arlen[7:4] != 0)
+		begin
+			axi_arlen <= 4'd15;
+			r_arlen <= r_arlen - 16;
+		end else if (r_arlen[3:0] != 0)
+		begin
+			axi_arlen <= r_arlen[3:0] - 1;
+			r_arlen <= 0;
+		end else if (arskd_valid)
+		begin
+			if (arskd_len[7:4] != 0)
+			begin
+				r_arlen <= arskd_len + 1 - 16;
+				axi_arlen <= 4'd15;
+			end else begin
+				r_arlen <= 0;
+				axi_arlen <= arskd_len[3:0];
+			end
+		end else begin
+			r_arlen <= 0;
+			axi_arlen <= 0;
+		end
+	end
+
+
+	always @(posedge S_AXI_ACLK)
+	if (arskd_valid && arskd_ready)
+		axi_araddr <= arskd_addr;
+	else if (M_AXI_ARVALID && M_AXI_ARREADY)
+	begin
+		// Verilator lint_off WIDTH
+		axi_araddr <= axi_araddr + ((M_AXI_ARLEN + 1) << M_AXI_ARSIZE);
+		// Verilator lint_on  WIDTH
+
+		case(M_AXI_AWSIZE)
+		3'b000: begin end
+		3'b001: axi_araddr[  0] <= 0;
+		3'b010: axi_araddr[1:0] <= 0;
+		3'b011: axi_araddr[2:0] <= 0;
+		3'b100: axi_araddr[3:0] <= 0;
+		3'b101: axi_araddr[4:0] <= 0;
+		3'b110: axi_araddr[5:0] <= 0;
+		3'b111: axi_araddr[6:0] <= 0;
+		endcase
+	end
+
+	initial	axi_arsize = ADDRLSB[2:0];
+	always @(posedge S_AXI_ACLK)
+	begin
+		if (arskd_valid && arskd_ready)
+		begin
+			axi_arid      <= arskd_id;
+			axi_arsize    <= arskd_size;
+			axi_arburst   <= arskd_burst;
+			axi_arlock[0] <= arskd_lock;
+			axi_arcache   <= arskd_cache;
+			axi_arprot    <= arskd_prot;
+			axi_arqos     <= arskd_qos;
+		end
+
+		// Propagate constants, to help the optimizer out out a touch
+		axi_arlock[1] <= 1'b0;
+
+		if (C_AXI_DATA_WIDTH < 16)
+			axi_arsize <= 3'b000;
+		else if (C_AXI_DATA_WIDTH < 32)
+			axi_arsize[2:1] <= 2'b00;
+		else if (C_AXI_DATA_WIDTH < 128)
+			axi_arsize[2] <= 1'b0;
+	end
+
+	generate for(ID=0; ID < NID; ID = ID + 1)
+	begin : READ_BURST_TRACKING
+		wire			rbfifo_empty, rbfifo_full;
+		wire	[LGFIFO:0]	rbfifo_fill;
+
+		initial	rbfifo_valid[ID] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			rbfifo_valid[ID] <= 0;
+		else if (!rbfifo_valid[ID] && !rbfifo_empty)
+			rbfifo_valid[ID] <= 1;
+		else if (rskd_valid && rskd_ready && rskd_last && rskd_id==ID)
+			rbfifo_valid[ID] <= !rbfifo_empty;
+
+		sfifo #(.BW(1), .LGFLEN(LGFIFO))
+		rbfifo(S_AXI_ACLK, !S_AXI_ARESETN,
+			(!M_AXI_ARVALID || M_AXI_ARREADY)
+				&& (((r_arlen>0)&&(M_AXI_ARID==ID))
+					|| (arskd_valid && arskd_id == ID)),
+			((arskd_valid && arskd_ready && arskd_len <= 15)
+				||(r_arlen <= 15)) ? 1'b1 : 1'b0,
+			rbfifo_full, rbfifo_fill,
+			//
+			(!rbfifo_valid[ID] || (M_AXI_RVALID && M_AXI_RREADY
+					&& M_AXI_RID == ID && M_AXI_RLAST)),
+			rid_last[ID], rbfifo_empty
+		);
+
+		// Verilator lint_off UNUSED
+		wire	unused;
+		assign	unused = &{ 1'b0, rbfifo_full, rbfifo_fill };
+		// Verilator lint_on  UNUSED
+	end endgenerate
+
+	assign	M_AXI_ARVALID= axi_arvalid;
+	assign	M_AXI_ARID   = axi_arid;
+	assign	M_AXI_ARADDR = axi_araddr;
+	assign	M_AXI_ARLEN  = axi_arlen;
+	assign	M_AXI_ARSIZE = axi_arsize;
+	assign	M_AXI_ARBURST= axi_arburst;
+	assign	M_AXI_ARLOCK = axi_arlock;
+	assign	M_AXI_ARCACHE= axi_arcache;
+	assign	M_AXI_ARPROT = axi_arprot;
+	assign	M_AXI_ARQOS  = axi_arqos;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read data channel
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	wire				rskd_valid;
+	reg				rskd_ready;
+	wire	[C_AXI_ID_WIDTH-1:0]	rskd_id;
+	wire	[C_AXI_DATA_WIDTH-1:0]	rskd_data;
+	wire				rskd_last;
+	wire	[1:0]			rskd_resp;
+	reg	[1:0]			rburst_err	[0:NID-1];
+	reg	[NID-1:0]		rbfifo_valid;
+	reg	[NID-1:0]		rid_last;
+	reg				axi_rvalid;
+	reg	[C_AXI_ID_WIDTH-1:0]	axi_rid;
+	reg	[C_AXI_DATA_WIDTH-1:0]	axi_rdata;
+	reg				axi_rlast;
+	reg	[1:0]			axi_rresp;
+
+	skidbuffer #(
+		.DW(C_AXI_DATA_WIDTH + C_AXI_ID_WIDTH + 3),
+		.OPT_OUTREG(1'b0)
+	) rskid (
+		.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_valid(M_AXI_RVALID), .o_ready(M_AXI_RREADY),
+			.i_data({ M_AXI_RID, M_AXI_RDATA,  M_AXI_RLAST,
+				M_AXI_RRESP }),
+		.o_valid(rskd_valid), .i_ready(rskd_ready),
+			.o_data({ rskd_id,  rskd_data,  rskd_last, rskd_resp })
+	);
+
+	always @(*)
+		rskd_ready = !S_AXI_RVALID || S_AXI_RREADY;
+
+	initial	axi_rvalid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_rvalid <= 1'b0;
+	else if (rskd_valid && rskd_ready)
+		axi_rvalid <= 1'b1;
+	else if (S_AXI_RREADY)
+		axi_rvalid <= 1'b0;
+
+	generate for(ID=0; ID < NID; ID = ID + 1)
+	begin : READ_ERR_BY_ID
+
+		initial	rburst_err[ID] = 2'b0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			rburst_err[ID] <= 2'b0;
+		else if (S_AXI_RVALID && S_AXI_RREADY && S_AXI_RLAST
+				&& S_AXI_RID == ID)
+			rburst_err[ID] <= 2'b0;
+		else if (rskd_valid && rskd_id == ID)
+			rburst_err[ID] <= rburst_err[ID] | rskd_resp;
+
+	end endgenerate
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_RVALID || S_AXI_RREADY)
+	begin
+		axi_rid   <= rskd_id;
+		axi_rdata <= rskd_data;
+		axi_rresp <= rskd_resp | rburst_err[rskd_id];
+		axi_rlast <= rid_last[rskd_id] && rskd_last;
+	end
+
+	assign	S_AXI_RVALID= axi_rvalid;
+	assign	S_AXI_RID   = axi_rid;
+	assign	S_AXI_RDATA = axi_rdata;
+	assign	S_AXI_RRESP = axi_rresp;
+	assign	S_AXI_RLAST = axi_rlast;
+	// }}}
+	// }}}
+	// Make Verilator happy
+	// {{{
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, wfifo_fill[LGWFIFO-2:0], wskd_last,
+			wfifo_wlen, wfifo_full };
+	// Verilator lint_on UNUSED
+	// }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal property section
+//
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+//
+// This design has not been formally verified.
+//
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axi2axilite.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axi2axilite.v
new file mode 100644
index 0000000..9b2b54b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axi2axilite.v
@@ -0,0 +1,1085 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axi2axilite.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Convert from AXI to AXI-lite with no performance loss.
+//
+// Performance:	The goal of this converter is to convert from AXI to AXI-lite
+//		while still maintaining the one-clock per transaction speed
+//	of AXI.  It currently achieves this goal.  The design needs very little
+//	configuration to be useful, but you might wish to resize the FIFOs
+//	within depending upon the length of your slave's data path.  The current
+//	FIFO length, LGFIFO=4, is sufficient to maintain full speed.  If the
+//	slave, however, can maintain full speed but requires a longer
+//	processing cycle, then you may need longer FIFOs.
+//
+//	The AXI specification does require an additional 2 clocks per
+//	transaction when using this core, so your latency will go up.
+//
+// Related:	There's a related axidouble.v core in the same repository as
+//		well.  That can be used to convert the AXI protocol to something
+//	simpler (even simpler than AXI-lite), but it can also do so for multiple
+//	downstream slaves at the same time.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// }}}
+module axi2axilite #(
+		// {{{
+		parameter integer C_AXI_ID_WIDTH	= 2,
+		parameter integer C_AXI_DATA_WIDTH	= 32,
+		parameter integer C_AXI_ADDR_WIDTH	= 6,
+		parameter	 [0:0]	OPT_WRITES	= 1,
+		parameter	 [0:0]	OPT_READS	= 1,
+		// Log (based two) of the maximum number of outstanding AXI
+		// (not AXI-lite) transactions.  If you multiply 2^LGFIFO * 256,
+		// you'll get the maximum number of outstanding AXI-lite
+		// transactions
+		parameter	LGFIFO			= 4
+		// }}}
+	) (
+		// {{{
+		input	wire	S_AXI_ACLK,
+		input	wire	S_AXI_ARESETN,
+		// AXI4 slave interface
+		// {{{
+		// Write address channel
+		// {{{
+		input	wire				S_AXI_AWVALID,
+		output	wire				S_AXI_AWREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_AWID,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_AWADDR,
+		input	wire	[7:0]			S_AXI_AWLEN,
+		input	wire	[2:0]			S_AXI_AWSIZE,
+		input	wire	[1:0]			S_AXI_AWBURST,
+		input	wire				S_AXI_AWLOCK,
+		input	wire	[3:0]			S_AXI_AWCACHE,
+		input	wire	[2:0]			S_AXI_AWPROT,
+		input	wire	[3:0]			S_AXI_AWQOS,
+		// }}}
+		// Write data channel
+		// {{{
+		input	wire				S_AXI_WVALID,
+		output	wire				S_AXI_WREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]	S_AXI_WDATA,
+		input	wire	[(C_AXI_DATA_WIDTH/8)-1:0] S_AXI_WSTRB,
+		input	wire				S_AXI_WLAST,
+		// }}}
+		// Write return channel
+		// {{{
+		output	wire				S_AXI_BVALID,
+		input	wire				S_AXI_BREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_BID,
+		output	wire	[1:0]			S_AXI_BRESP,
+		// }}}
+		// Read address channel
+		// {{{
+		input	wire				S_AXI_ARVALID,
+		output	wire				S_AXI_ARREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_ARID,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_ARADDR,
+		input	wire	[7:0]			S_AXI_ARLEN,
+		input	wire	[2:0]			S_AXI_ARSIZE,
+		input	wire	[1:0]			S_AXI_ARBURST,
+		input	wire				S_AXI_ARLOCK,
+		input	wire	[3:0]			S_AXI_ARCACHE,
+		input	wire	[2:0]			S_AXI_ARPROT,
+		input	wire	[3:0]			S_AXI_ARQOS,
+		// }}}
+		// Read data channel
+		// {{{
+		output	wire				S_AXI_RVALID,
+		input	wire				S_AXI_RREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0] S_AXI_RID,
+		output	wire	[C_AXI_DATA_WIDTH-1:0] S_AXI_RDATA,
+		output	wire	[1:0]			S_AXI_RRESP,
+		output	wire				S_AXI_RLAST,
+		// }}}
+		// }}}
+		// AXI-lite master interface
+		// {{{
+		// AXI-lite Write interface
+		// {{{
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_AWADDR,
+		output	wire	[2 : 0]			M_AXI_AWPROT,
+		output	wire				M_AXI_AWVALID,
+		input	wire				M_AXI_AWREADY,
+		output	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_WDATA,
+		output	wire	[(C_AXI_DATA_WIDTH/8)-1:0] M_AXI_WSTRB,
+		output	wire				M_AXI_WVALID,
+		input	wire				M_AXI_WREADY,
+		input	wire	[1 : 0]			M_AXI_BRESP,
+		input	wire				M_AXI_BVALID,
+		output	wire				M_AXI_BREADY,
+		// }}}
+		// AXI-lite read interface
+		// {{{
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_ARADDR,
+		output	wire	[2:0]			M_AXI_ARPROT,
+		output	wire				M_AXI_ARVALID,
+		input	wire				M_AXI_ARREADY,
+		//
+		input	wire				M_AXI_RVALID,
+		output	wire				M_AXI_RREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1 : 0] M_AXI_RDATA,
+		input	wire	[1 : 0]			M_AXI_RRESP
+		// }}}
+		// }}}
+		// }}}
+	);
+
+	// Local parameters, register, and net declarations
+	// {{{
+	localparam [1:0]	OKAY = 2'b00,
+				EXOKAY = 2'b01,
+				SLVERR = 2'b10,
+				DECERR = 2'b10;
+	localparam	AW = C_AXI_ADDR_WIDTH;
+	localparam	DW = C_AXI_DATA_WIDTH;
+	localparam	IW = C_AXI_ID_WIDTH;
+	localparam	LSB = $clog2(C_AXI_DATA_WIDTH)-3;
+
+	//
+	// Write registers
+	reg				m_axi_awvalid, s_axi_wready;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	axi_awaddr;
+	reg	[7:0]			axi_awlen, axi_blen;
+	reg	[1:0]			axi_awburst;
+	reg	[2:0]			axi_awsize;
+	wire	[C_AXI_ADDR_WIDTH-1:0]	next_write_addr;
+	wire	[4:0]			wfifo_count;
+	wire				wfifo_full;
+	wire				wfifo_empty;
+	wire	[7:0]			wfifo_bcount;
+	wire	[IW-1:0]		wfifo_bid;
+	reg	[8:0]			bcounts;
+	reg	[C_AXI_ID_WIDTH-1:0]	axi_bid, bid;
+	reg	[1:0]			axi_bresp;
+	reg				s_axi_bvalid;
+	wire				read_from_wrfifo;
+	//
+	// Read register
+	reg				m_axi_arvalid;
+	wire	[4:0]			rfifo_count;
+	wire				rfifo_full;
+	wire				rfifo_empty;
+	wire	[7:0]			rfifo_rcount;
+	reg				s_axi_rvalid;
+	reg	[1:0]			s_axi_rresp;
+	reg	[8:0]			rcounts;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	axi_araddr;
+	reg	[7:0]			axi_arlen, axi_rlen;
+	reg	[1:0]			axi_arburst;
+	reg	[2:0]			axi_arsize;
+	wire	[C_AXI_ADDR_WIDTH-1:0]	next_read_addr;
+	reg	[C_AXI_ID_WIDTH-1:0]	s_axi_rid;
+	wire	[C_AXI_ID_WIDTH-1:0]	rfifo_rid;
+	reg	[C_AXI_DATA_WIDTH-1:0]	s_axi_rdata;
+	reg				s_axi_rlast;
+	reg	[IW-1:0]		rid;
+	wire				read_from_rdfifo;
+
+	//
+	// S_AXI_AW* skid buffer
+	wire			skids_awvalid, skids_awready;
+	wire	[IW-1:0]	skids_awid;
+	wire	[AW-1:0]	skids_awaddr;
+	wire	[7:0]		skids_awlen;
+	wire	[2:0]		skids_awsize;
+	wire	[1:0]		skids_awburst;
+	//
+	// S_AXI_W* skid buffer
+	wire			skids_wvalid, skids_wready, skids_wlast;
+	wire	[DW-1:0]	skids_wdata;
+	wire	[DW/8-1:0]	skids_wstrb;
+	//
+	// S_AXI_B* skid buffer isn't needed
+	//
+	// M_AXI_AW* skid buffer isn't needed
+	//
+	// M_AXI_W* skid buffer
+	wire			skidm_wvalid, skidm_wready;
+	wire	[DW-1:0]	skidm_wdata;
+	wire	[DW/8-1:0]	skidm_wstrb;
+	//
+	// M_AXI_B* skid buffer
+	wire			skidm_bvalid, skidm_bready;
+	wire	[1:0]		skidm_bresp;
+	//
+	//
+	//
+	// S_AXI_AR* skid buffer
+	wire			skids_arvalid, skids_arready;
+	wire	[IW-1:0]	skids_arid;
+	wire	[AW-1:0]	skids_araddr;
+	wire	[7:0]		skids_arlen;
+	wire	[2:0]		skids_arsize;
+	wire	[1:0]		skids_arburst;
+	//
+	// S_AXI_R* skid buffer isn't needed
+	//
+	// M_AXI_AR* skid buffer isn't needed
+	// M_AXI_R* skid buffer
+	wire			skidm_rvalid, skidm_rready;
+	wire	[DW-1:0]	skidm_rdata;
+	wire	[1:0]		skidm_rresp;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write logic
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate if (OPT_WRITES)
+	begin : IMPLEMENT_WRITES
+		// {{{
+		// The write address channel's skid buffer
+		// {{{
+		skidbuffer #(.DW(IW+AW+8+3+2), .OPT_LOWPOWER(0), .OPT_OUTREG(0))
+		awskid(S_AXI_ACLK, !S_AXI_ARESETN,
+			S_AXI_AWVALID, S_AXI_AWREADY,
+			{ S_AXI_AWID, S_AXI_AWADDR, S_AXI_AWLEN, S_AXI_AWSIZE,
+				S_AXI_AWBURST },
+			skids_awvalid, skids_awready,
+			{ skids_awid, skids_awaddr, skids_awlen, skids_awsize,
+				skids_awburst });
+		// }}}
+		//
+		// The write data channel's skid buffer (S_AXI_W*)
+		// {{{
+		skidbuffer #(.DW(DW+DW/8+1), .OPT_LOWPOWER(0), .OPT_OUTREG(0))
+		wskid(S_AXI_ACLK, !S_AXI_ARESETN,
+			S_AXI_WVALID, S_AXI_WREADY,
+			{ S_AXI_WDATA, S_AXI_WSTRB, S_AXI_WLAST },
+			skids_wvalid, skids_wready,
+			{ skids_wdata, skids_wstrb, skids_wlast });
+		// }}}
+		//
+		// The downstream AXI-lite write data (M_AXI_W*) skid buffer
+		// {{{
+		skidbuffer #(.DW(DW+DW/8), .OPT_LOWPOWER(0), .OPT_OUTREG(1))
+		mwskid(S_AXI_ACLK, !S_AXI_ARESETN,
+			skidm_wvalid, skidm_wready, { skidm_wdata, skidm_wstrb },
+			M_AXI_WVALID,M_AXI_WREADY,{ M_AXI_WDATA, M_AXI_WSTRB });
+		// }}}
+		//
+		// The downstream AXI-lite response (M_AXI_B*) skid buffer
+		// {{{
+		skidbuffer #(.DW(2), .OPT_LOWPOWER(0), .OPT_OUTREG(0))
+		bskid(S_AXI_ACLK, !S_AXI_ARESETN,
+			M_AXI_BVALID, M_AXI_BREADY, { M_AXI_BRESP },
+			skidm_bvalid, skidm_bready, { skidm_bresp });
+		// }}}
+
+		// m_axi_awvalid
+		// {{{
+		initial	m_axi_awvalid = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			m_axi_awvalid <= 0;
+		else if (skids_awvalid & skids_awready)
+			m_axi_awvalid <= 1;
+		else if (M_AXI_AWREADY && axi_awlen == 0)
+			m_axi_awvalid <= 0;
+
+		assign	M_AXI_AWVALID = m_axi_awvalid;
+		// }}}
+
+		// skids_awready
+		// {{{
+		assign	skids_awready = (!M_AXI_AWVALID
+				|| ((axi_awlen == 0)&&M_AXI_AWREADY))
+				&& !wfifo_full
+				&&(!s_axi_wready || (skids_wvalid && skids_wlast && skids_wready));
+		// }}}
+
+		// Address processing
+		// {{{
+		always @(posedge S_AXI_ACLK)
+		if (skids_awvalid && skids_awready)
+		begin
+			axi_awaddr <= skids_awaddr;
+			axi_blen   <= skids_awlen;
+			axi_awburst<= skids_awburst;
+			axi_awsize <= skids_awsize;
+		end else if (M_AXI_AWVALID && M_AXI_AWREADY)
+			axi_awaddr <= next_write_addr;
+		// }}}
+
+		// axi_awlen
+		// {{{
+		initial	axi_awlen = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			axi_awlen <= 0;
+		else if (skids_awvalid && skids_awready)
+			axi_awlen <= skids_awlen;
+		else if (M_AXI_AWVALID && M_AXI_AWREADY && axi_awlen > 0)
+			axi_awlen <= axi_awlen - 1;
+		// }}}
+
+		// axi_addr
+		// {{{
+		axi_addr #(.AW(C_AXI_ADDR_WIDTH), .DW(C_AXI_DATA_WIDTH))
+		calcwraddr(axi_awaddr, axi_awsize, axi_awburst,
+			axi_blen, next_write_addr);
+		// }}}
+
+		// s_axi_wready
+		// {{{
+		// We really don't need to do anything special to the write
+		// channel.
+		initial	s_axi_wready = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			s_axi_wready <= 0;
+		else if (skids_awvalid && skids_awready)
+			s_axi_wready <= 1;
+		else if (skids_wvalid && skids_wready && skids_wlast)
+			s_axi_wready <= 0;
+		// }}}
+
+		// skidm*, and read_from_wrfifo
+		// {{{
+		assign	skidm_wdata  = skids_wdata;
+		assign	skidm_wstrb  = skids_wstrb;
+		assign	skidm_wvalid = skids_wvalid && s_axi_wready;
+		assign	skids_wready = s_axi_wready && skidm_wready;
+
+		assign	read_from_wrfifo = (bcounts <= 1)&&(!wfifo_empty)
+			    &&(skidm_bvalid && skidm_bready);
+		// }}}
+
+		// BFIFO
+		// {{{
+		sfifo	#(
+			.BW(C_AXI_ID_WIDTH+8), .LGFLEN(LGFIFO)
+		) bidlnfifo(
+			S_AXI_ACLK, !S_AXI_ARESETN,
+			skids_awvalid && skids_awready,
+			{ skids_awid, skids_awlen },
+			wfifo_full, wfifo_count,
+			read_from_wrfifo,
+			{ wfifo_bid, wfifo_bcount }, wfifo_empty);
+		// }}}
+
+		// bcounts
+		// {{{
+		// Return counts
+		initial	bcounts = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			bcounts <= 0;
+		else if (read_from_wrfifo)
+		begin
+			bcounts <= wfifo_bcount + bcounts;
+		end else if (skidm_bvalid && skidm_bready)
+			bcounts <= bcounts - 1;
+		// }}}
+
+		// bid
+		// {{{
+		always @(posedge S_AXI_ACLK)
+		if (read_from_wrfifo)
+			bid <= wfifo_bid;
+
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_BVALID || S_AXI_BREADY)
+			axi_bid <= (read_from_wrfifo && bcounts==0) ? wfifo_bid : bid;
+		// }}}
+
+		// s_axi_bvalid
+		// {{{
+		initial	s_axi_bvalid = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			s_axi_bvalid <= 0;
+		else if (skidm_bvalid && skidm_bready)
+			s_axi_bvalid <= (bcounts == 1)
+				||((bcounts == 0) && (!wfifo_empty) && (wfifo_bcount == 0));
+		else if (S_AXI_BREADY)
+			s_axi_bvalid <= 0;
+		// }}}
+
+		// axi_bresp
+		// {{{
+		initial	axi_bresp = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			axi_bresp <= 0;
+		else if (S_AXI_BVALID && S_AXI_BREADY)
+		begin
+			if (skidm_bvalid && skidm_bready)
+				axi_bresp <= skidm_bresp;
+			else
+				axi_bresp <= 0;
+		end else if (skidm_bvalid && skidm_bready)
+		begin
+			// Let SLVERR take priority over DECERR
+			casez({ S_AXI_BRESP, skidm_bresp })
+			4'b??0?: axi_bresp <= S_AXI_BRESP;
+			4'b0?1?: axi_bresp <= skidm_bresp;
+			4'b1?10: axi_bresp <= SLVERR;
+			4'b1011: axi_bresp <= SLVERR;
+			4'b1111: axi_bresp <= skidm_bresp;
+			endcase
+		end
+		// /}}}
+
+		// M_AXI_AW*
+		// {{{
+		assign	M_AXI_AWVALID= m_axi_awvalid;
+		assign	M_AXI_AWADDR = axi_awaddr;
+		assign	M_AXI_AWPROT = 0;
+		// }}}
+
+		// skidm_bready, S_AXI_B*
+		// {{{
+		assign	skidm_bready = ((bcounts > 0)||(!wfifo_empty))&&(!S_AXI_BVALID | S_AXI_BREADY);
+		assign	S_AXI_BID    = axi_bid;
+		assign	S_AXI_BRESP  = axi_bresp;
+		assign	S_AXI_BVALID = s_axi_bvalid;
+		// }}}
+		// }}}
+	end else begin : NO_WRITE_SUPPORT
+		// {{{
+		assign	S_AXI_AWREADY = 0;
+		assign	S_AXI_WREADY  = 0;
+		assign	S_AXI_BID     = 0;
+		assign	S_AXI_BRESP   = 2'b11;
+		assign	S_AXI_BVALID  = 0;
+		assign	S_AXI_BID     = 0;
+
+		//
+		assign	M_AXI_AWVALID = 0;
+		assign	M_AXI_AWADDR  = 0;
+		assign	M_AXI_AWPROT  = 0;
+		//
+		assign	M_AXI_WVALID  = 0;
+		assign	M_AXI_WDATA   = 0;
+		assign	M_AXI_WSTRB   = 0;
+		//
+		assign	M_AXI_BREADY  = 0;
+
+		//
+		// S_AXI_AW* skid buffer
+		assign	skids_awvalid = 0;
+		assign	skids_awready = 0;
+		assign	skids_awid    = 0;
+		assign	skids_awaddr  = 0;
+		assign	skids_awlen   = 0;
+		assign	skids_awsize  = 0;
+		assign	skids_awburst = 0;
+		//
+		// S_AXI_W* skid buffer
+		assign	skids_wvalid = S_AXI_WVALID;
+		assign	skids_wready = S_AXI_WREADY;
+		assign	skids_wdata  = S_AXI_WDATA;
+		assign	skids_wstrb  = S_AXI_WSTRB;
+		assign	skids_wlast  = S_AXI_WLAST;
+		//
+		// S_AXI_B* skid buffer isn't needed
+		//
+		// M_AXI_AW* skid buffer isn't needed
+		//
+		// M_AXI_W* skid buffer
+		assign	skidm_wvalid = M_AXI_WVALID;
+		assign	skidm_wready = M_AXI_WREADY;
+		assign	skidm_wdata  = M_AXI_WDATA;
+		assign	skidm_wstrb  = M_AXI_WSTRB;
+		//
+		// M_AXI_B* skid buffer
+		assign	skidm_bvalid = M_AXI_BVALID;
+		assign	skidm_bready = M_AXI_BREADY;
+		assign	skidm_bresp  = M_AXI_BRESP;
+		//
+		//
+		always @(*)
+		begin
+			s_axi_wready = 0;
+
+			axi_awlen = 0;
+			bcounts  = 0;
+			bid      = 0;
+			axi_bresp = 0;
+			axi_bid   = 0;
+
+		end
+
+		assign	wfifo_full  = 0;
+		assign	wfifo_empty = 1;
+		assign	wfifo_count = 0;
+		assign	read_from_wrfifo = 0;
+		// }}}
+	end endgenerate
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read logic
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate if (OPT_READS)
+	begin : IMPLEMENT_READS
+		// {{{
+		//
+		// S_AXI_AR* skid buffer
+		// {{{
+		skidbuffer #(.DW(IW+AW+8+3+2), .OPT_LOWPOWER(0), .OPT_OUTREG(0))
+		arskid(S_AXI_ACLK, !S_AXI_ARESETN,
+			S_AXI_ARVALID, S_AXI_ARREADY,
+			{ S_AXI_ARID, S_AXI_ARADDR, S_AXI_ARLEN, S_AXI_ARSIZE,
+				S_AXI_ARBURST },
+			skids_arvalid, skids_arready,
+			{ skids_arid, skids_araddr, skids_arlen, skids_arsize,
+				skids_arburst });
+		// }}}
+		// M_AXI_R* skid buffer
+		// {{{
+		skidbuffer #(.DW(DW+2), .OPT_LOWPOWER(0), .OPT_OUTREG(0))
+		rskid(S_AXI_ACLK, !S_AXI_ARESETN,
+			M_AXI_RVALID, M_AXI_RREADY,{ M_AXI_RDATA, M_AXI_RRESP },
+			skidm_rvalid,skidm_rready,{ skidm_rdata, skidm_rresp });
+		// }}}
+		// m_axi_arvalid
+		// {{{
+		initial	m_axi_arvalid = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			m_axi_arvalid <= 0;
+		else if (skids_arvalid && skids_arready)
+			m_axi_arvalid <= 1;
+		else if (M_AXI_ARREADY && axi_arlen == 0)
+			m_axi_arvalid <= 0;
+		// }}}
+
+		// Read address processing
+		// {{{
+		always @(posedge S_AXI_ACLK)
+		if (skids_arvalid && skids_arready)
+		begin
+			axi_araddr  <= skids_araddr;
+			axi_arburst <= skids_arburst;
+			axi_arsize  <= skids_arsize;
+			axi_rlen    <= skids_arlen;
+		end else if (M_AXI_ARREADY)
+			axi_araddr <= next_read_addr;
+
+		axi_addr #(.AW(C_AXI_ADDR_WIDTH), .DW(C_AXI_DATA_WIDTH))
+			calcrdaddr(axi_araddr, axi_arsize, axi_arburst,
+			axi_rlen, next_read_addr);
+		// }}}
+
+		// axi_arlen, Read length processing
+		// {{{
+		initial	axi_arlen = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			axi_arlen <= 0;
+		else if (skids_arvalid && skids_arready)
+			axi_arlen <= skids_arlen;
+		else if (M_AXI_ARVALID && M_AXI_ARREADY && axi_arlen > 0)
+			axi_arlen <= axi_arlen - 1;
+		// }}}
+
+		assign	skids_arready = (!M_AXI_ARVALID ||
+				((axi_arlen == 0) && M_AXI_ARREADY))
+				&& !rfifo_full;
+
+		assign	read_from_rdfifo = skidm_rvalid && skidm_rready
+					&& (rcounts <= 1) && !rfifo_empty;
+
+		// Read ID FIFO
+		// {{{
+		sfifo	#(.BW(C_AXI_ID_WIDTH+8), .LGFLEN(LGFIFO))
+		ridlnfifo(S_AXI_ACLK, !S_AXI_ARESETN,
+			skids_arvalid && skids_arready,
+			{ skids_arid, skids_arlen },
+			rfifo_full, rfifo_count,
+			read_from_rdfifo,
+			{ rfifo_rid, rfifo_rcount }, rfifo_empty);
+		// }}}
+
+		assign	skidm_rready = (!S_AXI_RVALID || S_AXI_RREADY);
+
+		// s_axi_rvalid
+		// {{{
+		initial	s_axi_rvalid = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			s_axi_rvalid <= 0;
+		else if (skidm_rvalid && skidm_rready)
+			s_axi_rvalid <= 1;
+		else if (S_AXI_RREADY)
+			s_axi_rvalid <= 0;
+		// }}}
+
+		// s_axi_rresp, s_axi_rdata
+		// {{{
+		always @(posedge S_AXI_ACLK)
+		if (skidm_rvalid && skidm_rready)
+		begin
+			s_axi_rresp <= skidm_rresp;
+			s_axi_rdata <= skidm_rdata;
+		end else if (S_AXI_RREADY)
+		begin
+			s_axi_rresp <= 0;
+			s_axi_rdata <= 0;
+		end
+		// }}}
+
+		// rcounts, Return counts
+		// {{{
+		initial	rcounts = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			rcounts <= 0;
+		else if (read_from_rdfifo)
+			rcounts <= rfifo_rcount + rcounts;
+		else if (skidm_rvalid && skidm_rready)
+			rcounts <= rcounts - 1;
+		// }}}
+
+		// rid
+		// {{{
+		initial	rid = 0;
+		always @(posedge S_AXI_ACLK)
+		if (read_from_rdfifo)
+			rid <= rfifo_rid;
+		// }}}
+
+		// s_axi_rlast
+		// {{{
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_RVALID || S_AXI_RREADY)
+		begin
+			// if (rcounts == 1) s_axi_rlast <= 1; else
+			if (read_from_rdfifo)
+				s_axi_rlast <= (rfifo_rcount == 0);
+			else
+				s_axi_rlast <= 0;
+
+			if (rcounts == 1)
+				s_axi_rlast <= 1;
+		end
+		// }}}
+
+		// s_axi_rid
+		// {{{
+		initial	s_axi_rid = 0;
+		always @(posedge S_AXI_ACLK)
+		if ((S_AXI_RVALID && S_AXI_RREADY && S_AXI_RLAST)
+				||(!S_AXI_RVALID && rcounts == 0))
+			s_axi_rid <= (read_from_rdfifo)&&(rcounts == 0)?rfifo_rid : rid;
+		// }}}
+
+		// M_AXI_AR*
+		// {{{
+		assign	M_AXI_ARVALID= m_axi_arvalid;
+		assign	M_AXI_ARADDR = axi_araddr;
+		assign	M_AXI_ARPROT = 0;
+		// }}}
+		// S_AXI_R*
+		// {{{
+		assign	S_AXI_RVALID = s_axi_rvalid;
+		assign	S_AXI_RDATA  = s_axi_rdata;
+		assign	S_AXI_RRESP  = s_axi_rresp;
+		assign	S_AXI_RLAST  = s_axi_rlast;
+		assign	S_AXI_RID    = s_axi_rid;
+		// }}}
+		// }}}
+	end else begin : NO_READ_SUPPORT // if (!OPT_READS)
+		// {{{
+		assign	M_AXI_ARVALID= 0;
+		assign	M_AXI_ARADDR = 0;
+		assign	M_AXI_ARPROT = 0;
+		assign	M_AXI_RREADY = 0;
+		//
+		assign	S_AXI_ARREADY= 0;
+		assign	S_AXI_RVALID = 0;
+		assign	S_AXI_RDATA  = 0;
+		assign	S_AXI_RRESP  = 0;
+		assign	S_AXI_RLAST  = 0;
+		assign	S_AXI_RID    = 0;
+
+		//
+		assign	skids_arvalid = S_AXI_ARVALID;
+		assign	skids_arready = S_AXI_ARREADY;
+		assign	skids_arid    = S_AXI_ARID;
+		assign	skids_araddr  = S_AXI_ARADDR;
+		assign	skids_arlen   = S_AXI_ARLEN;
+		assign	skids_arsize  = S_AXI_ARSIZE;
+		assign	skids_arburst = S_AXI_ARBURST;
+		//
+		assign	skidm_rvalid  = M_AXI_RVALID;
+		assign	skidm_rready  = M_AXI_RREADY;
+		assign	skidm_rdata   = M_AXI_RDATA;
+		assign	skidm_rresp   = M_AXI_RRESP;
+		//
+		//
+		always @(*)
+		begin
+			axi_arlen = 0;
+
+			rcounts = 0;
+			rid = 0;
+
+		end
+		assign	rfifo_empty = 1;
+		assign	rfifo_full  = 0;
+		assign	rfifo_count = 0;
+		// }}}
+	end endgenerate
+	// }}}
+	// Make Verilator happy
+	// {{{
+	// Verilator lint_off UNUSED
+	wire	[35-1:0]	unused;
+	assign	unused = {
+		S_AXI_AWLOCK, S_AXI_AWCACHE, S_AXI_AWPROT, S_AXI_AWQOS,
+		skids_wlast, wfifo_count,
+		S_AXI_ARLOCK, S_AXI_ARCACHE, S_AXI_ARPROT, S_AXI_ARQOS,
+		rfifo_count };
+	// Verilator lint_on  UNUSED
+	// }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties
+// {{{
+// The following are a subset of the formal properties used to verify this core
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	localparam	F_LGDEPTH = LGFIFO+1+8;
+
+	//
+	// ...
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI channel properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	faxi_slave #(.C_AXI_ID_WIDTH(IW),
+			.C_AXI_DATA_WIDTH(DW),
+			.C_AXI_ADDR_WIDTH(AW),
+			//
+			)
+		faxi(.i_clk(S_AXI_ACLK),
+			.i_axi_reset_n(S_AXI_ARESETN),
+			// Write address
+			.i_axi_awready(skids_awready),
+			.i_axi_awid(   skids_awid),
+			.i_axi_awaddr( skids_awaddr),
+			.i_axi_awlen(  skids_awlen),
+			.i_axi_awsize( skids_awsize),
+			.i_axi_awburst(skids_awburst),
+			.i_axi_awlock( 0),
+			.i_axi_awcache(0),
+			.i_axi_awprot( 0),
+			.i_axi_awqos(  0),
+			.i_axi_awvalid(skids_awvalid),
+			// Write data
+			.i_axi_wready( skids_wready),
+			.i_axi_wdata(  skids_wdata),
+			.i_axi_wstrb(  skids_wstrb),
+			.i_axi_wlast(  skids_wlast),
+			.i_axi_wvalid( skids_wvalid),
+			// Write return response
+			.i_axi_bid(    S_AXI_BID),
+			.i_axi_bresp(  S_AXI_BRESP),
+			.i_axi_bvalid( S_AXI_BVALID),
+			.i_axi_bready( S_AXI_BREADY),
+			// Read address
+			.i_axi_arready(skids_arready),
+			.i_axi_arid(   skids_arid),
+			.i_axi_araddr( skids_araddr),
+			.i_axi_arlen(  skids_arlen),
+			.i_axi_arsize( skids_arsize),
+			.i_axi_arburst(skids_arburst),
+			.i_axi_arlock( 0),
+			.i_axi_arcache(0),
+			.i_axi_arprot( 0),
+			.i_axi_arqos(  0),
+			.i_axi_arvalid(skids_arvalid),
+			// Read response
+			.i_axi_rid(    S_AXI_RID),
+			.i_axi_rresp(  S_AXI_RRESP),
+			.i_axi_rvalid( S_AXI_RVALID),
+			.i_axi_rdata(  S_AXI_RDATA),
+			.i_axi_rlast(  S_AXI_RLAST),
+			.i_axi_rready( S_AXI_RREADY),
+			//
+			// Formal property data
+			.f_axi_awr_nbursts(   faxi_awr_nbursts),
+			.f_axi_wr_pending(    faxi_wr_pending),
+			.f_axi_rd_nbursts(    faxi_rd_nbursts),
+			.f_axi_rd_outstanding(faxi_rd_outstanding),
+			//
+			// ...
+			);
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	faxil_master #(.C_AXI_DATA_WIDTH(DW), .C_AXI_ADDR_WIDTH(AW),
+			.F_OPT_NO_RESET(1),
+			.F_AXI_MAXWAIT(5),
+			.F_AXI_MAXDELAY(4),
+			.F_AXI_MAXRSTALL(0),
+			.F_OPT_WRITE_ONLY(OPT_WRITES && !OPT_READS),
+			.F_OPT_READ_ONLY(!OPT_WRITES &&  OPT_READS),
+			.F_LGDEPTH(F_AXIL_LGDEPTH))
+		faxil(.i_clk(S_AXI_ACLK),
+			.i_axi_reset_n(S_AXI_ARESETN),
+			// Write address channel
+			.i_axi_awready(M_AXI_AWREADY),
+			.i_axi_awaddr( M_AXI_AWADDR),
+			.i_axi_awcache(4'h0),
+			.i_axi_awprot( M_AXI_AWPROT),
+			.i_axi_awvalid(M_AXI_AWVALID),
+			// Write data
+			.i_axi_wready( skidm_wready),
+			.i_axi_wdata(  skidm_wdata),
+			.i_axi_wstrb(  skidm_wstrb),
+			.i_axi_wvalid( skidm_wvalid),
+			// Write response
+			.i_axi_bresp(  skidm_bresp),
+			.i_axi_bvalid( skidm_bvalid),
+			.i_axi_bready( skidm_bready),
+			// Read address
+			.i_axi_arready(M_AXI_ARREADY),
+			.i_axi_araddr( M_AXI_ARADDR),
+			.i_axi_arcache(4'h0),
+			.i_axi_arprot( M_AXI_ARPROT),
+			.i_axi_arvalid(M_AXI_ARVALID),
+			// Read data return
+			.i_axi_rresp(  skidm_rresp),
+			.i_axi_rvalid( skidm_rvalid),
+			.i_axi_rdata(  skidm_rdata),
+			.i_axi_rready( skidm_rready),
+			//
+			// Formal check variables
+			.f_axi_rd_outstanding(faxil_rd_outstanding),
+			.f_axi_wr_outstanding(faxil_wr_outstanding),
+			.f_axi_awr_outstanding(faxil_awr_outstanding));
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Assume that the two write channels stay within an appropriate
+	// distance of each other.  This is to make certain that the property
+	// file features are not violated, although not necessary true for
+	// actual operation
+	//
+	always @(*)
+		assert(s_axi_wready == (OPT_WRITES && faxi_wr_pending > 0));
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write induction properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	// These are extra properties necessary to pass write induction
+	//
+
+	always @(*)
+	if ((bcounts == 0)&&(!read_from_wrfifo))
+		assert(!skidm_bvalid || !skidm_bready);
+
+	always @(*)
+	if (axi_awlen > 0)
+	begin
+		assert(m_axi_awvalid);
+		if (axi_awlen > 1)
+			assert(!skids_awready);
+		else if (wfifo_full)
+			assert(!skids_awready);
+		else if (M_AXI_AWVALID && !M_AXI_AWREADY)
+			assert(!skids_awready);
+	end
+
+
+	always @(*)
+		assert(axi_bresp != EXOKAY);
+
+	reg	[F_LGDEPTH-1:0]	f_wfifo_bursts, f_wfifo_bursts_minus_one,
+				f_wfifo_within,
+				f_wfiid_bursts, f_wfiid_bursts_minus_one;
+	reg	[IW-1:0]	f_awid;
+	always @(posedge S_AXI_ACLK)
+	if (skids_awvalid && skids_awready)
+		f_awid = skids_awid;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read induction properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	always @(*)
+	if (!S_AXI_RVALID && rcounts > 0)
+		assert(rid == S_AXI_RID);
+
+	always @(*)
+	if (S_AXI_RVALID && !S_AXI_RLAST)
+		assert(rid == S_AXI_RID);
+
+	always @(*)
+	if ((rcounts == 0)&&(!read_from_rdfifo))
+		assert(!skidm_rvalid || !skidm_rready);
+
+	always @(*)
+	if (axi_arlen > 0)
+	begin
+		assert(m_axi_arvalid);
+		assert(!skids_arready);
+	end
+
+	//
+	// ...
+	//
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Select only write or only read operation
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate if (!OPT_WRITES)
+	begin
+		always @(*)
+		begin
+			assume(!skids_awvalid);
+			assume(!skids_wvalid);
+			assert(M_AXI_AWVALID == 0);
+			assert(faxil_awr_outstanding == 0);
+			assert(faxil_wr_outstanding == 0);
+			assert(!skidm_bvalid);
+			assert(!S_AXI_BVALID);
+		end
+	end endgenerate
+
+	generate if (!OPT_READS)
+	begin
+
+		always @(*)
+		begin
+			assume(!S_AXI_ARVALID);
+			assert(M_AXI_ARVALID == 0);
+			assert(faxil_rd_outstanding == 0);
+		end
+
+	end endgenerate
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover statements, to show performance
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate if (OPT_WRITES)
+	begin
+		// {{{
+		reg	[3:0]	cvr_write_count, cvr_write_count_simple;
+
+		initial	cvr_write_count = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			cvr_write_count_simple <= 0;
+		else if (S_AXI_AWVALID && S_AXI_AWREADY && S_AXI_AWLEN == 0)
+			cvr_write_count_simple <= cvr_write_count_simple + 1;
+
+		initial	cvr_write_count = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			cvr_write_count <= 0;
+		else if (S_AXI_AWVALID && S_AXI_AWREADY && S_AXI_AWLEN > 2)
+			cvr_write_count <= cvr_write_count + 1;
+
+		always @(*)
+			cover(cvr_write_count_simple > 6 && /* ... */ !S_AXI_BVALID);
+		always @(*)
+			cover(cvr_write_count > 2 && /* ... */ !S_AXI_BVALID);
+		// }}}
+	end endgenerate
+
+	generate if (OPT_READS)
+	begin
+		// {{{
+		reg	[3:0]	cvr_read_count, cvr_read_count_simple;
+
+		initial	cvr_read_count_simple = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			cvr_read_count_simple <= 0;
+		else if (S_AXI_ARVALID && S_AXI_ARREADY && S_AXI_ARLEN == 0)
+			cvr_read_count_simple <= cvr_read_count_simple + 1;
+
+		initial	cvr_read_count = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			cvr_read_count <= 0;
+		else if (S_AXI_ARVALID && S_AXI_ARREADY && S_AXI_ARLEN > 2)
+			cvr_read_count <= cvr_read_count + 1;
+
+		always @(*)
+			cover(cvr_read_count_simple > 6 && /* ... */ !S_AXI_RVALID);
+		always @(*)
+			cover(cvr_read_count > 2 && /* ... */ !S_AXI_RVALID);
+		// }}}
+	end endgenerate
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// ...
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	// }}}
+`undef	BMC_ASSERT
+`endif
+// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axi32axi.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axi32axi.v
new file mode 100644
index 0000000..5f69b95
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axi32axi.v
@@ -0,0 +1,377 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axi32axi.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Bridge from an AXI3 slave to an AXI4 master
+// {{{
+//	The goal here is to support as high a bus speed as possible, maintain
+//	burst support (if possible) and (more important) allow bus requests
+//	coming from the ARM within either the Zynq or one of Intel's SOC chips
+//	to speak with an AutoFPGA based design.
+//
+//	Note that if you aren't using AutoFPGA, then you probably don't need
+//	this core--the vendor tools should be able to handle this conversion
+//	quietly and automatically for you.
+//
+// Notes:
+//	AxCACHE is remapped as per the AXI4 specification, since the values
+//	aren't truly equivalent.  This forces a single clock delay in the Ax*
+//	channels and (likely) the W* channel as well as a system level
+//	consequence.
+//
+//	AXI3 locking is not supported under AXI4.  As per the AXI4 spec,
+//	AxLOCK is converteted from AXI3 to AXI4 by just dropping the high
+//	order bit.
+//
+//	The WID input is ignored.  Whether or not this input can be ignored
+//	is based upon how the ARM is implemented internally.  After a bit
+//	of research into both Zynq's and Intel SOCs, this appears to be the
+//	appropriate answer here.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+// }}}
+module	axi32axi #(
+		// {{{
+		parameter	C_AXI_ID_WIDTH = 1,
+		parameter	C_AXI_ADDR_WIDTH = 32,
+		parameter	C_AXI_DATA_WIDTH = 32,
+		parameter	OPT_REORDER_METHOD = 0,
+		parameter [0:0]	OPT_TRANSFORM_AXCACHE = 1,
+		parameter [0:0]	OPT_LOWPOWER = 0,
+		parameter [0:0]	OPT_LOW_LATENCY = 0,
+		parameter	WID_LGAWFIFO = 3,
+		parameter	WID_LGWFIFO = 3,
+		//
+		localparam	ADDRLSB= $clog2(C_AXI_DATA_WIDTH)-3,
+		localparam	IW=C_AXI_ID_WIDTH
+		// }}}
+	) (
+		// {{{
+		input	wire				S_AXI_ACLK,
+		input	wire				S_AXI_ARESETN,
+		//
+		// The AXI3 incoming/slave interface
+		input	reg				S_AXI_AWVALID,
+		output	wire				S_AXI_AWREADY,
+		input	reg	[C_AXI_ID_WIDTH-1:0]	S_AXI_AWID,
+		input	reg	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_AWADDR,
+		input	reg	[3:0]			S_AXI_AWLEN,
+		input	reg	[2:0]			S_AXI_AWSIZE,
+		input	reg	[1:0]			S_AXI_AWBURST,
+		input	reg	[1:0]			S_AXI_AWLOCK,
+		input	reg	[3:0]			S_AXI_AWCACHE,
+		input	reg	[2:0]			S_AXI_AWPROT,
+		input	reg	[3:0]			S_AXI_AWQOS,
+		//
+		//
+		input	wire				S_AXI_WVALID,
+		output	wire				S_AXI_WREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_WID,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]	S_AXI_WDATA,
+		input	wire [C_AXI_DATA_WIDTH/8-1:0]	S_AXI_WSTRB,
+		input	wire				S_AXI_WLAST,
+		//
+		//
+		output	wire				S_AXI_BVALID,
+		input	wire				S_AXI_BREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_BID,
+		output	wire	[1:0]			S_AXI_BRESP,
+		//
+		//
+		input	wire				S_AXI_ARVALID,
+		output	wire				S_AXI_ARREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_ARID,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_ARADDR,
+		input	wire	[3:0]			S_AXI_ARLEN,
+		input	wire	[2:0]			S_AXI_ARSIZE,
+		input	wire	[1:0]			S_AXI_ARBURST,
+		input	wire	[1:0]			S_AXI_ARLOCK,
+		input	wire	[3:0]			S_AXI_ARCACHE,
+		input	wire	[2:0]			S_AXI_ARPROT,
+		input	wire	[3:0]			S_AXI_ARQOS,
+		//
+		output	wire				S_AXI_RVALID,
+		input	wire				S_AXI_RREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_RID,
+		output	wire	[C_AXI_DATA_WIDTH-1:0]	S_AXI_RDATA,
+		output	wire				S_AXI_RLAST,
+		output	wire	[1:0]			S_AXI_RRESP,
+		//
+		//
+		// The AXI4 Master (outgoing) interface
+		output	wire				M_AXI_AWVALID,
+		input	wire				M_AXI_AWREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_AWID,
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_AWADDR,
+		output	wire	[7:0]			M_AXI_AWLEN,
+		output	wire	[2:0]			M_AXI_AWSIZE,
+		output	wire	[1:0]			M_AXI_AWBURST,
+		output	wire				M_AXI_AWLOCK,
+		output	wire	[3:0]			M_AXI_AWCACHE,
+		output	wire	[2:0]			M_AXI_AWPROT,
+		output	wire	[3:0]			M_AXI_AWQOS,
+		//
+		//
+		output	wire				M_AXI_WVALID,
+		input	wire				M_AXI_WREADY,
+		output	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_WDATA,
+		output	wire [C_AXI_DATA_WIDTH/8-1:0]	M_AXI_WSTRB,
+		output	wire				M_AXI_WLAST,
+		//
+		//
+		input	wire				M_AXI_BVALID,
+		output	wire				M_AXI_BREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_BID,
+		input	wire	[1:0]			M_AXI_BRESP,
+		//
+		//
+		output	wire				M_AXI_ARVALID,
+		input	wire				M_AXI_ARREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_ARID,
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_ARADDR,
+		output	wire	[7:0]			M_AXI_ARLEN,
+		output	wire	[2:0]			M_AXI_ARSIZE,
+		output	wire	[1:0]			M_AXI_ARBURST,
+		output	wire				M_AXI_ARLOCK,
+		output	wire	[3:0]			M_AXI_ARCACHE,
+		output	wire	[2:0]			M_AXI_ARPROT,
+		output	wire	[3:0]			M_AXI_ARQOS,
+		//
+		input	wire				M_AXI_RVALID,
+		output	wire				M_AXI_RREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_RID,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_RDATA,
+		input	wire				M_AXI_RLAST,
+		input	wire	[1:0]			M_AXI_RRESP
+		// }}}
+	);
+
+	// Register/net declarations
+	// {{{
+	reg	[3:0]	axi4_awcache, axi4_arcache;
+	reg		axi4_awlock, axi4_arlock;
+	wire		awskd_ready;
+	wire		wid_reorder_awready;
+	wire [IW-1:0]	reordered_wid;
+	// }}}
+
+	// Write cache remapping
+	// {{{
+	always @(*)
+	case(S_AXI_AWCACHE)
+	4'b1010: axi4_awcache = 4'b1110;
+	4'b1011: axi4_awcache = 4'b1111;
+	default: axi4_awcache = S_AXI_AWCACHE;
+	endcase
+	// }}}
+
+	// AWLOCK
+	// {{{
+	always @(*)
+		axi4_awlock = S_AXI_AWLOCK[0];
+	// }}}
+
+	// AW Skid buffer
+	// {{{
+	generate if (OPT_TRANSFORM_AXCACHE)
+	begin
+		// {{{
+		skidbuffer #(
+			.DW(C_AXI_ADDR_WIDTH + C_AXI_ID_WIDTH
+					+ 4 + 3 + 2 + 1+4+3+4),
+			.OPT_OUTREG(1'b1)
+		) awskid (
+			.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+			.i_valid(S_AXI_AWVALID && wid_reorder_awready),
+				.o_ready(awskd_ready),
+				.i_data({ S_AXI_AWID, S_AXI_AWADDR, S_AXI_AWLEN,
+					S_AXI_AWSIZE, S_AXI_AWBURST,axi4_awlock,
+					axi4_awcache, S_AXI_AWPROT, S_AXI_AWQOS
+					}),
+			.o_valid(M_AXI_AWVALID), .i_ready(M_AXI_AWREADY),
+				.o_data({ M_AXI_AWID, M_AXI_AWADDR,
+							 M_AXI_AWLEN[3:0],
+					M_AXI_AWSIZE,M_AXI_AWBURST,M_AXI_AWLOCK,
+					M_AXI_AWCACHE,M_AXI_AWPROT, M_AXI_AWQOS
+					})
+		);
+
+		assign	M_AXI_AWLEN[7:4] = 4'h0;
+		assign	S_AXI_AWREADY = awskd_ready && wid_reorder_awready;
+		// }}}
+	end else begin
+		// {{{
+		assign	M_AXI_AWVALID = S_AXI_AWVALID && wid_reorder_awready;
+		assign	S_AXI_AWREADY = M_AXI_AWREADY;
+		assign	M_AXI_AWID    = S_AXI_AWID;
+		assign	M_AXI_AWADDR  = S_AXI_AWADDR;
+		assign	M_AXI_AWLEN   = { 4'h0, S_AXI_AWLEN };
+		assign	M_AXI_AWSIZE  = S_AXI_AWSIZE;
+		assign	M_AXI_AWBURST = S_AXI_AWBURST;
+		assign	M_AXI_AWLOCK  = axi4_awlock;
+		assign	M_AXI_AWCACHE = axi4_awcache;
+		assign	M_AXI_AWPROT  = S_AXI_AWPROT;
+		assign	M_AXI_AWQOS   = S_AXI_AWQOS;
+
+		assign	awskd_ready = 1;
+		// }}}
+	end endgenerate
+	// }}}
+
+	// Handle write channel de-interleaving
+	// {{{
+	axi3reorder #(
+		// {{{
+		.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.OPT_METHOD(OPT_REORDER_METHOD),
+		.OPT_LOWPOWER(OPT_LOWPOWER),
+		.OPT_LOW_LATENCY(OPT_LOW_LATENCY),
+		.LGAWFIFO(WID_LGAWFIFO),
+		.LGWFIFO(WID_LGWFIFO),
+		// }}}
+	) widreorder (
+		// {{{
+		.S_AXI_ACLK(S_AXI_ACLK), .S_AXI_ARESETN(S_AXI_ARESETN),
+		// Incoming Write address ID
+		.S_AXI3_AWVALID(S_AXI_AWVALID && S_AXI_AWREADY),
+			.S_AXI3_AWREADY(wid_reorder_awready),
+			.S_AXI3_AWID(S_AXI_AWID),
+		// Incoming Write data info
+		.S_AXI3_WVALID(S_AXI_WVALID),
+			.S_AXI3_WREADY(S_AXI_WREADY),
+			.S_AXI3_WID(S_AXI_WID),
+			.S_AXI3_WDATA(S_AXI_WDATA),
+			.S_AXI3_WSTRB(S_AXI_WSTRB),
+			.S_AXI3_WLAST(S_AXI_WLAST),
+		// Outgoing write data channel
+		.M_AXI_WVALID(M_AXI_WVALID),
+			.M_AXI_WREADY(M_AXI_WREADY),
+			.M_AXI_WID(reordered_wid),
+			.M_AXI_WDATA(M_AXI_WDATA),
+			.M_AXI_WSTRB(M_AXI_WSTRB),
+			.M_AXI_WLAST(M_AXI_WLAST)
+		// }}}
+	);
+	// }}}
+
+	// Forward the B* channel return
+	// {{{
+	assign	S_AXI_BVALID = M_AXI_BVALID;
+	assign	M_AXI_BREADY = S_AXI_BREADY;
+	assign	S_AXI_BID    = M_AXI_BID;
+	assign	S_AXI_BRESP  = M_AXI_BRESP;
+	// }}}
+
+	// Read cache remapping
+	// {{{
+	always @(*)
+	case(S_AXI_ARCACHE)
+	4'b0110: axi4_arcache = 4'b1110;
+	4'b0111: axi4_arcache = 4'b1111;
+	default: axi4_arcache = S_AXI_ARCACHE;
+	endcase
+	// }}}
+
+	// ARLOCK
+	// {{{
+	always @(*)
+		axi4_arlock = S_AXI_ARLOCK[0];
+	// }}}
+
+	// AR Skid buffer
+	// {{{
+	generate if (OPT_TRANSFORM_AXCACHE)
+	begin
+		// {{{
+		skidbuffer #(
+			.DW(C_AXI_ADDR_WIDTH + C_AXI_ID_WIDTH
+					+ 4 + 3 + 2 + 1+4+3+4),
+			.OPT_OUTREG(1'b1)
+		) arskid (
+			.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+			.i_valid(S_AXI_ARVALID), .o_ready(S_AXI_ARREADY),
+				.i_data({ S_AXI_ARID, S_AXI_ARADDR,  S_AXI_ARLEN,
+					S_AXI_ARSIZE, S_AXI_ARBURST, axi4_arlock,
+					axi4_arcache,  S_AXI_ARPROT,  S_AXI_ARQOS }),
+			.o_valid(M_AXI_ARVALID), .i_ready(M_AXI_ARREADY),
+				.o_data({ M_AXI_ARID,  M_AXI_ARADDR,  M_AXI_ARLEN[3:0],
+					M_AXI_ARSIZE,  M_AXI_ARBURST, M_AXI_ARLOCK,
+					M_AXI_ARCACHE, M_AXI_ARPROT,  M_AXI_ARQOS })
+		);
+
+		assign	M_AXI_ARLEN[7:4] = 4'h0;
+		// }}}
+	end else begin
+		// {{{
+		assign	M_AXI_ARVALID = S_AXI_ARVALID;
+		assign	S_AXI_ARREADY = M_AXI_ARREADY;
+		assign	M_AXI_ARID    = S_AXI_ARID;
+		assign	M_AXI_ARADDR  = S_AXI_ARADDR;
+		assign	M_AXI_ARLEN   = { 4'h0, S_AXI_ARLEN };
+		assign	M_AXI_ARSIZE  = S_AXI_ARSIZE;
+		assign	M_AXI_ARBURST = S_AXI_ARBURST;
+		assign	M_AXI_ARLOCK  = axi4_arlock;
+		assign	M_AXI_ARCACHE = axi4_arcache;
+		assign	M_AXI_ARPROT  = S_AXI_ARPROT;
+		assign	M_AXI_ARQOS   = S_AXI_ARQOS;
+		// }}}
+	end endgenerate
+	// }}}
+
+	// Forward the R* channel return
+	// {{{
+	assign	S_AXI_RVALID = M_AXI_RVALID;
+	assign	M_AXI_RREADY = S_AXI_RREADY;
+	assign	S_AXI_RID    = M_AXI_RID;
+	assign	S_AXI_RDATA  = M_AXI_RDATA;
+	assign	S_AXI_RLAST  = M_AXI_RLAST;
+	assign	S_AXI_RRESP  = M_AXI_RRESP;
+	// }}}
+
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, S_AXI_AWLOCK[1], S_AXI_ARLOCK[1],
+			reordered_wid };
+	// Verilator lint_on UNUSED
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal property section
+//
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+//
+// This design has not been formally verified.
+//
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axi3reorder.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axi3reorder.v
new file mode 100644
index 0000000..437c7b4
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axi3reorder.v
@@ -0,0 +1,746 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axi3reorder.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	One of the challenges of working with AXI3 are the (potentially)
+//		out of order writes.  This modules is designed to re-order write
+//	beats back into the proper order given by the AW* channel.  Once done,
+//	write beats will always be contiguous--only changing ID's after WLAST.
+//	Indeed, once done, the WID field can be properly removed and ignored.
+//	it's left within for forms sake, but isn't required.
+//
+// Algorithms:
+//	The design currently contains one of three reordering algorithms.
+//
+//	MTHD_NONE	Is a basic pass-through.  This would be appropriate
+//			for AXI3 streams that are known to be in order already.
+//
+//	MTHD_SHIFT_REGISTER	Uses a shift-register based "FIFO".  (Not block
+//				RAM)  All write data goes into this FIFO.  Items
+//			are read from this FIFO out of order as required for
+//			the given ID.  When any item is read from the middle,
+//			the shift register back around the item read.
+//
+//			This is a compromise implementation that uses less
+//			logic than the PER/ID FIFOS, while still allowing some
+//			amount of reordering to take place.
+//
+//	MTHD_PERID_FIFOS	Uses an explicit FIFO for each ID.  Data come
+//				into the core and go directly into the FIFO's.
+//			Data are read out of the FIFOs in write-address order
+//			until WLAST, where the write address may (potentially)
+//			change.
+//
+//			For a small number of IDs, this solution should be
+//			*complete*, and lacking nothing.  (Unless you fill the
+//			write data FIFO's while needing data from another ID ..)
+//
+// Implementation notes:
+//	This module is intended to be used side by side with other AW* channel
+//	processing, and following an (external) AW* skidbuffer.  For this
+//	reason, it doesn't use an AW skid buffer, nor does it output AW*
+//	information.  External AWREADY handling should therefore be:
+//
+//		master_awskid_read = reorder_awready && any_other_awready;
+//
+//	going into a skid buffer, with the proper AWREADY being the upstream
+//	skidbuffer's AWREADY output.
+//
+// Expected performance:
+//	One beat per clock, all methods.
+//
+// Status:
+//	This module passes both a Verilator lint check and a 15-20 step formal
+//	bounded model check.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// }}}
+module	axi3reorder #(
+		// {{{
+		parameter	C_AXI_ID_WIDTH = 4,
+		parameter	C_AXI_DATA_WIDTH = 32,
+		parameter	LGAWFIFO = 3,	// # packets we can handle
+		parameter	LGWFIFO = 4,	// Full size of an AXI burst
+		parameter	OPT_METHOD = 0,
+		parameter [0:0]	OPT_LOWPOWER = 0,
+		parameter [0:0]	OPT_LOW_LATENCY = 0,
+		localparam	MTHD_NONE = 0,
+		localparam	MTHD_SHIFT_REGISTER = 1,
+		localparam	MTHD_PERID_FIFOS = 2,
+		localparam	IW = C_AXI_ID_WIDTH,
+		localparam	DW = C_AXI_DATA_WIDTH,
+		parameter	NUM_FIFOS = (1<<IW)
+		// }}}
+	) (
+		// {{{
+		input	wire	S_AXI_ACLK,
+		input	wire	S_AXI_ARESETN,
+		// AXI3 (partial) slave interface
+		// {{{
+		input	wire			S_AXI3_AWVALID,
+		output	wire			S_AXI3_AWREADY,
+		input	wire	[IW-1:0]	S_AXI3_AWID,
+		// input	wire [AW-1:0]	S_AXI3_AWADDR,
+		// input	wire	[3:0]	S_AXI3_AWLEN,
+		// input	wire	[2:0]	S_AXI3_AWSIZE,
+		// input	wire	[1:0]	S_AXI3_AWBURST,
+		// input	wire	[1:0]	S_AXI3_AWLOCK,
+		// input	wire	[3:0]	S_AXI3_AWCACHE,
+		// input	wire	[2:0]	S_AXI3_AWPROT,
+		// input	wire	[3:0]	S_AXI3_AWQOS,
+		//
+		input	wire			S_AXI3_WVALID,
+		output	wire			S_AXI3_WREADY,
+		input	wire	[IW-1:0]	S_AXI3_WID,
+		input	wire	[DW-1:0]	S_AXI3_WDATA,
+		input	wire	[DW/8-1:0]	S_AXI3_WSTRB,
+		input	wire			S_AXI3_WLAST,
+		// }}}
+		// Reordered write data port.  WID may now be discarded.
+		// {{{
+		output	reg			M_AXI_WVALID,
+		input	wire			M_AXI_WREADY,
+		output	reg	[IW-1:0]	M_AXI_WID,
+		output	reg	[DW-1:0]	M_AXI_WDATA,
+		output	reg	[DW/8-1:0]	M_AXI_WSTRB,
+		output	reg			M_AXI_WLAST
+		// }}}
+		// }}}
+	);
+
+	// Register declarations
+	// {{{
+	wire			awfifo_full, awfifo_empty;
+	reg			read_awid_fifo;
+	wire	[IW-1:0]	awfifo_id;
+	wire	[LGAWFIFO:0]	awfifo_fill;
+
+	genvar	gk;
+	reg			read_beat_fifo;
+
+	reg			cid_valid;
+	reg	[IW-1:0]	current_id;
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write address ID's go to an address ID FIFO
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	generate if (OPT_METHOD == MTHD_NONE)
+	begin : IGNORE_AW_CHANNEL
+		// No write address ID's to keep track of
+		// {{{
+		// These values are irrelevant.  They are placeholders, put here
+		// to keep the linter from complaining.
+
+		assign	awfifo_id = S_AXI3_AWID;
+		assign	S_AXI3_AWREADY = 1'b1;
+		assign	awfifo_full  = 0;
+		assign	awfifo_fill  = 0;
+		assign	awfifo_empty = !S_AXI3_AWVALID;
+		assign	cid_valid = S_AXI3_AWVALID;
+		always @(*)
+			cid_valid = S_AXI3_AWVALID;
+		always @(*)
+			current_id= S_AXI3_AWID;
+		always @(*)
+			read_awid_fifo = 0;
+
+		// Verilator lint_off UNUSED
+		wire	none_aw_unused;
+		assign	none_aw_unused = &{ 1'b0, awfifo_full, awfifo_fill,
+				awfifo_empty, read_awid_fifo, awfifo_id };
+		// }}}
+	end else begin : AWFIFO
+		////////////////////////////////////////////////////////////////
+		//
+		// Write address ID FIFO
+		// {{{
+		////////////////////////////////////////////////////////////////
+		//
+		//
+		sfifo #(
+			// {{{
+			.BW(IW),
+			.LGFLEN(LGAWFIFO),
+			.OPT_READ_ON_EMPTY(OPT_LOW_LATENCY)
+			// }}}
+		) awidfifo(
+			// {{{
+			.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+			.i_wr(S_AXI3_AWVALID && S_AXI3_AWREADY),
+				.i_data(S_AXI3_AWID),
+				.o_full(awfifo_full),
+				.o_fill(awfifo_fill),
+				.i_rd(read_awid_fifo),
+				.o_data( awfifo_id ),
+				.o_empty(awfifo_empty)
+			// }}}
+		);
+
+		assign	S_AXI3_AWREADY = !awfifo_full;
+		// }}}
+		////////////////////////////////////////////////////////////////
+		//
+		// Current ID -- what ID shall we output next?
+		// {{{
+		////////////////////////////////////////////////////////////////
+		//
+		// The current ID is given by the write address channel
+
+		initial	cid_valid = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			cid_valid <= 1'b0;
+		else if (read_awid_fifo)
+			cid_valid  <= !awfifo_empty;
+
+		// The current ID is given by the write address channel
+		always @(posedge S_AXI_ACLK)
+		if (read_awid_fifo)
+			current_id <= awfifo_id;
+
+		// }}}
+	end endgenerate
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write data channel processing and reordering
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate if (OPT_METHOD == MTHD_NONE)
+	begin : COPY_SW_TO_MW // Copy S_AXI3_W* values to M_AXIW*
+		// {{{
+		// {{{
+		always @(*)
+		begin
+			M_AXI_WVALID = S_AXI3_WVALID;
+			M_AXI_WID    = S_AXI3_WID;
+			M_AXI_WDATA  = S_AXI3_WDATA;
+			M_AXI_WSTRB  = S_AXI3_WSTRB;
+			M_AXI_WLAST  = S_AXI3_WLAST;
+
+			read_beat_fifo = 0;
+		end
+		// }}}
+		
+		assign	S_AXI3_WREADY = M_AXI_WREADY;
+
+		// Keep Verilator happy
+		// Verilator lint_off UNUSED
+		wire	none_unused;
+		assign	none_unused = &{ 1'b0, S_AXI_ACLK, S_AXI_ARESETN,
+				current_id, cid_valid, read_beat_fifo };
+		// Verilator lint_on  UNUSED
+		// }}}
+	end else if (OPT_METHOD == MTHD_SHIFT_REGISTER)
+	begin : SHIFT_REGISTER
+		// {{{
+
+		////////////////////////////////////////////////////////////////
+		//
+		// Local declarations
+		// {{{
+		////////////////////////////////////////////////////////////////
+		//
+		//
+		localparam	NSREG = (1<<LGWFIFO);
+		reg	[NSREG-1:0]	sr_advance;
+		reg	[NSREG-1:0]	sr_write;
+		reg	[NSREG-1:0]	sr_valid;
+		reg	[IW-1:0]	sr_id	[0:NSREG];
+		reg	[DW-1:0]	sr_data	[0:NSREG];
+		reg	[DW/8-1:0]	sr_strb	[0:NSREG];
+		reg	[NSREG-1:0]	sr_last;
+
+		integer	ik;
+		// }}}
+		////////////////////////////////////////////////////////////////
+		//
+		// Per-register-station logic
+		// {{{
+		////////////////////////////////////////////////////////////////
+		//
+		//
+
+		for (gk = 0; gk<NSREG; gk=gk+1)
+		begin
+
+			// sr_advance
+			// {{{
+			// Do we copy from the next station into this one or no?
+			always @(*)
+			begin
+				sr_advance[gk] = 0;
+				if ((gk > 0)&&(sr_advance[gk-1]))
+					sr_advance[gk] = 1;
+				if ((!M_AXI_WVALID || M_AXI_WREADY)
+					&& cid_valid && current_id == sr_id[gk])
+					sr_advance[gk] = 1;
+				if (!sr_valid[gk])
+					sr_advance[gk] = 0;
+			end
+			// }}}
+
+			// sw_write
+			// {{{
+			// Do we write new data into this station?
+			always @(*)
+			begin
+				sr_write[gk] = S_AXI3_WVALID && S_AXI3_WREADY;
+				if (sr_valid[gk] && (!sr_advance[gk]
+						||(gk < NSREG-1 && sr_valid[gk+1])))
+					sr_write[gk] = 0;
+				if (gk > 0 && (!sr_valid[gk-1]
+					|| (sr_advance[gk-1] && !sr_valid[gk])))
+					sr_write[gk] = 0;
+			end
+			// }}}
+
+			// sr_valid
+			// {{{
+			initial	sr_valid[gk] = 0;
+			always @(posedge S_AXI_ACLK)
+			if (!S_AXI_ARESETN)
+				sr_valid[gk] <= 0;
+			else if (sr_write[gk])
+				sr_valid[gk] <= 1;
+			else if (sr_advance[gk] && gk<NSREG-1)
+				sr_valid[gk] <= sr_valid[gk+1];
+			else if (sr_advance[gk])
+				sr_valid[gk] <= 0;
+			// }}}
+
+			// sr_id, sr_data, sr_strb, sr_last
+			// {{{
+			always @(posedge S_AXI_ACLK)
+			if (OPT_LOWPOWER && !S_AXI_ARESETN)
+			begin
+				sr_id[gk]   <= 0;
+				sr_data[gk] <= 0;
+				sr_strb[gk] <= 0;
+				sr_last[gk] <= 0;
+			end else if (sr_write[gk])
+			begin
+				sr_id[gk]   <= S_AXI3_WID;
+				sr_data[gk] <= S_AXI3_WDATA;
+				sr_strb[gk] <= S_AXI3_WSTRB;
+				sr_last[gk] <= S_AXI3_WLAST;
+			end else if ((gk < NSREG-1) && sr_advance[gk])
+			begin
+				sr_id[gk]   <= sr_id[gk+1];
+				sr_data[gk] <= sr_data[gk+1];
+				sr_strb[gk] <= sr_strb[gk+1];
+				sr_last[gk] <= sr_last[gk+1];
+
+				if (OPT_LOWPOWER && gk < NSREG-1 && !sr_valid[gk+1])
+				begin
+					// If we are running in low power,
+					// Keep every unused register == 0
+					sr_id[gk]   <= 0;
+					sr_data[gk] <= 0;
+					sr_strb[gk] <= 0;
+					sr_last[gk] <= 0;
+				end
+			end else if ((!OPT_LOWPOWER && !sr_valid[gk])
+				|| sr_write[gk])
+			begin
+				sr_id[gk]   <= S_AXI3_WID;
+				sr_data[gk] <= S_AXI3_WDATA;
+				sr_strb[gk] <= S_AXI3_WSTRB;
+				sr_last[gk] <= S_AXI3_WLAST;
+			end
+			// }}}
+		end
+		// }}}
+		////////////////////////////////////////////////////////////////
+		//
+		// Pick a register location to output
+		// {{{
+		////////////////////////////////////////////////////////////////
+		//
+		reg			known_next;
+		reg	[LGWFIFO-1:0]	sr_next;
+		always @(*)
+		begin
+			known_next = 0;
+			sr_next = -1;
+			for(ik=0; ik<NSREG; ik=ik+1)
+			if (!known_next && current_id == sr_id[ik])
+			begin
+				sr_next = ik[LGWFIFO-1:0];
+				known_next = sr_valid[ik];
+			end
+
+			if (!cid_valid)
+				known_next = 0;
+		end
+
+		assign	S_AXI3_WREADY = !sr_valid[NSREG-1];
+		// }}}
+		////////////////////////////////////////////////////////////////
+		//
+		//
+		// {{{
+		////////////////////////////////////////////////////////////////
+		//
+		//
+		always @(*)
+			read_awid_fifo = (!M_AXI_WVALID || M_AXI_WREADY)
+				&& (!cid_valid
+				|| (known_next && sr_last[sr_next]));
+
+		always @(*)
+			read_beat_fifo = (!M_AXI_WVALID || M_AXI_WREADY)
+				&&(known_next);
+
+		initial	M_AXI_WVALID = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			M_AXI_WVALID <= 0;
+		else if (!M_AXI_WVALID || M_AXI_WREADY)
+			M_AXI_WVALID <= known_next;
+
+		initial	M_AXI_WID   = 0;
+		initial	M_AXI_WDATA = 0;
+		initial	M_AXI_WSTRB = 0;
+		initial	M_AXI_WLAST = 0;
+		always @(posedge S_AXI_ACLK)
+		if (OPT_LOWPOWER && !S_AXI_ARESETN)
+		begin
+			// {{{
+			M_AXI_WID   <= 0;
+			M_AXI_WDATA <= 0;
+			M_AXI_WSTRB <= 0;
+			M_AXI_WLAST <= 0;
+			// }}}
+		end else if (!M_AXI_WVALID || M_AXI_WREADY)
+		begin
+			if (OPT_LOWPOWER && !known_next)
+			begin
+				// {{{
+				M_AXI_WID <= 0;
+				M_AXI_WDATA <= 0;
+				M_AXI_WSTRB <= 0;
+				M_AXI_WLAST <= 0;
+				// }}}
+			end else begin
+				// {{{
+				M_AXI_WID <= current_id;
+				// Verilator lint_off WIDTH
+				M_AXI_WDATA <= sr_data[sr_next];
+				M_AXI_WSTRB <= sr_strb[sr_next];
+				M_AXI_WLAST <= sr_last[sr_next];
+				// Verilator lint_on  WIDTH
+				// }}}
+			end
+		end
+		// }}}
+		// Verilator lint_off UNUSED
+		wire	unused_sreg;
+		assign	unused_sreg = &{ 1'b0, read_beat_fifo };
+		// Verilator lint_on  UNUSED
+`ifdef	FORMAL
+		always @(*)
+		if (S_AXI3_WVALID && S_AXI3_WREADY)
+			assert($onehot(sr_write));
+		else if (S_AXI_ARESETN)
+			assert(sr_write == 0);
+
+		always @(*)
+			assert(((sr_write << 1) & sr_valid) == 0);
+
+		reg	cvr_sreg_full;
+
+		initial	cvr_sreg_full = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			cvr_sreg_full <= 0;
+		else if (!S_AXI3_WREADY)
+			cvr_sreg_full <= 1;
+
+		always @(*)
+			cover(cvr_sreg_full && sr_valid == 0);
+		
+`endif
+		// }}}
+	end else if (OPT_METHOD == MTHD_PERID_FIFOS)
+	begin : MULTIPLE_FIFOS
+		// {{{
+		wire	[NUM_FIFOS-1:0]	wbfifo_full, wbfifo_empty, wbfifo_last;
+		// wire	[IW-1:0]	wbfifo_id	[0:NUM_FIFOS-1];
+		wire	[DW-1:0]	wbfifo_data	[0:NUM_FIFOS-1];
+		wire	[DW/8-1:0]	wbfifo_strb	[0:NUM_FIFOS-1];
+
+		////////////////////////////////////////////////////////////////
+		//
+		// The write beat FIFO
+		////////////////////////////////////////////////////////////////
+		// {{{
+		//
+		// Every write beat goes into a separate FIFO based on its ID
+		//
+		for (gk=0; gk < NUM_FIFOS; gk=gk+1)
+		begin
+		// {{{
+			wire	[LGWFIFO:0]	wbfifo_fill;
+
+			sfifo #(
+				.BW(DW+(DW/8)+1),
+				.LGFLEN(LGWFIFO),
+				.OPT_READ_ON_EMPTY(OPT_LOW_LATENCY)
+			) write_beat_fifo (
+				.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+				.i_wr(S_AXI3_WVALID && S_AXI3_WREADY && S_AXI3_WID == gk),
+				.i_data({ S_AXI3_WDATA, S_AXI3_WSTRB,
+					S_AXI3_WLAST }),
+				.o_full(wbfifo_full[gk]), .o_fill(wbfifo_fill),
+				.i_rd(read_beat_fifo && current_id == gk),
+				.o_data({ wbfifo_data[gk],
+					wbfifo_strb[gk], wbfifo_last[gk] }),
+				.o_empty(wbfifo_empty[gk])
+			);
+
+			// Verilator lint_off UNUSED
+			wire	unused;
+			assign	unused = &{ 1'b0, wbfifo_fill };
+			// Verilator lint_on  UNUSED
+			// }}}
+		end
+
+		assign	S_AXI3_WREADY = !wbfifo_full[S_AXI3_WID];
+		// }}}
+		////////////////////////////////////////////////////////////////
+		//
+		// Outgoing write data channel
+		// {{{
+		////////////////////////////////////////////////////////////////
+		//
+		//
+
+		always @(*)
+			read_awid_fifo = (!M_AXI_WVALID || M_AXI_WREADY)
+				&& (!cid_valid
+				|| (read_beat_fifo && wbfifo_last[current_id]));
+		// Write packets associated with the current ID can move forward
+		always @(*)
+			read_beat_fifo = (!M_AXI_WVALID || M_AXI_WREADY)
+				&&(cid_valid)&&(!wbfifo_empty[current_id]);
+
+		initial	M_AXI_WVALID = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			M_AXI_WVALID <= 0;
+		else if (!M_AXI_WVALID || M_AXI_WREADY)
+			M_AXI_WVALID <= read_beat_fifo;
+
+		initial	M_AXI_WID   = 0;
+		initial	M_AXI_WDATA = 0;
+		initial	M_AXI_WSTRB = 0;
+		initial	M_AXI_WLAST = 0;
+		always @(posedge S_AXI_ACLK)
+		if (OPT_LOWPOWER && !S_AXI_ARESETN)
+		begin
+			// {{{
+			M_AXI_WID   <= 0;
+			M_AXI_WDATA <= 0;
+			M_AXI_WSTRB <= 0;
+			M_AXI_WLAST <= 0;
+			// }}}
+		end else if (!M_AXI_WVALID || M_AXI_WREADY)
+		begin
+			// {{{
+			M_AXI_WID <= current_id;
+			M_AXI_WDATA <= wbfifo_data[current_id];
+			M_AXI_WSTRB <= wbfifo_strb[current_id];
+			M_AXI_WLAST <= wbfifo_last[current_id];
+
+			if (OPT_LOWPOWER && !read_beat_fifo)
+			begin
+				// {{{
+				M_AXI_WID   <= 0;
+				M_AXI_WDATA <= 0;
+				M_AXI_WSTRB <= 0;
+				M_AXI_WLAST <= 0;
+				// }}}
+			end
+			// }}}
+		end
+		// }}}
+		// }}}
+	end endgenerate
+	// }}}
+	// Make Verilator happy
+	// {{{
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, awfifo_fill };
+	// Verilator lint_on  UNUSED
+	// }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	reg				f_past_valid;
+	reg	[LGAWFIFO+LGWFIFO-1:0]	f_awid_count;
+	(* anyconst *) reg	[IW-1:0]	f_const_id;
+
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+
+	always @(*)
+	if (!f_past_valid)
+		assume(!S_AXI_ARESETN);
+
+	always @(posedge S_AXI_ACLK)
+	if (!f_past_valid || $past(!S_AXI_ARESETN))
+	begin
+		assume(!S_AXI3_AWVALID);
+		assume(!S_AXI3_WVALID);
+
+		assume(!M_AXI_WVALID);
+	end else begin
+		if ($past(S_AXI3_AWVALID && !S_AXI3_AWREADY))
+		begin
+			assume(S_AXI3_AWVALID);
+			assume($stable(S_AXI3_AWID));
+		end
+
+		if ($past(S_AXI3_WVALID && !S_AXI3_WREADY))
+		begin
+			assume(S_AXI3_WVALID);
+			assume($stable(S_AXI3_WID));
+			assume($stable(S_AXI3_WDATA));
+			assume($stable(S_AXI3_WSTRB));
+			assume($stable(S_AXI3_WLAST));
+		end
+
+		if ($past(M_AXI_WVALID && !M_AXI_WREADY))
+		begin
+			assert(M_AXI_WVALID);
+			assert($stable(M_AXI_WID));
+			assert($stable(M_AXI_WDATA));
+			assert($stable(M_AXI_WSTRB));
+			assert($stable(M_AXI_WLAST));
+		end
+	end
+
+	generate if (OPT_METHOD != MTHD_NONE)
+	begin : F_FIFO_CHECK
+		wire	[LGWFIFO:0]	f_ckfifo_fill;
+		wire	[LGWFIFO:0]	f_ckfifo_full, f_ckfifo_empty;
+		wire	[IW-1:0]	f_ckfifo_id;
+		wire	[DW-1:0]	f_ckfifo_data;
+		wire	[DW/8-1:0]	f_ckfifo_strb;
+		wire			f_ckfifo_last;
+
+		sfifo #(
+			.BW(IW + DW + (DW/8) + 1),
+			.LGFLEN(LGWFIFO),
+			.OPT_READ_ON_EMPTY(OPT_LOW_LATENCY)
+		) f_checkfifo (
+			.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+			.i_wr(S_AXI3_WVALID && S_AXI3_WREADY
+							&& S_AXI3_WID == f_const_id),
+			.i_data({ S_AXI3_WID, S_AXI3_WDATA, S_AXI3_WSTRB, S_AXI3_WLAST }),
+			.o_full(f_ckfifo_full), .o_fill(f_ckfifo_fill),
+			.i_rd(M_AXI_WVALID && M_AXI_WREADY
+						&& M_AXI_WID == f_const_id),
+			.o_data({ f_ckfifo_id, f_ckfifo_data, f_ckfifo_strb,
+					f_ckfifo_last }),
+			.o_empty(f_ckfifo_empty)
+		);
+
+		always @(*)
+		if (S_AXI_ARESETN && M_AXI_WVALID && M_AXI_WID == f_const_id)
+		begin
+			assert(!f_ckfifo_empty);
+			assert(f_ckfifo_id   == M_AXI_WID);
+			assert(f_ckfifo_data == M_AXI_WDATA);
+			assert(f_ckfifo_strb == M_AXI_WSTRB);
+			assert(f_ckfifo_last == M_AXI_WLAST);
+		end
+	end endgenerate
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_awid_count = 0;
+	else case({S_AXI3_AWVALID&& S_AXI3_AWREADY && S_AXI3_AWID == f_const_id,
+			M_AXI_WVALID && M_AXI_WREADY && M_AXI_WLAST
+			&& M_AXI_WID == f_const_id })
+	2'b01: f_awid_count <= f_awid_count - 1;
+	2'b10: f_awid_count <= f_awid_count + 1;
+	default begin end
+	endcase
+
+	always @(*)
+	if (M_AXI_WVALID && M_AXI_WID == f_const_id)
+		assert(f_awid_count > 0);
+
+	generate if (OPT_LOWPOWER)
+	begin : F_LOWPOWER_CHECK
+		always @(*)
+		if (!S_AXI3_AWVALID)
+			assume(S_AXI3_AWID == 0);
+
+		always @(*)
+		if (!S_AXI3_WVALID)
+		begin
+			assume(S_AXI3_WID   == 0);
+			assume(S_AXI3_WDATA == 0);
+			assume(S_AXI3_WSTRB == 0);
+			assume(S_AXI3_WLAST == 0);
+		end
+
+		always @(*)
+		if (!M_AXI_WVALID)
+		begin
+			assert(M_AXI_WID   == 0);
+			assert(M_AXI_WDATA == 0);
+			assert(M_AXI_WSTRB == 0);
+			assert(M_AXI_WLAST == 0);
+		end
+
+	end endgenerate
+
+`endif
+	// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axi_addr.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axi_addr.v
new file mode 100644
index 0000000..99abd8d
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axi_addr.v
@@ -0,0 +1,240 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axi_addr.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	The AXI (full) standard has some rather complicated addressing
+//		modes, where the address can either be FIXED, INCRementing, or
+//	even where it can WRAP around some boundary.  When in either INCR or
+//	WRAP modes, the next address must always be aligned.  In WRAP mode,
+//	the next address calculation needs to wrap around a given value, and
+//	that value is dependent upon the burst size (i.e. bytes per beat) and
+//	length (total numbers of beats).  Since this calculation can be
+//	non-trivial, and since it needs to be done multiple times, the logic
+//	below captures it for every time it might be needed.
+//
+// 20200918 - modified to accommodate (potential) AXI3 burst lengths
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+// }}}
+module	axi_addr #(
+		// {{{
+		parameter	AW = 32,
+				DW = 32,
+		parameter [0:0]	OPT_AXI3 = 1'b0,
+		localparam	LENB = 8
+		// }}}
+	) (
+		// {{{
+		input	wire	[AW-1:0]	i_last_addr,
+		input	wire	[2:0]		i_size, // 1b, 2b, 4b, 8b, etc
+		input	wire	[1:0]		i_burst, // fixed, incr, wrap, reserved
+		input	wire	[LENB-1:0]	i_len,
+		output	reg	[AW-1:0]	o_next_addr
+		// }}}
+	);
+
+	// Parameter/register declarations
+	// {{{
+	localparam		DSZ = $clog2(DW)-3;
+	localparam [1:0]	FIXED     = 2'b00;
+	localparam [1:0]	INCREMENT = 2'b01;
+	localparam [1:0]	WRAP      = 2'b10;
+
+	reg	[AW-1:0]	wrap_mask, increment;
+	// }}}
+
+	// Address increment
+	// {{{
+	always @(*)
+	begin
+		increment = 0;
+		if (i_burst != 0)
+		begin
+			// Addresses increment from one beat to the next
+			// {{{
+			if (DSZ == 0)
+				increment = 1;
+			else if (DSZ == 1)
+				increment = (i_size[0]) ? 2 : 1;
+			else if (DSZ == 2)
+				increment = (i_size[1]) ? 4 : ((i_size[0]) ? 2 : 1);
+			else if (DSZ == 3)
+				case(i_size[1:0])
+				2'b00: increment = 1;
+				2'b01: increment = 2;
+				2'b10: increment = 4;
+				2'b11: increment = 8;
+				endcase
+			else
+				increment = (1<<i_size);
+			// }}}
+		end
+	end
+	// }}}
+
+	// wrap_mask
+	// {{{
+	// The wrap_mask is used to determine which bits remain stable across
+	// the burst, and which are allowed to change.  It is only used during
+	// wrapped addressing.
+	always @(*)
+	begin
+		// Start with the default, minimum mask
+		wrap_mask = 1;
+
+		/*
+		// Here's the original code.  It works, but it's
+		// not economical (uses too many LUTs)
+		//
+		if (i_len[3:0] == 1)
+			wrap_mask = (1<<(i_size+1));
+		else if (i_len[3:0] == 3)
+			wrap_mask = (1<<(i_size+2));
+		else if (i_len[3:0] == 7)
+			wrap_mask = (1<<(i_size+3));
+		else if (i_len[3:0] == 15)
+			wrap_mask = (1<<(i_size+4));
+		wrap_mask = wrap_mask - 1;
+		*/
+
+		// Here's what we *want*
+		//
+		// wrap_mask[i_size:0] = -1;
+		//
+		// On the other hand, since we're already guaranteed that our
+		// addresses are aligned, do we really care about
+		// wrap_mask[i_size-1:0] ?
+
+		// What we want:
+		//
+		// wrap_mask[i_size+3:i_size] |= i_len[3:0]
+		//
+		// We could simplify this to
+		//
+		// wrap_mask = wrap_mask | (i_len[3:0] << (i_size));
+		//
+		// But verilator complains about the left-hand side of
+		// the shift having only 3 bits.
+		//
+		if (DSZ < 2)
+			wrap_mask = wrap_mask | ({{(AW-4){1'b0}},i_len[3:0]} << (i_size[0]));
+		else if (DSZ < 4)
+			wrap_mask = wrap_mask | ({{(AW-4){1'b0}},i_len[3:0]} << (i_size[1:0]));
+		else
+			wrap_mask = wrap_mask | ({{(AW-4){1'b0}},i_len[3:0]} << (i_size));
+
+		if (AW > 12)
+			wrap_mask[((AW>12)?(AW-1):(AW-1)):((AW>12)?12:(AW-1))] = 0;
+	end
+	// }}}
+
+	// o_next_addr
+	// {{{
+	always @(*)
+	begin
+		o_next_addr = i_last_addr + increment;
+		if (i_burst != FIXED)
+		begin
+			// Align subsequent beats in any burst
+			// {{{
+			//
+			// We use the bus size here to simplify the logic
+			// required in case the bus is smaller than the
+			// maximum.  This depends upon AxSIZE being less than
+			// $clog2(DATA_WIDTH/8).
+			if (DSZ < 2)
+			begin
+				// {{{
+				// Align any subsequent address
+				if (i_size[0])
+					o_next_addr[0] = 0;
+				// }}}
+			end else if (DSZ < 4)
+			begin
+				// {{{
+				// Align any subsequent address
+				case(i_size[1:0])
+				2'b00:  o_next_addr = o_next_addr;
+				2'b01:  o_next_addr[  0] = 0;
+				2'b10:  o_next_addr[(AW-1>1) ? 1 : (AW-1):0]= 0;
+				2'b11:  o_next_addr[(AW-1>2) ? 2 : (AW-1):0]= 0;
+				endcase
+				// }}}
+			end else begin
+				// {{{
+				// Align any subsequent address
+				case(i_size)
+				3'b001:  o_next_addr[  0] = 0;
+				3'b010:  o_next_addr[(AW-1>1) ? 1 : (AW-1):0]=0;
+				3'b011:  o_next_addr[(AW-1>2) ? 2 : (AW-1):0]=0;
+				3'b100:  o_next_addr[(AW-1>3) ? 3 : (AW-1):0]=0;
+				3'b101:  o_next_addr[(AW-1>4) ? 4 : (AW-1):0]=0;
+				3'b110:  o_next_addr[(AW-1>5) ? 5 : (AW-1):0]=0;
+				3'b111:  o_next_addr[(AW-1>6) ? 6 : (AW-1):0]=0;
+				default: o_next_addr = o_next_addr;
+				endcase
+				// }}}
+			end
+			// }}}
+		end
+
+		// WRAP addressing
+		// {{{
+		if (i_burst[1])
+		begin
+			// WRAP!
+			o_next_addr[AW-1:0] = (i_last_addr & ~wrap_mask)
+					| (o_next_addr & wrap_mask);
+		end
+		// }}}
+
+		// Guarantee only the bottom 12 bits change
+		// {{{
+		// This is really a logic simplification.  AXI bursts aren't
+		// allowed to cross 4kB boundaries.  Given that's the case,
+		// we don't have to suffer from the propagation across all
+		// AW bits, and can limit any address propagation to just the
+		// lower 12 bits
+		if (AW > 12)
+			o_next_addr[AW-1:((AW>12)? 12:(AW-1))]
+				= i_last_addr[AW-1:((AW>12) ? 12:(AW-1))];
+		// }}}
+	end
+	// }}}
+
+	// Make Verilator happy
+	// {{{
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = (LENB <= 4) ? {1'b0, i_len[0] }
+				: &{ 1'b0, i_len[LENB-1:4], i_len[0] };
+	// Verilator lint_on UNUSED
+	// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axidma.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axidma.v
new file mode 100644
index 0000000..5b2b584
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axidma.v
@@ -0,0 +1,2742 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axidma.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	To move memory from one location to another, at high speed.
+//		This is not a memory to stream, nor a stream to memory core,
+//	but rather a memory to memory core.
+//
+//
+// Registers:
+//
+//	0. Control
+//		8b	KEY
+//			3'b PROT
+//			4'b QOS
+//		1b	Abort: Either aborting or aborted
+//		1b	Err: Ended on an error
+//		1b	Busy
+//		1b	Interrupt Enable
+//		1b	Interrupt Clear
+//		1b	Start
+//	1. Unused
+//	2-3. Source address, low and then high 64-bit words
+//		(Last value read address)
+//	4-5. Destination address, low and then high 64-bit words
+//		(Next value to write address)
+//	6-7. Length, low and then high words
+//		(Total number minus successful writes)
+//
+// Performance goals:
+//	100% throughput
+//	Stay off the bus until you can drive it hard
+// Other goals:
+//	Be both AXI3 and AXI4 capable
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// `define			AXI3
+//
+module	axidma #(
+		parameter	C_AXI_ID_WIDTH = 1,
+		parameter	C_AXI_ADDR_WIDTH = 32,
+		parameter	C_AXI_DATA_WIDTH = 32,
+		//
+		// These two "parameters" really aren't things that can be
+		// changed externally.  They control the size of the AXI4-lite
+		// port.  Internally, it's defined to have 8, 32-bit registers.
+		// The registers are configured wide enough to support 64-bit
+		// AXI addressing.  Similarly, the AXI-lite data width is fixed
+		// at 32-bits.
+		localparam	C_AXIL_ADDR_WIDTH = 5,
+		localparam	C_AXIL_DATA_WIDTH = 32,
+		//
+		// OPT_UNALIGNED turns on support for unaligned addresses,
+		// whether source, destination, or length parameters.
+		parameter [0:0]	OPT_UNALIGNED = 1'b1,
+		//
+		// OPT_WRAPMEM controls what happens if the transfer runs off
+		// of the end of memory.  If set, the transfer will continue
+		// again from the beginning of memory.  If clear, the transfer
+		// will be aborted with an error if either read or write
+		// address ever get this far.
+		parameter [0:0]	OPT_WRAPMEM = 1'b1,
+		//
+		// LGMAXBURST controls the size of the maximum burst produced
+		// by this core.  Specifically, its the log (based 2) of that
+		// maximum size.  Hence, for AXI4, this size must be 8
+		// (i.e. 2^8 or 256 beats) or less.  For AXI3, the size must
+		// be 4 or less.  Tests have verified performance for
+		// LGMAXBURST as low as 2.  While I expect it to fail at
+		// LGMAXBURST=0, I haven't verified at what value this burst
+		// parameter is too small.
+`ifdef	AXI3
+		parameter	LGMAXBURST=4,	// 16 beats max
+`else
+		parameter	LGMAXBURST=8,	// 256 beats
+`endif
+		// The number of beats in this maximum burst size is
+		// automatically determined from LGMAXBURST, and so its
+		// forced to be a power of two this way.
+		localparam	MAXBURST=(1<<LGMAXBURST),
+		//
+		// LGFIFO: This is the (log-based-2) size of the internal FIFO.
+		// Hence if LGFIFO=8, the internal FIFO will have 256 elements
+		// (words) in it.  High throughput transfers are accomplished
+		// by first storing data into a FIFO, then once a full burst
+		// size is available bursting that data over the bus.  In
+		// order to be able to keep receiving data while bursting it
+		// out, the FIFO size must be at least twice the size of the
+		// maximum burst size.  Larger sizes are possible as well.
+		parameter	LGFIFO = LGMAXBURST+1,	// 512 element FIFO
+		//
+		// LGLEN: specifies the number of bits in the transfer length
+		// register.  If a transfer cannot be specified in LGLEN bits,
+		// it won't happen.  LGLEN must be less than or equal to the
+		// address width.
+		parameter	LGLEN = C_AXI_ADDR_WIDTH,
+		//
+		// AXI uses ID's to transfer information.  This core rather
+		// ignores them.  Instead, it uses a constant ID for all
+		// transfers.  The following two parameters control that ID.
+		parameter	[C_AXI_ID_WIDTH-1:0]	AXI_READ_ID = 0,
+		parameter	[C_AXI_ID_WIDTH-1:0]	AXI_WRITE_ID = 0,
+		//
+		// The "ABORT_KEY" is a byte that, if written to the control
+		// word while the core is running, will cause the data transfer
+		// to be aborted.
+		parameter	[7:0]			ABORT_KEY  = 8'h6d,
+		//
+		localparam	ADDRLSB= $clog2(C_AXI_DATA_WIDTH)-3,
+		localparam	AXILLSB= $clog2(C_AXIL_DATA_WIDTH)-3,
+		localparam	LGLENW= LGLEN-ADDRLSB
+	) (
+		input	wire	S_AXI_ACLK,
+		input	wire	S_AXI_ARESETN,
+		//
+		// The AXI4-lite control interface
+		input	wire				S_AXIL_AWVALID,
+		output	wire				S_AXIL_AWREADY,
+		input	wire [C_AXIL_ADDR_WIDTH-1:0]	S_AXIL_AWADDR,
+		input	wire 	[2:0]			S_AXIL_AWPROT,
+		//
+		input	wire				S_AXIL_WVALID,
+		output	wire				S_AXIL_WREADY,
+		input	wire [C_AXIL_DATA_WIDTH-1:0]	S_AXIL_WDATA,
+		input	wire [C_AXIL_DATA_WIDTH/8-1:0]	S_AXIL_WSTRB,
+		//
+		output	reg				S_AXIL_BVALID,
+		input	wire				S_AXIL_BREADY,
+		output	reg	[1:0]			S_AXIL_BRESP,
+		//
+		input	wire				S_AXIL_ARVALID,
+		output	wire				S_AXIL_ARREADY,
+		input	wire [C_AXIL_ADDR_WIDTH-1:0]	S_AXIL_ARADDR,
+		input	wire 	[2:0]			S_AXIL_ARPROT,
+		//
+		output	reg				S_AXIL_RVALID,
+		input	wire				S_AXIL_RREADY,
+		output	reg [C_AXIL_DATA_WIDTH-1:0]	S_AXIL_RDATA,
+		output	reg	[1:0]			S_AXIL_RRESP,
+		//
+		//
+		// The AXI Master (DMA) interface
+		output	reg				M_AXI_AWVALID,
+		input	wire				M_AXI_AWREADY,
+		output	reg	[C_AXI_ID_WIDTH-1:0]	M_AXI_AWID,
+		output	reg	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_AWADDR,
+`ifdef	AXI3
+		output	reg	[3:0]			M_AXI_AWLEN,
+`else
+		output	reg	[7:0]			M_AXI_AWLEN,
+`endif
+		output	reg	[2:0]			M_AXI_AWSIZE,
+		output	reg	[1:0]			M_AXI_AWBURST,
+		output	reg				M_AXI_AWLOCK,
+		output	reg	[3:0]			M_AXI_AWCACHE,
+		output	reg	[2:0]			M_AXI_AWPROT,
+		output	reg	[3:0]			M_AXI_AWQOS,
+		//
+		//
+		output	reg				M_AXI_WVALID,
+		input	wire				M_AXI_WREADY,
+`ifdef	AXI3
+		output	reg	[C_AXI_ID_WIDTH-1:0]	M_AXI_WID,
+`endif
+		output	reg	[C_AXI_DATA_WIDTH-1:0]	M_AXI_WDATA,
+		output	reg [C_AXI_DATA_WIDTH/8-1:0]	M_AXI_WSTRB,
+		output	reg				M_AXI_WLAST,
+		//
+		//
+		input	wire				M_AXI_BVALID,
+		output	reg				M_AXI_BREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_BID,
+		input	wire	[1:0]			M_AXI_BRESP,
+		//
+		//
+		output	reg				M_AXI_ARVALID,
+		input	wire				M_AXI_ARREADY,
+		output	reg	[C_AXI_ID_WIDTH-1:0]	M_AXI_ARID,
+		output	reg	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_ARADDR,
+`ifdef	AXI3
+		output	reg	[3:0]			M_AXI_ARLEN,
+`else
+		output	reg	[7:0]			M_AXI_ARLEN,
+`endif
+		output	reg	[2:0]			M_AXI_ARSIZE,
+		output	reg	[1:0]			M_AXI_ARBURST,
+		output	reg				M_AXI_ARLOCK,
+		output	reg	[3:0]			M_AXI_ARCACHE,
+		output	reg	[2:0]			M_AXI_ARPROT,
+		output	reg	[3:0]			M_AXI_ARQOS,
+		//
+		input	wire				M_AXI_RVALID,
+		output	reg				M_AXI_RREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_RID,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_RDATA,
+		input	wire				M_AXI_RLAST,
+		input	wire	[1:0]			M_AXI_RRESP,
+		//
+		output	reg				o_int);
+
+	localparam	[2:0]	CTRL_ADDR   = 3'b000,
+				UNUSED_ADDR = 3'b001,
+				SRCLO_ADDR  = 3'b010,
+				SRCHI_ADDR  = 3'b011,
+				DSTLO_ADDR  = 3'b100,
+				DSTHI_ADDR  = 3'b101,
+				LENLO_ADDR  = 3'b110,
+				LENHI_ADDR  = 3'b111;
+	localparam		CTRL_START_BIT = 0,
+				CTRL_BUSY_BIT  = 0,
+				CTRL_INT_BIT   = 1,
+				CTRL_INTEN_BIT = 2,
+				CTRL_ABORT_BIT = 3,
+				CTRL_ERR_BIT   = 4;
+	localparam	[1:0]	AXI_INCR = 2'b01, AXI_OKAY = 2'b00;
+
+	wire	i_clk   = S_AXI_ACLK;
+	wire	i_reset = !S_AXI_ARESETN;
+
+	reg	axil_write_ready, axil_read_ready;
+	reg	[2*C_AXIL_DATA_WIDTH-1:0] wide_src, wide_dst, wide_len;
+	reg	[2*C_AXIL_DATA_WIDTH-1:0] new_widesrc, new_widedst, new_widelen;
+
+	reg	r_busy, r_err, r_abort, w_start, r_int, r_int_enable,
+				r_done, last_write_ack, zero_len;
+	reg	[3:0]		r_qos;
+	reg	[2:0]		r_prot;
+	reg	[LGLEN-1:0]	r_len;	// Length of transfer in octets
+	reg	[C_AXI_ADDR_WIDTH-1:0]	r_src_addr, r_dst_addr;
+
+	reg			fifo_reset;
+	wire	[LGFIFO:0]	fifo_fill;
+	reg	[LGFIFO:0]	fifo_space_available;
+	reg	[LGFIFO:0]	fifo_data_available,
+				next_fifo_data_available;
+	wire			fifo_full, fifo_empty;
+	reg	[8:0]		write_count;
+	//
+	reg				phantom_read, w_start_read,
+					no_read_bursts_outstanding;
+	reg	[LGLEN:0]		readlen_b;
+	reg	[LGLENW:0]		readlen_w, initial_readlen_w;
+	reg	[C_AXI_ADDR_WIDTH:0]	read_address;
+	reg	[LGLENW:0]		reads_remaining_w,
+					read_beats_remaining_w,
+					read_bursts_outstanding;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	read_distance_to_boundary_b;
+	reg				reads_remaining_nonzero;
+	//
+	reg				phantom_write, w_write_start;
+	reg	[C_AXI_ADDR_WIDTH:0]	write_address;
+	reg	[LGLENW:0]		writes_remaining_w,
+					write_bursts_outstanding;
+	reg	[LGLENW:0]		write_burst_length;
+	reg				write_requests_remaining;
+	reg	[LGLEN:0]		writelen_b;
+	reg	[LGLENW:0]		write_beats_remaining;
+
+	wire				awskd_valid;
+	wire	[C_AXIL_ADDR_WIDTH-AXILLSB-1:0]	awskd_addr;
+	wire				wskd_valid;
+	wire	[C_AXIL_DATA_WIDTH-1:0]	wskd_data;
+	wire [C_AXIL_DATA_WIDTH/8-1:0]	wskd_strb;
+
+	wire	arskd_valid;
+	wire	[C_AXIL_ADDR_WIDTH-AXILLSB-1:0]	arskd_addr;
+	//
+	reg				r_partial_in_valid;
+	reg				r_write_fifo, r_read_fifo;
+	reg				r_partial_outvalid;
+	reg [C_AXI_DATA_WIDTH/8-1:0]	r_first_wstrb,
+					r_last_wstrb;
+	reg				extra_realignment_write,
+					extra_realignment_read;
+	reg	[2*ADDRLSB+2:0]		write_realignment;
+	reg				last_read_beat;
+	reg				clear_read_pipeline;
+	reg				last_write_burst;
+
+	//
+	// Push some write length calculations across clocks
+	reg	[LGLENW:0]		w_writes_remaining_w;
+	reg				multiple_write_bursts_remaining,
+					first_write_burst;
+	reg	[LGMAXBURST:0]		initial_write_distance_to_boundary_w,
+					first_write_len_w;
+
+
+
+
+
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-Lite control interface
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_ADDR_WIDTH-AXILLSB))
+	axilawskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_AWVALID), .o_ready(S_AXIL_AWREADY),
+		.i_data(S_AXIL_AWADDR[C_AXIL_ADDR_WIDTH-1:AXILLSB]),
+		.o_valid(awskd_valid), .i_ready(axil_write_ready),
+		.o_data(awskd_addr));
+
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_DATA_WIDTH+C_AXIL_DATA_WIDTH/8))
+	axilwskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_WVALID), .o_ready(S_AXIL_WREADY),
+		.i_data({ S_AXIL_WSTRB, S_AXIL_WDATA }),
+		.o_valid(wskd_valid), .i_ready(axil_write_ready),
+		.o_data({ wskd_strb, wskd_data }));
+
+	always  @(*)
+	begin
+		axil_write_ready = !S_AXIL_BVALID || S_AXIL_BREADY;;
+		if (!awskd_valid || !wskd_valid)
+			axil_write_ready = 0;
+	end
+
+	initial	S_AXIL_BVALID = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		S_AXIL_BVALID <= 1'b0;
+	else if (!S_AXIL_BVALID || S_AXIL_BREADY)
+		S_AXIL_BVALID <= axil_write_ready;
+
+	always @(*)
+		S_AXIL_BRESP = AXI_OKAY;
+
+	always @(*)
+	begin
+		w_start = !r_busy && axil_write_ready && wskd_strb[0]
+				&& wskd_data[CTRL_START_BIT]
+				&& (awskd_addr == CTRL_ADDR);
+		if (r_err && (!wskd_strb[0] || !wskd_data[CTRL_ERR_BIT]))
+			w_start = 0;
+		if (zero_len)
+			w_start = 0;
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		r_err <= 1'b0;
+	else if (!r_busy && axil_write_ready)
+		r_err <= (r_err) && (!wskd_strb[0] || !wskd_data[CTRL_ERR_BIT]);
+	else if (r_busy)
+	begin
+		if (M_AXI_BVALID && M_AXI_BRESP[1])
+			r_err <= 1'b1;
+		if (M_AXI_RVALID && M_AXI_RRESP[1])
+			r_err <= 1'b1;
+
+		if (!OPT_WRAPMEM && write_address[C_AXI_ADDR_WIDTH]
+			&& write_requests_remaining)
+			r_err <= 1'b1;
+		if (!OPT_WRAPMEM && read_address[C_AXI_ADDR_WIDTH]
+			&& reads_remaining_nonzero)
+			r_err <= 1'b1;
+	end
+
+	initial	r_busy = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		r_busy <= 1'b0;
+	else if (!r_busy && axil_write_ready)
+		r_busy <= w_start;
+	else if (r_busy)
+	begin
+		if (M_AXI_BVALID && M_AXI_BREADY && last_write_ack)
+			r_busy <= 1'b0;
+		if (r_done)
+			r_busy <= 1'b0;
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (i_reset || !r_int_enable || !r_busy)
+		o_int <= 0;
+	else if (r_done)
+		o_int <= 1'b1;
+	else
+		o_int <= (last_write_ack && M_AXI_BVALID && M_AXI_BREADY);
+
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		r_int <= 0;
+	else if (!r_busy)
+	begin
+		if (axil_write_ready && awskd_addr == CTRL_ADDR
+			&& wskd_strb[0])
+		begin
+			if (wskd_data[CTRL_START_BIT])
+				r_int <= 0;
+			else if (wskd_data[CTRL_INT_BIT])
+				r_int <= 0;
+		end
+	end else if (r_done)
+		r_int <= 1'b1;
+	else
+		r_int <= (last_write_ack && M_AXI_BVALID && M_AXI_BREADY);
+
+	initial	r_abort = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		r_abort <= 1'b0;
+	else if (!r_busy)
+	begin
+		if (axil_write_ready && awskd_addr == CTRL_ADDR
+			&& wskd_strb[0])
+		begin
+			if(wskd_data[CTRL_START_BIT]
+				||wskd_data[CTRL_ABORT_BIT]
+				||wskd_data[CTRL_ERR_BIT])
+			r_abort <= 0;
+		end
+	end else if (!r_abort)
+		r_abort <= (axil_write_ready && awskd_addr == CTRL_ADDR)
+			&&(wskd_strb[3] && wskd_data[31:24] == ABORT_KEY);
+
+	wire	[C_AXIL_DATA_WIDTH-1:0]	newsrclo, newsrchi,
+					newdstlo, newdsthi, newlenlo, newlenhi;
+
+	always @(*)
+	begin
+		wide_src = 0;
+		wide_dst = 0;
+		wide_len = 0;
+
+		wide_src[C_AXI_ADDR_WIDTH-1:0] = r_src_addr;
+		wide_dst[C_AXI_ADDR_WIDTH-1:0] = r_dst_addr;
+		wide_len[LGLEN-1:0] = r_len;
+
+		if (!OPT_UNALIGNED)
+		begin
+			wide_src[ADDRLSB-1:0] <= 0;
+			wide_dst[ADDRLSB-1:0] <= 0;
+			wide_len[ADDRLSB-1:0] <= 0;
+		end
+	end
+
+	assign	newsrclo = apply_wstrb(
+			wide_src[C_AXIL_DATA_WIDTH-1:0],
+			wskd_data, wskd_strb);
+	assign	newsrchi = apply_wstrb(
+			wide_src[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH],
+			wskd_data, wskd_strb);
+	assign	newdstlo = apply_wstrb(
+			wide_dst[C_AXIL_DATA_WIDTH-1:0],
+			wskd_data, wskd_strb);
+	assign	newdsthi = apply_wstrb(
+			wide_dst[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH],
+			wskd_data, wskd_strb);
+	assign	newlenlo = apply_wstrb(
+			wide_len[C_AXIL_DATA_WIDTH-1:0],
+			wskd_data, wskd_strb);
+	assign	newlenhi = apply_wstrb(
+			wide_len[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH],
+			wskd_data, wskd_strb);
+
+	always @(*)
+	begin
+		new_widesrc = wide_src;
+		new_widedst = wide_dst;
+		new_widelen = wide_len;
+
+		if (!awskd_addr[0])
+		begin
+			new_widesrc[C_AXIL_DATA_WIDTH-1:0] = newsrclo;
+			new_widedst[C_AXIL_DATA_WIDTH-1:0] = newdstlo;
+			new_widelen[C_AXIL_DATA_WIDTH-1:0] = newlenlo;
+		end else begin
+			new_widesrc[2*C_AXIL_DATA_WIDTH-1
+					:C_AXIL_DATA_WIDTH] = newsrchi;
+			new_widedst[2*C_AXIL_DATA_WIDTH-1
+					:C_AXIL_DATA_WIDTH] = newdsthi;
+			new_widelen[2*C_AXIL_DATA_WIDTH-1
+					:C_AXIL_DATA_WIDTH] = newlenhi;
+		end
+
+		new_widesrc[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH] = 0;
+		new_widedst[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH] = 0;
+		new_widelen[2*C_AXIL_DATA_WIDTH-1:LGLEN] = 0;
+
+		if (!OPT_UNALIGNED)
+		begin
+			new_widesrc[ADDRLSB-1:0] <= 0;
+			new_widedst[ADDRLSB-1:0] <= 0;
+			new_widelen[ADDRLSB-1:0] <= 0;
+		end
+	end
+
+	initial	r_len    = 0;
+	initial	zero_len = 1;
+	initial	r_src_addr = 0;
+	initial	r_dst_addr = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+	begin
+		r_len <= 0;
+		zero_len <= 1;
+		r_prot <= 0;
+		r_qos  <= 0;
+		r_src_addr <= 0;
+		r_dst_addr <= 0;
+		r_int_enable <= 0;
+	end else if (!r_busy && axil_write_ready)
+	begin
+		case(awskd_addr)
+		CTRL_ADDR: begin
+				if (wskd_strb[2])
+				begin
+					r_prot <= wskd_data[22:20];
+					r_qos  <= wskd_data[19:16];
+				end
+			if (wskd_strb[0])
+				r_int_enable <= wskd_data[CTRL_INTEN_BIT];
+			end
+		SRCLO_ADDR: begin
+			r_src_addr <= new_widesrc[C_AXI_ADDR_WIDTH-1:0];
+			end
+		SRCHI_ADDR: if (C_AXI_ADDR_WIDTH > C_AXIL_DATA_WIDTH) begin
+			r_src_addr <= new_widesrc[C_AXI_ADDR_WIDTH-1:0];
+			end
+		DSTLO_ADDR: begin
+			r_dst_addr <= new_widedst[C_AXI_ADDR_WIDTH-1:0];
+			end
+		DSTHI_ADDR: if (C_AXI_ADDR_WIDTH > C_AXIL_DATA_WIDTH) begin
+			r_dst_addr <= new_widedst[C_AXI_ADDR_WIDTH-1:0];
+			end
+		LENLO_ADDR: begin
+			r_len    <= new_widelen[LGLEN-1:0];
+			zero_len <= (new_widelen == 0);
+			end
+		LENHI_ADDR: if (LGLEN > C_AXIL_DATA_WIDTH) begin
+			r_len    <= new_widelen[LGLEN-1:0];
+			zero_len <= (new_widelen == 0);
+			end
+		default: begin end
+		endcase
+	end else if (r_busy)
+	begin
+		r_dst_addr <= write_address[C_AXI_ADDR_WIDTH-1:0];
+		if (writes_remaining_w[LGLENW])
+			r_len <= -1;
+		else
+			r_len <= { writes_remaining_w[LGLENW-1:0],
+						{(ADDRLSB){1'b0}} };
+		if (OPT_UNALIGNED)
+			r_len[ADDRLSB-1:0] <= 0;
+
+		zero_len   <= (writes_remaining_w == 0);
+
+		if (M_AXI_RVALID && M_AXI_RREADY && !M_AXI_RRESP[1])
+		begin
+			r_src_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+				<= r_src_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]+1;
+			r_src_addr[ADDRLSB-1:0] <= 0;
+		end
+	end
+
+	always @(*)
+		S_AXIL_BRESP = 2'b00;
+
+	function [C_AXIL_DATA_WIDTH-1:0]	apply_wstrb;
+		input [C_AXIL_DATA_WIDTH-1:0]	prior_data;
+		input [C_AXIL_DATA_WIDTH-1:0]	new_data;
+		input [C_AXIL_DATA_WIDTH/8-1:0]	wstrb;
+
+		integer	k;
+		for(k=0; k<C_AXIL_DATA_WIDTH/8; k=k+1)
+		begin
+			apply_wstrb[k*8 +: 8] = wstrb[k] ? new_data[k*8 +: 8]
+				: prior_data[k*8 +: 8];
+		end
+	endfunction
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite control read interface
+	//
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_ADDR_WIDTH-AXILLSB))
+	axilarskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_ARVALID), .o_ready(S_AXIL_ARREADY),
+		.i_data(S_AXIL_ARADDR[C_AXIL_ADDR_WIDTH-1:AXILLSB]),
+		.o_valid(arskd_valid), .i_ready(axil_read_ready),
+		.o_data(arskd_addr));
+
+	always @(*)
+	begin
+		axil_read_ready = !S_AXIL_RVALID || S_AXIL_RREADY;
+		if (!arskd_valid)
+			axil_read_ready = 1'b0;
+	end
+
+	initial	S_AXIL_RVALID = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		S_AXIL_RVALID <= 1'b0;
+	else if (!S_AXIL_RVALID || S_AXIL_RREADY)
+		S_AXIL_RVALID <= axil_read_ready;
+
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		S_AXIL_RDATA <= 0;
+	else if (!S_AXIL_RVALID || S_AXIL_RREADY)
+	begin
+		S_AXIL_RDATA <= 0;
+		case(arskd_addr)
+		CTRL_ADDR: begin
+			S_AXIL_RDATA[CTRL_ERR_BIT]   <= r_err;
+			S_AXIL_RDATA[CTRL_ABORT_BIT] <= r_abort;
+			S_AXIL_RDATA[CTRL_INTEN_BIT] <= r_int_enable;
+			S_AXIL_RDATA[CTRL_INT_BIT]   <= r_int;
+			S_AXIL_RDATA[CTRL_BUSY_BIT]  <= r_busy;
+			end
+		SRCLO_ADDR:
+			S_AXIL_RDATA <= wide_src[C_AXIL_DATA_WIDTH-1:0];
+		SRCHI_ADDR:
+			S_AXIL_RDATA <= wide_src[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+		DSTLO_ADDR:
+			S_AXIL_RDATA <= wide_dst[C_AXIL_DATA_WIDTH-1:0];
+		DSTHI_ADDR:
+			S_AXIL_RDATA <= wide_dst[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+		LENLO_ADDR:
+			S_AXIL_RDATA <= wide_len[C_AXIL_DATA_WIDTH-1:0];
+		LENHI_ADDR:
+			S_AXIL_RDATA <= wide_len[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+		default: begin end
+		endcase
+
+		if (!axil_read_ready)
+			S_AXIL_RDATA <= 0;
+	end
+
+	always @(*)
+		S_AXIL_RRESP = AXI_OKAY;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI read processing
+	//
+	// Read data into our FIFO
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+
+	always @(posedge S_AXI_ACLK)
+	if (!r_busy)
+		read_address <= { 1'b0, r_src_addr };
+	else if (phantom_read)
+	begin
+	// Verilator lint_off WIDTH
+		read_address[C_AXI_ADDR_WIDTH:ADDRLSB]
+			<= read_address[C_AXI_ADDR_WIDTH:ADDRLSB] +(M_AXI_ARLEN+1);
+	// Verilator lint_on WIDTH
+		read_address[ADDRLSB-1:0] <= 0;
+	end
+
+	// Verilator lint_off WIDTH
+	always @(posedge S_AXI_ACLK)
+	if (!r_busy)
+		reads_remaining_w <= readlen_b[LGLEN:ADDRLSB];
+	else if (phantom_read)
+		reads_remaining_w <= reads_remaining_w - (M_AXI_ARLEN+1);
+
+	always @(posedge S_AXI_ACLK)
+	if (!r_busy)
+		reads_remaining_nonzero <= 1;
+	else if (phantom_read)
+		reads_remaining_nonzero
+				<= (reads_remaining_w != (M_AXI_ARLEN+1));
+	// Verilator lint_on WIDTH
+
+	always @(posedge S_AXI_ACLK)
+	if (!r_busy)
+		read_beats_remaining_w <= readlen_b[LGLEN:ADDRLSB];
+	else if (M_AXI_RVALID && M_AXI_RREADY)
+		read_beats_remaining_w <= read_beats_remaining_w - 1;
+
+	initial	read_bursts_outstanding = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset || !r_busy)
+	begin
+		read_bursts_outstanding <= 0;
+	end else case({phantom_read,M_AXI_RVALID&& M_AXI_RREADY && M_AXI_RLAST})
+	2'b01: read_bursts_outstanding <= read_bursts_outstanding - 1;
+	2'b10: read_bursts_outstanding <= read_bursts_outstanding + 1;
+	default: begin end
+	endcase
+
+	initial	no_read_bursts_outstanding = 1;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset || !r_busy)
+	begin
+		no_read_bursts_outstanding <= 1;
+	end else case({phantom_read,M_AXI_RVALID&& M_AXI_RREADY && M_AXI_RLAST})
+	2'b01: no_read_bursts_outstanding <= (read_bursts_outstanding == 1);
+	2'b10: no_read_bursts_outstanding <= 0;
+	default: begin end
+	endcase
+
+	always @(posedge S_AXI_ACLK)
+	if (!r_busy)
+		M_AXI_ARADDR <= r_src_addr;
+	else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+		M_AXI_ARADDR <= read_address[C_AXI_ADDR_WIDTH-1:0];
+
+	always @(*)
+	if (OPT_UNALIGNED)
+		readlen_b = r_len + { {(C_AXI_ADDR_WIDTH-ADDRLSB){1'b0}},
+					r_src_addr[ADDRLSB-1:0] }
+			+ { {(C_AXI_ADDR_WIDTH-ADDRLSB){1'b0}},
+				{(ADDRLSB){1'b1}} };
+	else begin
+		readlen_b = { 1'b0, r_len };
+		readlen_b[ADDRLSB-1:0] = 0;
+	end
+
+	always @(*)
+	begin
+		read_distance_to_boundary_b = 0;
+		read_distance_to_boundary_b[ADDRLSB +: LGMAXBURST]
+					= -r_src_addr[ADDRLSB +: LGMAXBURST];
+	end
+
+	always @(*)
+	begin
+		initial_readlen_w = 0;
+		initial_readlen_w[LGMAXBURST] = 1;
+
+		if (r_src_addr[ADDRLSB +: LGMAXBURST] != 0)
+			initial_readlen_w[LGMAXBURST:0] = { 1'b0,
+				read_distance_to_boundary_b[ADDRLSB +: LGMAXBURST] };
+		if (initial_readlen_w > readlen_b[LGLEN:ADDRLSB])
+			initial_readlen_w[LGMAXBURST:0] = { 1'b0,
+				readlen_b[ADDRLSB +: LGMAXBURST] };
+		initial_readlen_w[LGLENW-1:LGMAXBURST+1] = 0;
+	end
+
+	// Verilator lint_off WIDTH
+	always @(posedge S_AXI_ACLK)
+	if (!r_busy)
+	begin
+		readlen_w <= initial_readlen_w;
+	end else if (phantom_read)
+	begin
+		readlen_w <= reads_remaining_w - (M_AXI_ARLEN+1);
+		if (reads_remaining_w - (M_AXI_ARLEN+1) > (1<<LGMAXBURST))
+			readlen_w <= (1<<LGMAXBURST);
+	end
+	// Verilator lint_on WIDTH
+
+	always @(*)
+	begin
+		w_start_read = r_busy && reads_remaining_nonzero;
+		if (phantom_read)
+			w_start_read = 0;
+		if (!OPT_WRAPMEM && read_address[C_AXI_ADDR_WIDTH])
+			w_start_read = 0;
+		if (fifo_space_available < (1<<LGMAXBURST))
+			w_start_read = 0;
+		if (M_AXI_ARVALID && !M_AXI_ARREADY)
+			w_start_read = 0;
+		if (r_err || r_abort)
+			w_start_read = 0;
+	end
+
+	initial	M_AXI_ARVALID = 1'b0;
+	initial	phantom_read  = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset || !r_busy)
+	begin
+		M_AXI_ARVALID <= 0;
+		phantom_read  <= 0;
+	end else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+	begin
+		M_AXI_ARVALID <= w_start_read;
+		phantom_read  <= w_start_read;
+	end else
+		phantom_read  <= 0;
+
+	always @(posedge S_AXI_ACLK)
+	if (i_reset || !r_busy)
+		M_AXI_ARLEN <= 0;
+	else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+`ifdef	AXI3
+		M_AXI_ARLEN <= readlen_w[3:0] - 4'h1;
+`else
+		M_AXI_ARLEN <= readlen_w[7:0] - 8'h1;
+`endif
+
+	always @(*)
+	begin
+		M_AXI_ARID    = AXI_READ_ID;
+		M_AXI_ARBURST = AXI_INCR;
+		M_AXI_ARSIZE  = ADDRLSB[2:0];
+		M_AXI_ARLOCK  = 1'b0;
+		M_AXI_ARCACHE = 4'b0011;
+		M_AXI_ARPROT  = r_prot;
+		M_AXI_ARQOS   = r_qos;
+		//
+		M_AXI_RREADY = !no_read_bursts_outstanding;
+	end
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The intermediate FIFO
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(*)
+		fifo_reset = i_reset || !r_busy || r_done;
+
+	generate if (OPT_UNALIGNED)
+	begin : REALIGNMENT_FIFO
+		reg	[ADDRLSB-1:0]		inbyte_shift, outbyte_shift,
+						remaining_read_realignment;
+		reg	[ADDRLSB+3-1:0]		inshift_down, outshift_down,
+						inshift_up, outshift_up;
+		reg	[C_AXI_DATA_WIDTH-1:0]	r_partial_inword,
+						r_outword, r_partial_outword,
+						r_realigned_incoming;
+		wire	[C_AXI_DATA_WIDTH-1:0]	fifo_data;
+		reg	[ADDRLSB-1:0]		r_last_write_addr;
+		reg				r_oneword, r_firstword;
+
+
+		///////////////////
+
+
+		always @(posedge S_AXI_ACLK)
+		if (!r_busy)
+		begin
+			inbyte_shift <= r_src_addr[ADDRLSB-1:0];
+			inshift_up   <= 0;
+			inshift_up[3 +: ADDRLSB] <= -r_src_addr[ADDRLSB-1:0];
+		end
+
+		always @(*)
+			inshift_down = {  inbyte_shift, 3'b000 };
+
+		always @(*)
+			remaining_read_realignment = -r_src_addr[ADDRLSB-1:0];
+
+		// extra_realignment_read will be true if we need to flush
+		// the read processor after the last word has been read in an
+		// extra write to the FIFO that isn't associated with any reads.
+		// In other words, if the number of writes to the FIFO is
+		// greater than the number of read beats
+		//			- (src_addr unaligned?1:0)
+		always @(posedge S_AXI_ACLK)
+		if (!r_busy)
+		begin
+			extra_realignment_read <= (remaining_read_realignment
+				>= r_len[ADDRLSB-1:0]) ? 1:0;
+			if (r_len[ADDRLSB-1:0] == 0)
+				extra_realignment_read <= 1'b0;
+			if (r_src_addr[ADDRLSB-1:0] == 0)
+				extra_realignment_read <= 1'b0;
+		end else if ((!r_write_fifo || !fifo_full) && clear_read_pipeline)
+			extra_realignment_read <= 1'b0;
+
+		always @(posedge S_AXI_ACLK)
+		if (!r_busy || !extra_realignment_read || clear_read_pipeline)
+			clear_read_pipeline <= 0;
+		else if (!r_write_fifo || !fifo_full)
+			clear_read_pipeline <= (read_beats_remaining_w
+						== (M_AXI_RVALID ? 1:0));
+
+`ifdef	FORMAL
+		always @(*)
+		if (r_busy)
+		begin
+			if (!extra_realignment_read)
+				assert(!clear_read_pipeline);
+			else if (read_beats_remaining_w > 0)
+				assert(!clear_read_pipeline);
+			else if (!no_read_bursts_outstanding)
+				assert(!clear_read_pipeline);
+		end
+`endif
+
+		always @(posedge S_AXI_ACLK)
+		if (fifo_reset)
+			r_partial_in_valid <= (r_src_addr[ADDRLSB-1:0] == 0);
+		else if (M_AXI_RVALID)
+			r_partial_in_valid <= 1;
+		else if ((!r_write_fifo || !fifo_full) && clear_read_pipeline)
+			// If we have to flush the final partial valid signal,
+			// the do it when writing to the FIFO with clear_read
+			// pipelin set.  Actually, this is one clock before
+			// that ...
+			r_partial_in_valid <= 0;
+
+		always @(posedge S_AXI_ACLK)
+		if (fifo_reset || (inbyte_shift == 0))
+			r_partial_inword <= 0;
+		else if (M_AXI_RVALID)
+			r_partial_inword <= M_AXI_RDATA >> inshift_down;
+
+		initial	r_write_fifo = 0;
+		always @(posedge S_AXI_ACLK)
+		if (fifo_reset)
+			r_write_fifo <= 0;
+		else if (M_AXI_RVALID || clear_read_pipeline)
+			r_write_fifo <= r_partial_in_valid;
+		else if (!fifo_full)
+			r_write_fifo <= 0;
+
+		always @(posedge S_AXI_ACLK)
+		if (fifo_reset)
+			r_realigned_incoming <= 0;
+		else if (M_AXI_RVALID)
+			r_realigned_incoming <= r_partial_inword
+					| (M_AXI_RDATA << inshift_up);
+		else if (!r_write_fifo || !fifo_full)
+			r_realigned_incoming <= r_partial_inword;
+
+		sfifo #(.BW(C_AXI_DATA_WIDTH), .LGFLEN(LGFIFO),
+						.OPT_ASYNC_READ(1'b1))
+		middata(i_clk, fifo_reset,
+				r_write_fifo, r_realigned_incoming,
+					fifo_full, fifo_fill,
+				r_read_fifo, fifo_data, fifo_empty);
+
+		always @(posedge S_AXI_ACLK)
+		if (!r_busy)
+		begin
+			outbyte_shift <= r_dst_addr[ADDRLSB-1:0];
+			outshift_down <= 0;
+			outshift_down[3 +: ADDRLSB] <= -r_dst_addr[ADDRLSB-1:0];
+		end
+
+		always @(*)
+			outshift_up   = {  outbyte_shift, 3'b000 };
+
+
+		always @(posedge S_AXI_ACLK)
+		if (fifo_reset)
+			r_partial_outword <= 0;
+		else if (r_read_fifo && outshift_up != 0)
+			r_partial_outword
+				<= (fifo_data >> outshift_down);
+		else if (M_AXI_WVALID && M_AXI_WREADY)
+			r_partial_outword <= 0;
+
+		always @(posedge S_AXI_ACLK)
+		if (fifo_reset)
+			r_partial_outvalid <= 0;
+		else if (r_read_fifo && !fifo_empty)
+			r_partial_outvalid <= 1;
+		else if (fifo_empty && M_AXI_WVALID && M_AXI_WREADY)
+			r_partial_outvalid <= extra_realignment_write;
+
+		always @(posedge S_AXI_ACLK)
+		if (fifo_reset)
+			r_outword <= 0;
+		else if (!r_partial_outvalid || (M_AXI_WVALID && M_AXI_WREADY))
+		begin
+			if (!fifo_empty)
+				r_outword <= r_partial_outword |
+					(fifo_data << outshift_up);
+			else
+				r_outword <= r_partial_outword;
+		end
+
+		always @(*)
+			M_AXI_WDATA = r_outword;
+
+		always @(*)
+		begin
+			r_read_fifo = 0;
+			if (!r_partial_outvalid)
+				r_read_fifo = 1;
+			if (M_AXI_WVALID && M_AXI_WREADY)
+				r_read_fifo = 1;
+
+			if (fifo_empty)
+				r_read_fifo = 0;
+		end
+
+		////////////////////////////////////////////////////////////////
+		//
+		// Write strobe logic for the unaligned case
+		//
+		////////////////////////////////////////////////////////////////
+		//
+		//
+
+		always @(posedge S_AXI_ACLK)
+		if (!r_busy)
+		begin
+			if (r_len[(LGLEN-1):(ADDRLSB+1)] != 0)
+				r_oneword <= 0;
+			else
+				r_oneword <= ({ 2'b0, r_dst_addr[ADDRLSB-1:0]}
+					+ r_len[ADDRLSB+1:0] <=
+					{ 2'b01, {(ADDRLSB){1'b0}} });
+		end
+
+		initial	r_first_wstrb = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!r_busy)
+		begin
+			if (r_len[LGLEN-1:ADDRLSB] != 0)
+				r_first_wstrb <= -1 << r_dst_addr[ADDRLSB-1:0];
+			else
+				r_first_wstrb <= ((1<<r_len[ADDRLSB-1:0]) -1) << r_dst_addr[ADDRLSB-1:0];
+		end
+
+		always @(*)
+			r_last_write_addr = r_dst_addr[ADDRLSB-1:0] + r_len[ADDRLSB-1:0];
+
+		always @(posedge S_AXI_ACLK)
+		if (!r_busy)
+		begin
+			if (r_last_write_addr[ADDRLSB-1:0] == 0)
+				r_last_wstrb <= -1;
+			else
+				r_last_wstrb <= (1<<r_last_write_addr)-1;
+		end
+
+		always @(posedge S_AXI_ACLK)
+		if (!r_busy)
+			r_firstword <= 1;
+		else if (M_AXI_WVALID && M_AXI_WREADY)
+			r_firstword <= 0;
+
+		always @(posedge S_AXI_ACLK)
+		if (!M_AXI_WVALID || M_AXI_WREADY)
+		begin
+			if (r_oneword)
+				M_AXI_WSTRB <= r_first_wstrb & r_last_wstrb;
+			else if (M_AXI_WVALID && M_AXI_WREADY)
+			begin
+				if (write_beats_remaining > 2)
+					M_AXI_WSTRB <= -1;
+				else
+					M_AXI_WSTRB <= r_last_wstrb;
+			end else if (r_firstword)
+				M_AXI_WSTRB <= r_first_wstrb;
+
+			if (r_err || r_abort)
+				M_AXI_WSTRB <= 0;
+		end
+
+	end else begin : ALIGNED_FIFO
+
+		always @(*)
+		begin
+			r_first_wstrb = -1;
+			r_last_wstrb = -1;
+			r_partial_in_valid = 1;
+			r_partial_outvalid = !fifo_empty;
+
+			r_write_fifo = M_AXI_RVALID;
+			r_read_fifo = M_AXI_WVALID && M_AXI_WREADY;
+
+			clear_read_pipeline = 1'b0;
+		end
+
+		sfifo #(.BW(C_AXI_DATA_WIDTH), .LGFLEN(LGFIFO), .OPT_ASYNC_READ(1'b1))
+		middata(i_clk, fifo_reset,
+				r_write_fifo, M_AXI_RDATA, fifo_full, fifo_fill,
+				r_read_fifo,  M_AXI_WDATA, fifo_empty);
+
+
+		initial	M_AXI_WSTRB = -1;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN || !r_busy)
+			M_AXI_WSTRB <= -1;
+		else if (!M_AXI_WVALID || M_AXI_WREADY)
+			M_AXI_WSTRB <= (r_err || r_abort) ? 0 : -1;
+
+		always @(*)
+			extra_realignment_read <= 0;
+
+	end endgenerate
+
+	always @(posedge S_AXI_ACLK)
+	if (fifo_reset)
+		fifo_space_available <= (1<<LGFIFO)
+		// space for r_partial_outvalid
+		+ (OPT_UNALIGNED ? 1:0)
+		// space for r_partial_in_valid
+		+ (OPT_UNALIGNED && (r_src_addr[ADDRLSB-1:0] != 0) ? 1:0);
+	else case({ phantom_read, M_AXI_WVALID && M_AXI_WREADY })
+	// Verilator lint_off WIDTH
+	2'b10: fifo_space_available <= fifo_space_available - (M_AXI_ARLEN+1);
+	2'b01: fifo_space_available <= fifo_space_available + 1;
+	2'b11: fifo_space_available <= fifo_space_available - M_AXI_ARLEN;
+	// Verilator lint_on  WIDTH
+	default: begin end
+	endcase
+
+	always @(*)
+	if (OPT_UNALIGNED)
+	begin
+		// Verilator lint_off WIDTH
+		// write_remaining
+		write_realignment[ADDRLSB+1:0]
+			= r_len[ADDRLSB-1:0]+r_dst_addr[ADDRLSB-1:0]
+				+ (1<<ADDRLSB)-1;
+
+		// Raw length
+		write_realignment[2*ADDRLSB+2:ADDRLSB+2]
+			= r_len[ADDRLSB-1:0] + (1<<ADDRLSB)-1;
+		// Verilator lint_on  WIDTH
+	end else
+		write_realignment = 0;
+
+	always @(posedge S_AXI_ACLK)
+	if (!OPT_UNALIGNED)
+		extra_realignment_write <= 1'b0;
+	else if (!r_busy)
+	begin
+		if ({ 1'b0, write_realignment[2*ADDRLSB+2] }
+			!= write_realignment[ADDRLSB+1:ADDRLSB])
+			extra_realignment_write <= 1'b1;
+		else
+			extra_realignment_write <= 1'b0;
+	end else if (M_AXI_WVALID && M_AXI_WREADY && fifo_empty)
+		extra_realignment_write <= 1'b0;
+
+	always @(posedge S_AXI_ACLK)
+	if (!r_busy)
+		last_read_beat <= 1'b0;
+	else
+		last_read_beat <= M_AXI_RVALID && M_AXI_RREADY
+				&& (read_beats_remaining_w == 1);
+
+	always @(*)
+	begin
+		next_fifo_data_available = fifo_data_available;
+		// Verilator lint_off WIDTH
+		if (phantom_write)
+			next_fifo_data_available = next_fifo_data_available
+				- (M_AXI_AWLEN + (r_write_fifo && !fifo_full ? 0:1));
+		else if (r_write_fifo && !fifo_full)
+			next_fifo_data_available = next_fifo_data_available + 1;
+
+		if (extra_realignment_write && last_read_beat)
+			next_fifo_data_available = next_fifo_data_available + 1;
+		// Verilator lint_on  WIDTH
+	end
+
+	initial	fifo_data_available = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!r_busy || r_done)
+		fifo_data_available <= 0;
+	else
+		fifo_data_available <= next_fifo_data_available;
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI write processing
+	//
+	// Write data from the FIFO to the AXI bus
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(posedge S_AXI_ACLK)
+	if (!r_busy)
+		write_address <= { 1'b0, r_dst_addr };
+	else if (phantom_write)
+	begin
+		// Verilator lint_off WIDTH
+		write_address <= write_address + ((M_AXI_AWLEN+1)<< M_AXI_AWSIZE);
+		// Verilator lint_on WIDTH
+		write_address[ADDRLSB-1:0] <= 0;
+	end
+
+	// Verilator lint_off WIDTH
+
+	always @(*)
+		w_writes_remaining_w = writes_remaining_w - (M_AXI_AWLEN+1);
+
+	always @(posedge S_AXI_ACLK)
+	if (i_reset || !r_busy)
+	begin
+		writes_remaining_w <= writelen_b[LGLEN:ADDRLSB];
+		multiple_write_bursts_remaining <= |writelen_b[LGLEN:(ADDRLSB+LGMAXBURST)];
+	end else if (phantom_write)
+	begin
+		writes_remaining_w <= w_writes_remaining_w;
+		multiple_write_bursts_remaining
+			<= |w_writes_remaining_w[LGLENW:LGMAXBURST];
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (i_reset || !r_busy)
+	begin
+		write_beats_remaining <= writelen_b[LGLEN:ADDRLSB];
+	end else if (M_AXI_WVALID && M_AXI_WREADY)
+		write_beats_remaining <= write_beats_remaining - 1;
+
+	initial	write_requests_remaining = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		write_requests_remaining <= 1'b0;
+	else if (!r_busy)
+		write_requests_remaining <= w_start;
+	else if (phantom_write)
+		write_requests_remaining <= (writes_remaining_w != (M_AXI_AWLEN+1));
+	// Verilator lint_on WIDTH
+
+	initial	write_bursts_outstanding = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset || !r_busy)
+	begin
+		write_bursts_outstanding <= 0;
+	end else case({phantom_write, M_AXI_BVALID && M_AXI_BREADY })
+	2'b01: write_bursts_outstanding <= write_bursts_outstanding - 1;
+	2'b10: write_bursts_outstanding <= write_bursts_outstanding + 1;
+	default: begin end
+	endcase
+
+	// Verilator lint_off  WIDTH
+	always @(posedge S_AXI_ACLK)
+	if (!r_busy)
+		last_write_ack <= 0;
+	else if (writes_remaining_w > ((phantom_write) ? (M_AXI_AWLEN+1) : 0))
+		last_write_ack <= 0;
+	else
+		last_write_ack <= (write_bursts_outstanding
+			== (phantom_write ? 0:1) + (M_AXI_BVALID ? 1:0));
+	// Verilator lint_on  WIDTH
+
+	always @(posedge S_AXI_ACLK)
+	if (!r_busy || M_AXI_ARVALID || M_AXI_AWVALID)
+		r_done <= 0;
+	else if (read_bursts_outstanding > 0)
+		r_done <= 0;
+	else if (write_bursts_outstanding > (M_AXI_BVALID ? 1:0))
+		r_done <= 0;
+	else if (r_abort || r_err)
+		r_done <= 1;
+	else if (writes_remaining_w > 0)
+		r_done <= 0;
+	else
+		r_done <= 1;
+
+	always @(*)
+	if (OPT_UNALIGNED)
+		writelen_b = { 1'b0, r_len } + { {(LGLEN+1-ADDRLSB){1'b0}},
+					r_dst_addr[ADDRLSB-1:0] }
+			+ { {(LGLEN+1-ADDRLSB){1'b0}}, {(ADDRLSB){1'b1}} };
+			// was + (1<<ADDRLSB)-1;
+	else begin
+		writelen_b = { 1'b0, r_len };
+		writelen_b[ADDRLSB-1:0] = 0;
+	end
+
+	always @(*)
+	begin
+		initial_write_distance_to_boundary_w
+			= - { 1'b0, write_address[ADDRLSB +: LGMAXBURST] };
+		initial_write_distance_to_boundary_w[LGMAXBURST] = 1'b0;
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (!r_busy)
+	begin
+		first_write_burst <= 1'b1;
+		if (|writelen_b[LGLEN:ADDRLSB+LGMAXBURST])
+			first_write_len_w <= (1<<LGMAXBURST);
+		else
+			first_write_len_w <= { 1'b0,
+				writelen_b[ADDRLSB +: LGMAXBURST] };
+	end else begin
+		if (phantom_write)
+			first_write_burst <= 1'b0;
+
+		if (first_write_burst
+			&& write_address[ADDRLSB +: LGMAXBURST] != 0
+			&& first_write_len_w
+				> initial_write_distance_to_boundary_w)
+			first_write_len_w<=initial_write_distance_to_boundary_w;
+	end
+
+	// Verilator lint_off WIDTH
+	always @(*)
+	if (first_write_burst)
+		write_burst_length = first_write_len_w;
+	else begin
+		write_burst_length = (1<<LGMAXBURST);
+
+		if (!multiple_write_bursts_remaining
+			&& (write_burst_length[ADDRLSB +: LGMAXBURST]
+				> writes_remaining_w[ADDRLSB +: LGMAXBURST]))
+			write_burst_length = writes_remaining_w;
+	end
+	// Verilator lint_on WIDTH
+
+	initial	write_count = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset || !r_busy)
+		write_count <= 0;
+	else if (w_write_start)
+		write_count <= write_burst_length[LGMAXBURST:0];
+	else if (M_AXI_WVALID && M_AXI_WREADY)
+		write_count <= write_count - 1;
+
+	initial	M_AXI_WLAST = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset || !r_busy)
+	begin
+		M_AXI_WLAST <= 0;
+	end else if (!M_AXI_WVALID || M_AXI_WREADY)
+	begin
+		M_AXI_WLAST <= 1;
+		if (write_count > 2)
+			M_AXI_WLAST <= 0;
+		if (w_write_start)
+`ifdef	AXI3
+			M_AXI_WLAST <= (write_burst_length[3:0] == 1);
+`else
+			M_AXI_WLAST <= (write_burst_length[7:0] == 1);
+`endif
+	end
+
+	always @(*)
+		last_write_burst = (write_burst_length == writes_remaining_w);
+
+	always @(*)
+	begin
+		// Verilator lint_off WIDTH
+		if (!last_write_burst && OPT_UNALIGNED)
+			w_write_start = (fifo_data_available > 1)
+				&&(fifo_data_available > write_burst_length);
+		else
+			w_write_start = (fifo_data_available >= write_burst_length);
+		// Verilator lint_on WIDTH
+		if (!write_requests_remaining)
+			w_write_start = 0;
+		if (!OPT_WRAPMEM && write_address[C_AXI_ADDR_WIDTH])
+			w_write_start = 0;
+		if (phantom_write)
+			w_write_start = 0;
+		if (M_AXI_AWVALID && !M_AXI_AWREADY)
+			w_write_start = 0;
+		if (M_AXI_WVALID && (!M_AXI_WLAST || !M_AXI_WREADY))
+			w_write_start = 0;
+		if (i_reset || r_err || r_abort || !r_busy)
+			w_write_start = 0;
+	end
+
+	initial	M_AXI_AWVALID = 0;
+	initial	phantom_write = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+	begin
+		M_AXI_AWVALID <= 0;
+		phantom_write <= 0;
+	end else if (!M_AXI_AWVALID || M_AXI_AWREADY)
+	begin
+		M_AXI_AWVALID <= w_write_start;
+		phantom_write <= w_write_start;
+	end else
+		phantom_write <= 0;
+
+	initial	M_AXI_WVALID = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		M_AXI_WVALID <= 0;
+	else if (!M_AXI_WVALID || M_AXI_WREADY)
+	begin
+		M_AXI_WVALID <= 0;
+		if (M_AXI_WVALID && !M_AXI_WLAST)
+			M_AXI_WVALID <= 1;
+		if (w_write_start)
+			M_AXI_WVALID <= 1;
+	end
+
+	initial	M_AXI_AWLEN = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset || !r_busy)
+		M_AXI_AWLEN <= 0;
+	else if (!M_AXI_AWVALID || M_AXI_AWREADY)
+	begin
+		M_AXI_AWLEN <= 0;
+		if (w_write_start)
+`ifdef	AXI3
+			M_AXI_AWLEN <= write_burst_length[3:0]-1;
+`else
+			M_AXI_AWLEN <= write_burst_length[7:0]-1;
+`endif
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (!r_busy)
+		M_AXI_AWADDR <= r_dst_addr;
+	else if (!M_AXI_AWVALID || M_AXI_AWREADY)
+		M_AXI_AWADDR <= write_address[C_AXI_ADDR_WIDTH-1:0];
+
+
+	always @(*)
+	begin
+		M_AXI_AWID    = AXI_WRITE_ID;
+		M_AXI_AWBURST = AXI_INCR;
+		M_AXI_AWSIZE  = ADDRLSB[2:0];
+		M_AXI_AWLOCK  = 1'b0;
+		M_AXI_AWCACHE = 4'b0011;
+		M_AXI_AWPROT  = r_prot;
+		M_AXI_AWQOS   = r_qos;
+		//
+`ifdef	AXI3
+		M_AXI_WID     = AXI_WRITE_ID;
+`endif
+		M_AXI_BREADY = !r_done;
+	end
+
+	// Keep Verilator happy
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, S_AXIL_AWPROT, S_AXIL_ARPROT, M_AXI_BID,
+			M_AXI_RID, M_AXI_BRESP[0], M_AXI_RRESP[0],
+			S_AXIL_AWADDR[AXILLSB-1:0], S_AXIL_ARADDR[AXILLSB-1:0],
+			fifo_full, fifo_fill, fifo_empty,
+`ifdef	AXI3
+			readlen_w[LGLENW:4],
+`else
+			readlen_w[LGLENW:8],
+`endif
+			writelen_b[ADDRLSB-1:0], readlen_b[ADDRLSB-1:0],
+			read_distance_to_boundary_b[C_AXI_ADDR_WIDTH-1:ADDRLSB + LGMAXBURST],
+			read_distance_to_boundary_b[ADDRLSB-1:0]
+			};
+
+	generate if (C_AXI_ADDR_WIDTH < 2*C_AXIL_DATA_WIDTH)
+	begin : NEW_UNUSED
+		wire	genunused;
+
+		assign genunused = &{ 1'b0,
+			new_widesrc[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH],
+			new_widedst[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH] };
+	end endgenerate
+	// Verilator lint_on UNUSED
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal property section
+//
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The following formal properties are only a subset of those used
+	// to verify the full core.  Do not be surprised to find syntax errors
+	// here, or registers that are not defined.  These are correct in the
+	// full version.
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	reg	f_past_valid;
+
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+
+	//
+	// ...
+	//
+
+	reg	[C_AXI_ADDR_WIDTH:0]	f_next_wraddr, f_next_rdaddr;
+
+	reg	[C_AXI_ADDR_WIDTH:0]	f_src_addr, f_dst_addr,
+				f_read_address, f_write_address,
+				f_read_check_addr, f_write_beat_addr,
+				f_read_beat_addr;
+	reg	[LGLEN:0]	f_length, f_rdlength, f_wrlength,
+				f_writes_complete, f_reads_complete;
+
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The control interface
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	faxil_slave #(
+		.C_AXI_DATA_WIDTH(C_AXIL_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXIL_ADDR_WIDTH)
+		//
+		// ...
+		//
+		)
+	faxil(
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXIL_AWVALID),
+		.i_axi_awready(S_AXIL_AWREADY),
+		.i_axi_awaddr(S_AXIL_AWADDR),
+		.i_axi_awprot(S_AXIL_AWPROT),
+		//
+		.i_axi_wvalid(S_AXIL_WVALID),
+		.i_axi_wready(S_AXIL_WREADY),
+		.i_axi_wdata( S_AXIL_WDATA),
+		.i_axi_wstrb( S_AXIL_WSTRB),
+		//
+		.i_axi_bvalid(S_AXIL_BVALID),
+		.i_axi_bready(S_AXIL_BREADY),
+		.i_axi_bresp( S_AXIL_BRESP),
+		//
+		.i_axi_arvalid(S_AXIL_ARVALID),
+		.i_axi_arready(S_AXIL_ARREADY),
+		.i_axi_araddr( S_AXIL_ARADDR),
+		.i_axi_arprot( S_AXIL_ARPROT),
+		//
+		.i_axi_rvalid(S_AXIL_RVALID),
+		.i_axi_rready(S_AXIL_RREADY),
+		.i_axi_rdata( S_AXIL_RDATA),
+		.i_axi_rresp( S_AXIL_RRESP)
+		//
+		// ...
+		//
+		);
+
+	//
+	// ...
+	//
+
+	//
+	// Verify the AXI-lite result registers
+	//
+	always @(*)
+	if (!r_busy)
+		assert((r_done && (r_err || r_abort))
+				|| (zero_len == (r_len == 0)));
+	else
+		assert(zero_len == (r_len == 0 && writes_remaining_w == 0));
+
+	always @(*)
+	if (!i_reset && !OPT_UNALIGNED)
+		assert(r_src_addr[ADDRLSB-1:0] == 0);
+
+	always @(*)
+	if (!i_reset && !OPT_UNALIGNED)
+		assert(r_dst_addr[ADDRLSB-1:0] == 0);
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The main AXI data interface
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	faxi_master #(
+		.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.OPT_MAXBURST(MAXBURST)
+		//
+		// ...
+		//
+		)
+	faxi(
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(M_AXI_AWVALID),
+		.i_axi_awready(M_AXI_AWREADY),
+		.i_axi_awid(   M_AXI_AWID),
+		.i_axi_awaddr( M_AXI_AWADDR),
+		.i_axi_awlen(  M_AXI_AWLEN),
+		.i_axi_awsize( M_AXI_AWSIZE),
+		.i_axi_awburst(M_AXI_AWBURST),
+		.i_axi_awlock( M_AXI_AWLOCK),
+		.i_axi_awcache(M_AXI_AWCACHE),
+		.i_axi_awprot( M_AXI_AWPROT),
+		.i_axi_awqos(  M_AXI_AWQOS),
+		//
+		.i_axi_wvalid(M_AXI_WVALID),
+		.i_axi_wready(M_AXI_WREADY),
+		.i_axi_wdata( M_AXI_WDATA),
+		.i_axi_wstrb( M_AXI_WSTRB),
+		.i_axi_wlast( M_AXI_WLAST),
+		//
+		.i_axi_bvalid(M_AXI_BVALID),
+		.i_axi_bready(M_AXI_BREADY),
+		.i_axi_bid(   M_AXI_BID),
+		.i_axi_bresp( M_AXI_BRESP),
+		//
+		.i_axi_arvalid(M_AXI_ARVALID),
+		.i_axi_arready(M_AXI_ARREADY),
+		.i_axi_arid(   M_AXI_ARID),
+		.i_axi_araddr( M_AXI_ARADDR),
+		.i_axi_arlen(  M_AXI_ARLEN),
+		.i_axi_arsize( M_AXI_ARSIZE),
+		.i_axi_arburst(M_AXI_ARBURST),
+		.i_axi_arlock( M_AXI_ARLOCK),
+		.i_axi_arcache(M_AXI_ARCACHE),
+		.i_axi_arprot( M_AXI_ARPROT),
+		.i_axi_arqos(  M_AXI_ARQOS),
+		//
+		//
+		.i_axi_rvalid(M_AXI_RVALID),
+		.i_axi_rready(M_AXI_RREADY),
+		.i_axi_rid(   M_AXI_RID),
+		.i_axi_rdata( M_AXI_RDATA),
+		.i_axi_rlast( M_AXI_RLAST),
+		.i_axi_rresp( M_AXI_RRESP)
+		//
+		// ...
+		//
+		);
+
+	always @(*)
+	begin
+		//
+		// ...
+		//
+		if (r_done)
+		begin
+			//
+			// ...
+			//
+			assert(!M_AXI_AWVALID);
+			assert(!M_AXI_WVALID);
+			assert(!M_AXI_ARVALID);
+		end
+	end
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Internal assertions (Induction)
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(posedge S_AXI_ACLK)
+	if (w_start)
+	begin
+		f_src_addr <= { 1'b0, r_src_addr };
+		f_dst_addr <= { 1'b0, r_dst_addr };
+		f_length   <= r_len;
+	end else if (r_busy)
+	begin
+		assert(f_length != 0);
+		assert(f_length[LGLEN] == 0);
+
+		assert(f_src_addr[C_AXI_ADDR_WIDTH] == 1'b0);
+		assert(f_dst_addr[C_AXI_ADDR_WIDTH] == 1'b0);
+	end
+
+	always @(*)
+	begin
+		f_rdlength = f_length + f_src_addr[ADDRLSB-1:0]
+				+ (1<<ADDRLSB)-1;
+		f_rdlength[ADDRLSB-1:0] = 0;
+
+		f_wrlength = f_length + f_dst_addr[ADDRLSB-1:0]
+				+ (1<<ADDRLSB)-1;
+		f_wrlength[ADDRLSB-1:0] = 0;
+
+		f_raw_length = f_length + (1<<ADDRLSB)-1;
+		f_raw_length[ADDRLSB-1:0] = 0;
+
+		// One past the last address we'll actually read
+		f_last_src_addr = f_src_addr + f_length + (1<<ADDRLSB)-1;
+		f_last_src_addr[ADDRLSB-1:0] = 0;
+		f_last_src_beat = f_src_addr + f_length -1;
+		f_last_src_beat[ADDRLSB-1:0] = 0;
+
+		f_last_dst_addr = f_dst_addr + f_length + (1<<ADDRLSB)-1;
+		f_last_dst_addr[ADDRLSB-1:0] = 0;
+
+		f_rd_arfirst = ({ 1'b0, M_AXI_ARADDR } == f_src_addr);
+		f_rd_arlast  = (M_AXI_ARADDR[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+			+ (M_AXI_ARLEN+1)
+			== f_last_src_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]);
+		f_rd_ckfirst = (faxi_rd_ckaddr == f_src_addr);
+		f_rd_cklast  = (faxi_rd_ckaddr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+				+ faxi_rd_cklen == f_last_src_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]);
+
+		// f_extra_realignment_read
+		// true if we need to write a partial word to the FIFO/buffer
+		// *after* all of our reads are complete.  This is a final
+		// flush sort of thing.
+		if (OPT_UNALIGNED && f_src_addr[ADDRLSB-1:0] != 0)
+		begin
+			// In general, if we are 1) unaligned, and 2) the
+			// length is greater than a word, and 3) there's a
+			// fraction of a word remaining, then we need to flush
+			// a last word into the FIFO.
+			f_extra_realignment_read
+				= (((1<<ADDRLSB)-f_src_addr[ADDRLSB-1:0])
+					>= f_length[ADDRLSB-1:0]) ? 1:0;
+			if (f_length[ADDRLSB-1:0] == 0)
+				f_extra_realignment_read = 0;
+		end else
+			f_extra_realignment_read = 1'b0;
+
+		//
+		// f_extra_realignment_preread
+		// will be true anytime we need to read a first word before
+		// writing anything to the buffer.
+		if (OPT_UNALIGNED && f_src_addr[ADDRLSB-1:0] != 0)
+			f_extra_realignment_preread = 1'b1;
+		else
+			f_extra_realignment_preread = 1'b0;
+
+		//
+		// f_extra_realignment_write
+		// true if following the last read from the FIFO there's a
+		// partial word that will need to be flushed through the
+		// system.
+		if (OPT_UNALIGNED && f_raw_length[LGLEN:ADDRLSB]
+						!= f_wrlength[LGLEN:ADDRLSB])
+			f_extra_realignment_write = 1'b1;
+		else
+			f_extra_realignment_write = 1'b0;
+
+		f_extra_write_in_fifo = (f_extra_realignment_write)
+			&& (read_beats_remaining_w == 0)&&(!last_read_beat);
+	end
+
+	always @(*)
+	if (r_busy && !OPT_UNALIGNED)
+	begin
+		assert(f_src_addr[ADDRLSB-1:0] == 0);
+		assert(f_dst_addr[ADDRLSB-1:0] == 0);
+		assert(f_length[ADDRLSB-1:0] == 0);
+	end
+
+	always @(*)
+	if (r_busy)
+	begin
+		if (!f_extra_realignment_write)
+			assert(!extra_realignment_write);
+		else if (f_writes_complete >= f_wrlength[LGLEN:ADDRLSB]-1)
+			assert(!extra_realignment_write);
+		else
+			assert(extra_realignment_write);
+
+		if ((f_writes_complete > 0 || M_AXI_WVALID)
+					&& extra_realignment_write)
+			assert(r_partial_outvalid);
+	end
+
+	always @(*)
+	if (r_busy)
+	begin
+		if (extra_realignment_read)
+			assert(f_extra_realignment_read);
+		else if (read_beats_remaining_w > 0)
+		assert(f_extra_realignment_read == extra_realignment_read);
+	end
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (fifo_full)
+		assert(no_read_bursts_outstanding);
+
+	always @(*)
+	if (r_busy)
+		assert(!r_int);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write checks
+	//
+
+	//
+	// ...
+	//
+
+	always @(*)
+	begin
+		f_write_address = 0;
+		f_write_address[C_AXI_ADDR_WIDTH:ADDRLSB]
+		= f_dst_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+			+ (f_wrlength[LGLEN:ADDRLSB] - writes_remaining_w);
+	end
+
+	always @(*)
+	begin
+		f_next_wraddr = { 1'b0, M_AXI_AWADDR }
+					+ ((M_AXI_AWLEN+1)<<M_AXI_AWSIZE);
+		f_next_wraddr[ADDRLSB-1:0] = 0;
+	end
+
+	always @(*)
+	if (M_AXI_AWVALID)
+	begin
+		assert(M_AXI_WVALID);
+		assert(M_AXI_AWLEN < (1<<LGMAXBURST));
+
+		if (M_AXI_AWLEN != (1<<LGMAXBURST)-1)
+		begin
+			assert((M_AXI_AWADDR[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+				== f_dst_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB])
+				||(phantom_write)
+				||(writes_remaining_w == 0));
+		end else begin
+			assert(M_AXI_AWADDR[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+			== f_write_beat_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]);
+		end
+
+		if (M_AXI_AWADDR[ADDRLSB-1:0] != 0)
+			assert({ 1'b0, M_AXI_AWADDR[C_AXI_ADDR_WIDTH-1:0] }
+					== f_dst_addr);
+		else if (M_AXI_AWADDR != f_dst_addr)
+			assert(M_AXI_AWADDR[0 +: LGMAXBURST+ADDRLSB] == 0);
+	end
+
+	always @(*)
+	if (!OPT_UNALIGNED)
+	begin
+		assert(r_len[ADDRLSB-1:0] == 0);
+		assert(r_src_addr[ADDRLSB-1:0] == 0);
+		assert(r_dst_addr[ADDRLSB-1:0] == 0);
+	end
+
+	always @(*)
+	if (r_busy)
+	begin
+		assert(writes_remaining_w  <= f_wrlength[LGLEN:ADDRLSB]);
+		assert(f_writes_complete   <= f_wrlength[LGLEN:ADDRLSB]);
+		assert(fifo_fill           <= f_wrlength[LGLEN:ADDRLSB]);
+
+		assert(write_address[C_AXI_ADDR_WIDTH:ADDRLSB]
+			== f_write_address[C_AXI_ADDR_WIDTH:ADDRLSB]);
+
+		if (M_AXI_AWADDR != f_dst_addr && writes_remaining_w != 0)
+			assert(M_AXI_AWADDR[LGMAXBURST+ADDRLSB-1:0] == 0);
+		else if (!OPT_UNALIGNED)
+			assert(M_AXI_AWADDR[ADDRLSB-1:0] == 0);
+
+		if((writes_remaining_w!= f_wrlength[LGLEN:ADDRLSB])
+			&&(writes_remaining_w != 0))
+			assert(write_address[LGMAXBURST+ADDRLSB-1:0] == 0);
+
+		if ((write_address[C_AXI_ADDR_WIDTH:ADDRLSB]
+				!= f_dst_addr[C_AXI_ADDR_WIDTH:ADDRLSB])
+			&&(writes_remaining_w > 0))
+			assert(write_address[LGMAXBURST+ADDRLSB-1:0] == 0);
+
+		if (writes_remaining_w != f_wrlength[LGLEN:ADDRLSB]
+				&& writes_remaining_w != 0)
+			assert((write_burst_length == (1<<LGMAXBURST))
+				||(write_burst_length == writes_remaining_w));
+
+		assert(write_requests_remaining == (writes_remaining_w != 0));
+	end
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (M_AXI_AWVALID && !phantom_write)
+	begin
+		assert(write_count == (M_AXI_AWLEN+1));
+		//
+		// ...
+		//
+	end
+
+	always @(*)
+	if (r_busy && last_write_ack)
+	begin
+		assert(reads_remaining_w == 0);
+		assert(!M_AXI_ARVALID);
+		assert(writes_remaining_w == 0);
+	end
+
+	always @(*)
+	if (r_busy && !r_abort && !r_err)
+		assert(write_address[C_AXI_ADDR_WIDTH:ADDRLSB]
+				== f_dst_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+			|| (write_address[LGMAXBURST-1:0] == 0)
+			|| (writes_remaining_w == 0));
+
+	always @(*)
+	if (phantom_write)
+		assert(writes_remaining_w >= (M_AXI_AWLEN+1));
+	else if (M_AXI_AWVALID)
+		assert(write_address[C_AXI_ADDR_WIDTH-1:0]
+					== f_next_wraddr[C_AXI_ADDR_WIDTH-1:0]);
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (M_AXI_WVALID)
+	begin
+		if (OPT_UNALIGNED)
+			assert(r_partial_outvalid);
+		else
+			assert(!fifo_empty || r_abort || r_err);
+		//
+		// ...
+		//
+	end
+
+	always @(*)
+	begin
+		f_write_beat_addr = 0;
+		f_write_beat_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+			= f_dst_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+			+ (f_wrlength[LGLEN:ADDRLSB]-write_beats_remaining);
+
+		//
+		// ...
+		//
+	end
+
+	always @(*)
+	if (r_busy)
+	begin
+		//
+		// ...
+		//
+
+		if (write_beats_remaining == 0)
+			assert(!M_AXI_WVALID);
+	end
+
+	always @(*)
+	if (writes_remaining_w < f_wrlength[LGLEN:ADDRLSB])
+	begin
+		if (writes_remaining_w == 0)
+			assert(fifo_data_available == 0);
+		// else ...
+	end
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read checks
+	//
+	always @(*)
+	begin
+		f_reads_complete = f_rdlength[LGLEN:ADDRLSB]
+				- reads_remaining_w - // ...
+		//
+		// ...
+		//
+	end
+
+	always @(*)
+	begin
+		if (reads_remaining_w == f_rdlength[LGLEN:ADDRLSB])
+			f_read_address = f_src_addr;
+		else begin
+			f_read_address = 0;
+			f_read_address[C_AXI_ADDR_WIDTH:ADDRLSB]
+			= f_src_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+				+ (f_rdlength[LGLEN:ADDRLSB] - reads_remaining_w);
+		end
+
+		f_araddr = f_read_address;
+		if (M_AXI_ARVALID && !phantom_read)
+			f_araddr[C_AXI_ADDR_WIDTH:ADDRLSB]
+				= f_araddr[C_AXI_ADDR_WIDTH:ADDRLSB]
+						- (M_AXI_ARLEN+1);
+		if (f_araddr[C_AXI_ADDR_WIDTH:ADDRLSB]
+					== f_src_addr[C_AXI_ADDR_WIDTH:ADDRLSB])
+			f_araddr[ADDRLSB-1:0] = f_src_addr[ADDRLSB-1:0];
+
+		//
+		// Match the read check address to our source address
+		//
+		f_read_check_addr = 0;
+		f_read_check_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+			= f_src_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+			+ f_reads_complete + // ...
+
+
+		//
+		// Match the RVALID address to our source address
+		//
+		f_read_beat_addr = 0;
+		if (f_reads_complete == 0)
+			f_read_beat_addr = f_src_addr;
+		else
+			f_read_beat_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+				= f_src_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+				+ f_reads_complete;
+
+		f_end_of_read_burst = M_AXI_ARADDR;
+		f_end_of_read_burst[ADDRLSB-1:0] = 0;
+		f_end_of_read_burst[C_AXI_ADDR_WIDTH:ADDRLSB]
+			= f_end_of_read_burst[C_AXI_ADDR_WIDTH:ADDRLSB]
+			+ (M_AXI_ARLEN + 1);
+
+		//
+		// ...
+		//
+	end
+
+	always @(*)
+	begin
+		f_next_rdaddr = { 1'b0, M_AXI_ARADDR } + ((M_AXI_ARLEN+1)<<M_AXI_ARSIZE);
+		f_next_rdaddr[ADDRLSB-1:0] = 0;
+	end
+
+	/////////
+	//
+	// Constrain the read address
+	//
+
+	always @(*)
+	if (r_busy)
+	begin
+		if (!f_rd_arfirst)
+		begin
+			assert(reads_remaining_w < f_rdlength[LGLEN:ADDRLSB]);
+
+			// All bursts following the first one must be aligned
+			if (M_AXI_ARVALID || reads_remaining_w > 0)
+				assert(M_AXI_ARADDR[0 +: LGMAXBURST + ADDRLSB] == 0);
+		end else if (phantom_read)
+			assert(reads_remaining_w == f_rdlength[LGLEN:ADDRLSB]);
+		else if (M_AXI_ARVALID)
+			assert(reads_remaining_w == f_rdlength[LGLEN:ADDRLSB]
+				- (M_AXI_ARLEN+1));
+
+		// All but the first burst should be aligned
+		if (!OPT_UNALIGNED || M_AXI_ARADDR != f_src_addr)
+			assert(M_AXI_ARADDR[ADDRLSB-1:0] == 0);
+
+		if (phantom_read)
+			assert(M_AXI_ARADDR == read_address[C_AXI_ADDR_WIDTH-1:0]);
+		else if (M_AXI_ARVALID)
+			assert(read_address[C_AXI_ADDR_WIDTH-1:0] == f_next_rdaddr[C_AXI_ADDR_WIDTH-1:0]);
+	end // else ...
+
+	//
+	// ...
+	//
+
+	// Constrain read_address--our pointer to the next bursts address
+	always @(*)
+	if (r_busy)
+	begin
+		assert((read_address == f_src_addr)
+			|| (read_address[LGMAXBURST+ADDRLSB-1:0] == 0)
+			|| (reads_remaining_w == 0));
+
+
+		assert(read_address == f_read_address);
+		if (!OPT_UNALIGNED)
+			assert(read_address[ADDRLSB-1:0] == 0);
+
+		if ((reads_remaining_w != f_rdlength[LGLEN:ADDRLSB])
+			&&(reads_remaining_w > 0))
+			assert(read_address[LGMAXBURST+ADDRLSB-1:0] == 0);
+
+		if ((read_address[C_AXI_ADDR_WIDTH:ADDRLSB]
+				!= f_src_addr[C_AXI_ADDR_WIDTH:ADDRLSB])
+			&&(reads_remaining_w > 0))
+			assert(read_address[LGMAXBURST+ADDRLSB-1:0] == 0);
+	end
+
+
+	/////////
+	//
+	// Constrain the read length
+	//
+	always @(*)
+	if (M_AXI_ARVALID)
+	begin
+		assert(M_AXI_ARLEN < (1<<LGMAXBURST));
+		if (M_AXI_ARLEN != (1<<LGMAXBURST)-1)
+		begin
+			assert((M_AXI_ARADDR == f_src_addr)
+				||(phantom_read)
+				||(reads_remaining_w == 0));
+		end
+
+		assert(f_end_of_read_burst_last[C_AXI_ADDR_WIDTH-1:LGMAXBURST+ADDRLSB]
+			== M_AXI_ARADDR[C_AXI_ADDR_WIDTH-1:LGMAXBURST+ADDRLSB]);
+	end
+
+	always @(*)
+	if (M_AXI_ARVALID && reads_remaining_w > (M_AXI_ARLEN+1))
+		assert(f_end_of_read_burst[ADDRLSB+LGMAXBURST-1:0]==0);
+
+
+	/////////
+	//
+	// Constrain RLAST
+	//
+
+	always @(*)
+	if (M_AXI_RVALID)
+	begin
+		if (M_AXI_RLAST)
+		begin
+			if (f_read_beat_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+				!= f_last_src_beat[C_AXI_ADDR_WIDTH:ADDRLSB])
+				assert(&f_read_beat_addr[ADDRLSB+LGMAXBURST-1:ADDRLSB]);
+		end else
+			assert(f_read_beat_addr[ADDRLSB+LGMAXBURST-1:ADDRLSB]
+			!= {(LGMAXBURST){1'b1}});
+	end
+
+	always @(*)
+	if (f_read_beat_addr == f_last_src_beat)
+		assert(!M_AXI_RVALID || M_AXI_RLAST);
+	else
+		assert(!M_AXI_RVALID
+			|| M_AXI_RLAST == (&f_read_beat_addr[LGMAXBURST+ADDRLSB-1:ADDRLSB]));
+
+
+	/////////
+	//
+	//
+	//
+
+
+	always @(*)
+		assert(no_read_bursts_outstanding == (read_bursts_outstanding == 0));
+
+	always @(*)
+	if (r_busy && !r_err)
+		assert(f_read_beat_addr[C_AXI_ADDR_WIDTH-1:0] == r_src_addr);
+
+	always @(*)
+	if (r_busy)
+	begin
+		// Some quick checks to make sure the subsequent checks
+		// don't overflow anything
+		assert(reads_remaining_w   <= f_rdlength[LGLEN:ADDRLSB]);
+		assert(f_reads_complete    <= f_rdlength[LGLEN:ADDRLSB]);
+		// ...
+		assert(fifo_fill           <= f_raw_length[LGLEN:ADDRLSB]);
+		assert(fifo_space_available<= (1<<LGFIFO));
+		assert(fifo_space_available<= (1<<LGFIFO) - fifo_fill);
+		// ...
+
+
+		if (reads_remaining_w != f_rdlength[LGLEN:ADDRLSB]
+				&& reads_remaining_w != 0)
+			assert((readlen_w == (1<<LGMAXBURST))
+				||(readlen_w == reads_remaining_w));
+
+		//
+		// Read-length checks
+		assert(readlen_w <= (1<<LGMAXBURST));
+		if (reads_remaining_w > 0)
+			assert(readlen_w != 0);
+		if (readlen_w != (1<<LGMAXBURST))
+			assert(reads_remaining_w == readlen_w
+				||(read_address == f_src_addr));
+	end
+
+	//
+	// ...
+	//
+
+	////////////////////////////////////////
+	//
+	// Errors or aborts -- do we properly end gracefully
+	//
+	// Make certain we don't deadlock here, but also that we wait
+	// for the last burst return before we clear
+	//
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && r_busy && $past(r_busy))
+	begin
+		// Not allowed to set r_done while anything remains outstanding
+		if (!no_read_bursts_outstanding)
+			assert(!r_done);
+		if (write_bursts_outstanding > 0)
+			assert(!r_done);
+
+		//
+		// If no returns are outstanding, and following an error, then
+		// r_done should be set
+		if ($past(r_busy && (r_err || r_abort))
+		    &&($past(!M_AXI_ARVALID && read_bursts_outstanding==0))
+		    &&($past(!M_AXI_AWVALID && write_bursts_outstanding==0)))
+			assert(r_done);
+
+		if ($past(r_err || r_abort))
+		begin
+			//
+			// Just double check that we aren't starting anything
+			// new following either an abort or an error
+			//
+			assert(!$rose(M_AXI_ARVALID));
+			assert(!$rose(M_AXI_AWVALID));
+
+			if ($past(!M_AXI_WVALID || M_AXI_WREADY))
+				assert(M_AXI_WSTRB == 0);
+		end
+	end
+
+	//
+	// ...
+	//
+
+	////////////////////////////////////////
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (r_busy)
+	begin
+		if (readlen_w == 0)
+			assert(reads_remaining_w == 0);
+		else begin
+			assert(reads_remaining_w > 0);
+			if (!w_start_read)
+			begin
+				assert(readlen_w <= reads_remaining_w);
+				assert(readlen_w <= (1<<LGMAXBURST));
+			end
+		end
+	end
+
+	always @(*)
+	if (M_AXI_BVALID)
+		assert(M_AXI_BREADY);
+
+	always @(*)
+	if (M_AXI_RVALID)
+		assert(M_AXI_RREADY);
+
+	generate if (OPT_UNALIGNED)
+	begin : REALIGNMENT_CHECKS
+
+		//
+		// ...
+		//
+
+	end endgenerate
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// FIFO checks
+	//
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (phantom_read)
+		assert(M_AXI_ARVALID);
+
+	always @(*)
+	if (phantom_write)
+		assert(M_AXI_AWVALID);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Combined
+	//
+
+	always @(*)
+	if (r_busy)
+	begin
+		//
+		// ...
+		//
+
+		assert(writes_remaining_w + write_bursts_outstanding
+			<= f_wrlength[LGLEN:ADDRLSB]);
+
+		//
+		// ...
+		//
+		if (write_count > 0)
+			assert(M_AXI_WVALID);
+		//
+		// ...
+		//
+	end
+
+	always @(*)
+	if (r_busy)
+		assert(last_write_ack == ((write_bursts_outstanding <= 1)
+			&&(writes_remaining_w == 0)));
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Initial (only) constraints
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(posedge S_AXI_ACLK)
+	if (!f_past_valid || $past(!S_AXI_ARESETN))
+	begin
+		assert(!S_AXIL_BVALID);
+		assert(!S_AXIL_RVALID);
+
+		assert(!M_AXI_AWVALID);
+		assert(!M_AXI_WVALID);
+		assert(!M_AXI_ARVALID);
+
+		assert(write_bursts_outstanding == 0);
+		assert(write_requests_remaining == 0);
+
+		assert(!phantom_read);
+		assert(!phantom_write);
+		assert(!r_busy);
+		assert(read_bursts_outstanding == 0);
+		assert(no_read_bursts_outstanding);
+
+		assert(r_len == 0);
+		assert(zero_len);
+
+		assert(write_count == 0);
+		assert(!M_AXI_WLAST);
+		assert(M_AXI_AWLEN == 0);
+		assert(!r_write_fifo);
+		assert(r_src_addr == 0);
+		assert(r_dst_addr == 0);
+	end
+
+	always @(*)
+		assert(ADDRLSB + LGMAXBURST <= 12);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Formal contract checking
+	//
+	// Given an arbitrary address within the source address range, and an
+	// arbitrary piece of data at that source address, prove that said
+	// piece of data will get properly written to the destination address
+	// range
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// We'll pick the byte read from const_addr_src, and then written to
+	// const_addr_dst.
+	//
+	generate if (OPT_UNALIGNED)
+	begin : F_UNALIGNED_SAMPLE_CHECK
+		(* anyconst *) reg	[C_AXI_ADDR_WIDTH-1:0]	f_const_posn;
+		reg	[C_AXI_ADDR_WIDTH:0]	f_const_addr_src,
+						f_const_addr_dst;
+		reg	[8-1:0]			f_const_byte;
+		reg	[C_AXI_ADDR_WIDTH:0]	f_write_fifo_addr,
+						f_read_fifo_addr,
+						f_partial_out_addr;
+		reg	[C_AXI_DATA_WIDTH-1:0]	f_shifted_read, f_shifted_write;
+		reg	[C_AXI_DATA_WIDTH/8-1:0] f_shifted_wstrb;
+		reg	[C_AXI_DATA_WIDTH-1:0]	f_shifted_to_fifo,
+						f_shifted_partial_to_fifo,
+						f_shifted_partial_from_fifo;
+		reg	[C_AXI_DATA_WIDTH-1:0]	f_shifted_from_fifo,
+						f_shifted_from_partial_out;
+		reg	[ADDRLSB-1:0]		subshift;
+
+
+		always @(*)
+		begin
+			assume(f_const_posn < f_length);
+
+			f_const_addr_src = f_src_addr + f_const_posn;
+			f_const_addr_dst = f_dst_addr + f_const_posn;
+
+			f_shifted_read =(M_AXI_RDATA >> (8*f_const_addr_src[ADDRLSB-1:0]));
+			f_shifted_write=(M_AXI_WDATA >> (8*f_const_addr_dst[ADDRLSB-1:0]));
+			f_shifted_wstrb=(M_AXI_WSTRB >> (f_const_addr_dst[ADDRLSB-1:0]));
+		end
+
+		////////////////////////////////////////////////////////////////
+		//
+		// Step 1: Assume a known input
+		//	Actually, we'll copy it when it comes in
+		//
+		always @(posedge S_AXI_ACLK)
+		if (M_AXI_RVALID
+			&& f_read_beat_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+				== f_const_addr_src[C_AXI_ADDR_WIDTH:ADDRLSB])
+		begin
+			// Record our byte to be read
+			f_const_byte <= f_shifted_read[7:0];
+		end
+
+		////////////////////////////////////////////////////////////////
+		//
+		// Step 2: Assert that value gets written on the way out
+		//
+		always @(*)
+		if (M_AXI_WVALID
+			&& f_write_beat_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+				== f_const_addr_dst[C_AXI_ADDR_WIDTH:ADDRLSB])
+		begin
+			// Assert that we have the right byte in the end
+			if (!r_err && !r_abort)
+			begin
+				// Although it only really matters if we are
+				// actually writing it to the bus
+				assert(f_shifted_wstrb[0]);
+				assert(f_shifted_write[7:0] == f_const_byte);
+			end else
+				assert(f_shifted_wstrb[0] || M_AXI_WSTRB==0);
+		end
+
+
+		////////////////////////////////////////////////////////////////
+		//
+		// Assert the write side of the realignment FIFO
+		//
+		always @(*)
+		begin
+			//
+			// ...
+			//
+
+			subshift = f_const_posn[ADDRLSB-1:0];
+		end
+
+		always @(*)
+			f_shifted_to_fifo = REALIGNMENT_FIFO.r_realigned_incoming
+				>> (8*subshift);
+
+		always @(*)
+			f_shifted_partial_to_fifo = REALIGNMENT_FIFO.r_partial_inword
+				>> (8*subshift);
+
+		//
+		// ...
+		//
+
+		always @(*)
+		if (S_AXI_ARESETN && r_write_fifo
+			&& f_write_fifo_addr <= f_const_addr_src
+			&& f_write_fifo_addr + (1<<ADDRLSB) > f_const_addr_src)
+		begin
+			// Assert that our special byte gets written to the FIFO
+			assert(f_const_byte == f_shifted_to_fifo[7:0]);
+		end
+
+		////////////////////////////////////////////////////////////////
+		//
+		// Assert the read side of the realignment FIFO
+		//
+		always @(*)
+		begin
+			f_read_fifo_addr =f_dst_addr;
+			f_read_fifo_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+				= f_dst_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+					+ (r_partial_outvalid ? 1:0)
+					+ f_writes_complete;
+
+			f_partial_out_addr = f_read_fifo_addr;
+			f_partial_out_addr[ADDRLSB-1:0] = 0;
+		end
+
+		always @(*)
+			f_shifted_from_fifo = REALIGNMENT_FIFO.fifo_data
+							>> (8*subshift);
+
+		always @(*)
+			f_shifted_from_partial_out
+				= REALIGNMENT_FIFO.r_partial_outword
+						>> (8*f_const_addr_dst[ADDRLSB-1:0]);
+
+
+		always @(*)
+		if (!fifo_empty && f_read_fifo_addr <= f_const_addr_dst
+			&& f_read_fifo_addr + (1<<ADDRLSB) > f_const_addr_dst)
+		begin
+			// Assume that our special byte gets read from the FIFO
+			// That way we don't have to verify every element of the
+			// FIFO.  We'll instead rely upon the FIFO working from
+			// here.
+			assume(f_const_byte == f_shifted_from_fifo[7:0]);
+		end
+
+		//
+		// ...
+		//
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	[3:0]	f_cvr_rd_bursts, f_cvr_wr_bursts;
+	reg		f_cvr_complete;
+
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		f_cvr_wr_bursts <= 0;
+	else if (w_start)
+		f_cvr_wr_bursts <= 0;
+	else if (M_AXI_AWVALID && M_AXI_AWREADY && !f_cvr_wr_bursts[3])
+		f_cvr_wr_bursts <= f_cvr_wr_bursts + 1;
+
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		f_cvr_rd_bursts <= 0;
+	else if (w_start)
+		f_cvr_rd_bursts <= 0;
+	else if (M_AXI_ARVALID && M_AXI_ARREADY && !f_cvr_rd_bursts[3])
+		f_cvr_rd_bursts <= f_cvr_rd_bursts + 1;
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $past(S_AXI_ARESETN && r_busy))
+		cover(!r_busy && !r_err && !r_abort && f_cvr_wr_bursts[0]
+			&& f_cvr_rd_bursts[0]);
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $past(S_AXI_ARESETN && r_busy))
+		cover(r_done && !r_err && !r_abort && f_cvr_wr_bursts[0]
+			&& f_cvr_rd_bursts[0]);
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $past(S_AXI_ARESETN && r_busy))
+		cover(!r_busy && !r_err && !r_abort && &f_cvr_wr_bursts[1]
+			&& f_cvr_rd_bursts[1]);
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $past(S_AXI_ARESETN && r_busy))
+		cover(!r_busy && !r_err && !r_abort && (&f_cvr_wr_bursts[1:0])
+			&& (&f_cvr_rd_bursts[1:0]));
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $past(S_AXI_ARESETN && r_busy))
+		cover(!r_busy && !r_err && !r_abort && f_cvr_wr_bursts[2]
+			&& f_cvr_rd_bursts[2]);
+
+	always @(*)
+		cover(f_past_valid && S_AXI_ARESETN && r_busy && r_err);
+
+	always @(*)
+		cover(f_past_valid && S_AXI_ARESETN && r_busy
+			&& M_AXI_RVALID && M_AXI_RRESP[1]);
+
+	always @(*)
+		cover(f_past_valid && S_AXI_ARESETN && r_busy
+			&& M_AXI_RVALID && M_AXI_BRESP[1]);
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $past(S_AXI_ARESETN && r_busy && r_err))
+		cover(!r_busy && r_err);
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $past(S_AXI_ARESETN && r_busy && r_abort))
+		cover(!r_busy && r_abort);
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && r_busy && !r_abort && !r_err)
+		cover(reads_remaining_w == 0);
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && r_busy && !r_abort && !r_err)
+		cover(reads_remaining_w == 0 && fifo_empty);
+
+	generate if (OPT_UNALIGNED)
+	begin : COVER_MISALIGNED_COPYING
+
+		reg	[2:0]	cvr_opt_checks;
+		integer		ik;
+
+		always @(*)
+		begin
+			cvr_opt_checks[0] = (f_src_addr[ADDRLSB-1:0] == 0);
+			cvr_opt_checks[1] = (f_dst_addr[ADDRLSB-1:0] == 0);
+			cvr_opt_checks[2] = (f_length[  ADDRLSB-1:0] == 0);
+		end
+
+		always @(posedge S_AXI_ACLK)
+		if (f_past_valid && S_AXI_ARESETN && o_int)
+		begin
+			for(ik=0; ik<8; ik=ik+1)
+			begin
+				cover(cvr_opt_checks == ik[2:0]
+					&& !r_busy && r_err && !r_abort
+					&& f_cvr_wr_bursts[0]
+					&& f_cvr_rd_bursts[0]);
+
+				cover(cvr_opt_checks == ik[2:0]
+					&& !r_busy && !r_err && r_abort
+					&& f_cvr_wr_bursts[0]
+					&& f_cvr_rd_bursts[0]);
+
+				cover(cvr_opt_checks == ik[2:0]
+					&& !r_busy && !r_err && !r_abort
+					&& f_cvr_wr_bursts[0]
+					&& f_cvr_rd_bursts[0]);
+
+				cover(cvr_opt_checks == ik[2:0]
+					&& !r_busy && !r_err && !r_abort
+					&& f_cvr_wr_bursts[2]
+					&& f_cvr_rd_bursts[2]);
+			end
+		end
+
+		always @(posedge S_AXI_ACLK)
+		if (f_past_valid && S_AXI_ARESETN && o_int)
+		begin
+			cover(!r_busy && !r_err && !r_abort
+				&& f_extra_realignment_preread
+				&& f_extra_realignment_read
+				&& f_extra_realignment_write);
+
+			//
+			// Will never happen--since f_extra_realignment_read
+			// can only be true if f_extra_realignment_preread
+			// is also true
+			//
+			// cover(!r_busy && !r_err && !r_abort
+				// && !f_extra_realignment_preread
+				// && f_extra_realignment_read
+				// && f_extra_realignment_write);
+
+			cover(!r_busy && !r_err && !r_abort
+				&& f_extra_realignment_preread
+				&& !f_extra_realignment_read
+				&& f_extra_realignment_write);
+
+			cover(!r_busy && !r_err && !r_abort
+				&& !f_extra_realignment_preread
+				&& !f_extra_realignment_read
+				&& f_extra_realignment_write);
+
+			cover(!r_busy && !r_err && !r_abort
+				&& f_extra_realignment_preread
+				&& f_extra_realignment_read
+				&& !f_extra_realignment_write);
+
+			// !preread && read will never happen
+
+			cover(!r_busy && !r_err && !r_abort
+				&& f_extra_realignment_preread
+				&& !f_extra_realignment_read
+				&& !f_extra_realignment_write);
+
+			cover(!r_busy && !r_err && !r_abort
+				&& !f_extra_realignment_preread
+				&& !f_extra_realignment_read
+				&& !f_extra_realignment_write);
+
+			cover(!r_busy && !r_err && !r_abort
+				&& f_extra_realignment_preread
+				&& f_extra_realignment_read
+				&& f_extra_realignment_write
+				&& f_length[LGLEN-1:ADDRLSB] > 2);
+
+			// !preread && read will never happen
+
+			cover(!r_busy && !r_err && !r_abort
+				&& f_extra_realignment_preread
+				&& !f_extra_realignment_read
+				&& f_extra_realignment_write
+				&& f_length[LGLEN-1:ADDRLSB] > 2);
+
+			cover(!r_busy && !r_err && !r_abort
+				&& !f_extra_realignment_preread
+				&& !f_extra_realignment_read
+				&& f_extra_realignment_write
+				&& f_length[LGLEN-1:ADDRLSB] > 2);
+
+			cover(!r_busy && !r_err && !r_abort
+				&& f_extra_realignment_preread
+				&& f_extra_realignment_read
+				&& !f_extra_realignment_write
+				&& f_length[LGLEN-1:ADDRLSB] > 2);
+
+
+			// !preread && read will never happen
+
+			cover(!r_busy && !r_err && !r_abort
+				&& f_extra_realignment_preread
+				&& !f_extra_realignment_read
+				&& !f_extra_realignment_write
+				&& f_length[LGLEN-1:ADDRLSB] > 2);
+
+			cover(!r_busy && !r_err && !r_abort
+				&& !f_extra_realignment_preread
+				&& !f_extra_realignment_read
+				&& !f_extra_realignment_write
+				&& f_length[LGLEN-1:ADDRLSB] > 2);
+		end
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Careless assumptions (i.e. constraints)
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// None (currently)
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axidouble.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axidouble.v
new file mode 100644
index 0000000..f40fea3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axidouble.v
@@ -0,0 +1,1200 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axidouble.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Create a special AXI slave which can be used to reduce crossbar
+//		logic for multiple simplified AXI slaves.  This is a companion
+//	core to the similar axisingle core, but allowing the slave to
+//	decode the clock between multiple possible addresses.
+//
+//	To use this, the slave must follow specific (simplified AXI) rules:
+//
+//	Write interface
+//	--------------------
+//	1. The controller will guarantee that AWVALID == WVALID
+//		(You can connect AWVALID to WVALID when connecting to your core)
+//	2. The controller will guarantee that AWID == 0 for the slave
+//		All ID logic will be handled internally
+//	3. The controller will guarantee that AWLEN == 0 and WLAST == 1
+//		Instead, the controller will handle all burst addressing
+//		internally
+//	4. This makes AWBURST irrelevant
+//	5. Other wires are simplified as well: AWLOCK=0, AWCACHE=3, AWQOS=0
+//	6. If OPT_EXCLUSIVE_ACCESS is set, the controller will handle lock
+//		logic internally
+//	7. The slave must guarantee that AWREADY == WREADY = 1
+//		(This core doesn't have AWREADY or WREADY inputs)
+//	8. The slave must also guarantee that BVALID == $past(AWVALID)
+//		(This core internally generates BVALID, and so the slave's
+//		BVALID return is actually ignored.)
+//	9. The controller will also guarantee that BREADY = 1
+//		(This core doesn't have a BVALID input)
+//
+//	The controller will maintain AWPROT in case the slave wants to
+//	disallow particular writes, and AWSIZE so the slave can know how many
+//	bytes are being accessed.
+//
+//	Read interface
+//	--------------------
+//	1. The controller will guarantee that RREADY = 1
+//		(This core doesn't have an RREADY output)
+//	2. The controller will guarantee that ARID = 0
+//		All IDs are handled internally
+//	3. The controller will guarantee that ARLEN == 0
+//		All burst logic is handled internally
+//	4. As before, this makes ARBURST irrelevant
+//	5. Other wires are simplified: ARLOCK=0, ARCACHE = 3, ARQOS=0, etc
+//	6. The slave must guarantee that RVALID == $past(ARVALID)
+//		The controller actually ignores RVALID--but to be a valid slave,
+//		this must be assumed.
+//	7. The slave must also guarantee that RLAST == 1 anytime RVALID
+//
+//	As with the write side, the controller will fill in ARSIZE and ARPROT.
+//	They may be used or ignored by the slave.
+//
+//	Why?  This simplifies slave logic.  Slaves may interact with the bus
+//	using only the logic below:
+//
+//		always @(posedge S_AXI_ACLK)
+//		if (AWVALID) case(AWADDR)
+//		R1:	slvreg_1 <= WDATA;
+//		R2:	slvreg_2 <= WDATA;
+//		R3:	slvreg_3 <= WDATA;
+//		R4:	slvreg_4 <= WDATA;
+//		endcase
+//
+//		always @(*)
+//			BRESP = 2'b00; // OKAY
+//
+//		always @(posedge S_AXI_ACLK)
+//		if (ARVALID)
+//		case(ARADDR)
+//			R1: RDATA <= slvreg_1;
+//			R2: RDATA <= slvreg_2;
+//			R3: RDATA <= slvreg_3;
+//			R4: RDATA <= slvreg_4;
+//		endcase
+//
+//		always @(*)
+//			RRESP = 2'b00; // OKAY
+//
+//	This core will then keep track of the more complex bus logic, locking,
+//	burst length, burst ID's, etc, simplifying both slaves and connection
+//	logic.  Slaves with the more complicated (and proper/accurate) logic,
+//	that follow the rules above, should have no problems with this
+//	additional logic.
+//
+// Performance:
+//
+//	Throughput: The slave can sustain one read/write per clock as long as
+//	the upstream master keeps S_AXI_[BR]READY high.  If S_AXI_[BR]READY
+//	ever drops, there's some flexibility provided by the return FIFO, so
+//	the master might not notice a drop in throughput until the FIFO fills.
+//
+//	Latency: This core will create a four clock latency on all requests.
+//
+//	Logic: Actual logic depends upon how this is set up and built.  As
+//	parameterized below, this core can fit within 639 Xilinx 6-LUTs and
+//	39 M-LUTs.
+//
+//	Narrow bursts: This core supports narrow bursts by nature.  Whether the
+//	subcores pay attention to WSTRB, AWSIZE, and ARSIZE is up to the
+//	subcore itself.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+module	axidouble #(
+		parameter integer C_AXI_DATA_WIDTH = 32,
+		parameter integer C_AXI_ADDR_WIDTH = 32,
+		parameter integer C_AXI_ID_WIDTH = 1,
+		//
+		// NS is the number of slave interfaces.  If you are interested
+		// in a single slave interface, checkout the demofull.v core
+		// in this same repository.
+		parameter	NS = 8,
+		//
+		// Shorthand for address width, data width, and id width
+		// AW, and DW, are short-hand abbreviations used locally.
+		localparam AW = C_AXI_ADDR_WIDTH,
+		localparam DW = C_AXI_DATA_WIDTH,
+		localparam IW = C_AXI_ID_WIDTH,
+		//
+		// Each of the slave interfaces has an address range.  The
+		// base address for each slave is given by AW bits of SLAVE_ADDR
+		// below.
+		parameter	[NS*AW-1:0]	SLAVE_ADDR = {
+			{ 3'b111, {(AW-3){1'b0}} },
+			{ 3'b110, {(AW-3){1'b0}} },
+			{ 3'b101, {(AW-3){1'b0}} },
+			{ 3'b100, {(AW-3){1'b0}} },
+			{ 3'b011, {(AW-3){1'b0}} },
+			{ 3'b010, {(AW-3){1'b0}} },
+			{ 4'b0001,{(AW-4){1'b0}} },
+			{ 4'b0000,{(AW-4){1'b0}} } },
+		//
+		//
+		// The relevant bits of the slave address are given in
+		// SLAVE_MASK below, at AW bits per slave.  To be valid,
+		// SLAVE_ADDR & ~SLAVE_MASK must be zero.  Only the masked
+		// bits will be used in any compare.
+		//
+		// Also, while not technically required, it is strongly
+		// recommended that the bottom 12-bits of each AW bits of
+		// the SLAVE_MASK bust be zero.
+		parameter	[NS*AW-1:0]	SLAVE_MASK =
+			(NS <= 1) ? 0
+			: {	{(NS-2){ 3'b111, {(AW-3){1'b0}} }},
+				{(2){   4'b1111, {(AW-4){1'b0}} }}
+			},
+		//
+		// LGFLEN specifies the log (based two) of the number of
+		// transactions that may need to be held outstanding internally.
+		// If you really want high throughput, and if you expect any
+		// back pressure at all, then increase LGFLEN.  Otherwise the
+		// default value of 3 (FIFO size = 8) should be sufficient
+		// to maintain full loading
+		parameter	LGFLEN=3,
+		//
+		// This core will handle exclusive access if
+		// OPT_EXCLUSIVE_ACCESS is set to one.  If set to 1, all
+		// subcores will have exclusive access applied.  There is no
+		// core-by-core means of enabling exclusive access at this time.
+		parameter [0:0]	OPT_EXCLUSIVE_ACCESS = 1'b1
+		//
+	) (
+		input	wire				S_AXI_ACLK,
+		input	wire				S_AXI_ARESETN,
+		//
+		// Write address channel coming from upstream
+		input	wire				S_AXI_AWVALID,
+		output	wire				S_AXI_AWREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_AWID,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_AWADDR,
+		input	wire	[8-1:0]			S_AXI_AWLEN,
+		input	wire	[3-1:0]			S_AXI_AWSIZE,
+		input	wire	[2-1:0]			S_AXI_AWBURST,
+		input	wire				S_AXI_AWLOCK,
+		input	wire	[4-1:0]			S_AXI_AWCACHE,
+		input	wire	[3-1:0]			S_AXI_AWPROT,
+		input	wire	[4-1:0]			S_AXI_AWQOS,
+		//
+		// Write data channel coming from upstream
+		input	wire				S_AXI_WVALID,
+		output	wire				S_AXI_WREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]	S_AXI_WDATA,
+		input	wire [C_AXI_DATA_WIDTH/8-1:0]	S_AXI_WSTRB,
+		input	wire 				S_AXI_WLAST,
+		//
+		// Write responses sent back
+		output	wire				S_AXI_BVALID,
+		input	wire				S_AXI_BREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_BID,
+		output	wire	[2-1:0]			S_AXI_BRESP,
+		//
+		// Read address request channel from upstream
+		input	wire				S_AXI_ARVALID,
+		output	wire				S_AXI_ARREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_ARID,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_ARADDR,
+		input	wire	[8-1:0]			S_AXI_ARLEN,
+		input	wire	[3-1:0]			S_AXI_ARSIZE,
+		input	wire	[2-1:0]			S_AXI_ARBURST,
+		input	wire				S_AXI_ARLOCK,
+		input	wire	[4-1:0]			S_AXI_ARCACHE,
+		input	wire	[3-1:0]			S_AXI_ARPROT,
+		input	wire	[4-1:0]			S_AXI_ARQOS,
+		//
+		// Read data return channel back upstream
+		output	wire				S_AXI_RVALID,
+		input	wire				S_AXI_RREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_RID,
+		output	wire	[C_AXI_DATA_WIDTH-1:0]	S_AXI_RDATA,
+		output	wire				S_AXI_RLAST,
+		output	wire	[2-1:0]			S_AXI_RRESP,
+		//
+		//
+		// Now for the simplified downstream interface to a series
+		// of downstream slaves.  All outgoing wires are shared between
+		// the slaves save the AWVALID and ARVALID signals.  Slave
+		// returns are not shared.
+		//
+		//
+		// Simplified Write address channel.
+		output	wire	[NS-1:0]		M_AXI_AWVALID,
+		// input wire M_AXI_AWREADY is assumed to be 1
+		output	wire	[0:0]			M_AXI_AWID,//    = 0
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_AWADDR,
+		output	wire	[8-1:0]			M_AXI_AWLEN,//   = 0
+		output	wire	[3-1:0]			M_AXI_AWSIZE,
+		output	wire	[2-1:0]			M_AXI_AWBURST,//=INC
+		output	wire				M_AXI_AWLOCK,//  = 0
+		output	wire	[4-1:0]			M_AXI_AWCACHE,// = 0
+		output	wire	[3-1:0]			M_AXI_AWPROT,//  = 0
+		output	wire	[4-1:0]			M_AXI_AWQOS,//   = 0
+		//
+		// Simplified write data channel
+		output	wire	[NS-1:0]		M_AXI_WVALID,//=AWVALID
+		// input wire M_AXI_WVALID is *assumed* to be 1
+		output	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_WDATA,
+		output	wire [C_AXI_DATA_WIDTH/8-1:0]	M_AXI_WSTRB,
+		output	wire				M_AXI_WLAST,//   = 1
+		//
+		// Simplified write response channel
+		// input wire M_AXI_BVALID is *assumed* to be
+		//	$past(M_AXI_AWVALID), and so ignored
+		output	wire				M_AXI_BREADY,//  = 1
+		input	wire	[NS*2-1:0]		M_AXI_BRESP,
+		// The controller handles BID, so this can be ignored as well
+		//
+		// Simplified read address channel
+		output	wire	[NS-1:0]		M_AXI_ARVALID,
+		// input wire M_AXI_ARREADY is assumed to be 1
+		output	wire	[0:0]			M_AXI_ARID,//    = 0
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_ARADDR,
+		output	wire	[8-1:0]			M_AXI_ARLEN,//   = 0
+		output	wire	[3-1:0]			M_AXI_ARSIZE,
+		output	wire	[2-1:0]			M_AXI_ARBURST,//=INC
+		output	wire				M_AXI_ARLOCK,//  = 0
+		output	wire	[4-1:0]			M_AXI_ARCACHE,// = 0
+		output	wire	[3-1:0]			M_AXI_ARPROT,//  = 0
+		output	wire	[4-1:0]			M_AXI_ARQOS,//   = 0
+		//
+		// Simplified read data return channel
+		// input wire M_AXI_RVALID is assumed to be $past(ARVALID,1)
+		output	wire				M_AXI_RREADY,//  = 1
+		input	wire [NS*C_AXI_DATA_WIDTH-1:0]	M_AXI_RDATA,
+		input	wire	[NS*2-1:0]		M_AXI_RRESP
+		// input wire M_AXI_RLAST is assumed to be 1
+	);
+	//
+	//
+	// LGNS is the number of bits required in a slave index
+	localparam	LGNS = $clog2(NS);
+	//
+	localparam [1:0]	OKAY = 2'b00,
+				EXOKAY = 2'b01,
+				SLVERR = 2'b10,
+				INTERCONNECT_ERROR = 2'b11;
+	localparam	ADDR_LSBS = $clog2(DW)-3;
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Unused wire assignments
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	assign	M_AXI_AWID  = 0;
+	assign	M_AXI_AWLEN = 0;
+	assign	M_AXI_AWBURST = 2'b00;
+	assign	M_AXI_AWLOCK  = 1'b0;
+	assign	M_AXI_AWCACHE = 4'h3;
+	// assign	M_AXI_AWPROT  = 3'h0;
+	assign	M_AXI_AWQOS   = 4'h0;
+	//
+	assign	M_AXI_WVALID  = M_AXI_AWVALID;
+	assign	M_AXI_WLAST   = 1'b1;
+	//
+	assign	M_AXI_BREADY  = 1'b1;
+	//
+	assign	M_AXI_ARID	= 1'b0;
+	assign	M_AXI_ARLEN	= 8'h0; // Burst of one beat
+	assign	M_AXI_ARBURST	= 2'b00; // INC
+	assign	M_AXI_ARLOCK	= 1'b0;
+	assign	M_AXI_ARCACHE	= 4'h3;
+	// assign	M_AXI_ARPROT	= 3'h0;
+	assign	M_AXI_ARQOS	= 4'h0;
+	//
+	assign	M_AXI_RREADY	= -1;
+
+	////////////////////////////////////////////////////////////////////////
+
+	reg	locked_burst, locked_write, lock_valid;
+	integer			k;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write logic:
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	wire			awskd_stall;
+	wire			awskid_valid, bffull, bempty, write_awskidready,
+				dcd_awvalid;
+	reg			write_bvalid, write_response;
+	reg			bfull, write_no_index;
+	wire	[NS:0]		raw_wdecode;
+	reg	[NS:0]		last_wdecode, wdecode;
+	wire	[AW-1:0]	m_awaddr;
+	reg	[LGNS-1:0]	write_windex, write_bindex;
+	wire	[3-1:0]		awskid_prot, m_axi_awprot;
+	wire	[LGFLEN:0]	bfill;
+	reg	[LGFLEN:0]	write_count;
+	reg	[1:0]		write_resp;
+	//
+	reg	[C_AXI_ID_WIDTH-1:0]	write_id, write_bid, write_retid;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	write_addr;
+	wire	[C_AXI_ID_WIDTH-1:0]	awskid_awid;
+	wire	[C_AXI_ADDR_WIDTH-1:0]	awskid_awaddr, next_waddr;
+	reg			write_request, write_topofburst,
+				write_beat_bvalid;
+	reg	[3-1:0]		write_size;
+	reg	[2-1:0]		write_burst;
+	reg	[8-1:0]		write_len, write_awlen;
+	wire	[8-1:0]		awskid_awlen;
+	wire	[2-1:0]		awskid_awburst;
+	wire	[3-1:0]		awskid_awsize;
+	wire			awskid_awlock;
+	//
+	reg			write_top_beat;
+
+
+	//
+	// Incoming write address requests must go through a skidbuffer.  By
+	// keeping OPT_OUTREG == 0, this shouldn't cost us any time, but should
+	// instead buy us the ability to keep AWREADY high even if for reasons
+	// we can't act on AWVALID & AWREADY on the same cycle
+	skidbuffer #(.OPT_OUTREG(0),
+			.DW(C_AXI_ID_WIDTH+AW+8+3+2+1+3))
+	awskid(	.i_clk(S_AXI_ACLK),
+		.i_reset(!S_AXI_ARESETN),
+		.i_valid(S_AXI_AWVALID),
+			.o_ready(S_AXI_AWREADY),
+			.i_data({ S_AXI_AWID, S_AXI_AWADDR, S_AXI_AWLEN,
+				S_AXI_AWSIZE, S_AXI_AWBURST,
+				S_AXI_AWLOCK, S_AXI_AWPROT }),
+		.o_valid(awskid_valid), .i_ready(write_awskidready),
+			.o_data({ awskid_awid, awskid_awaddr, awskid_awlen,
+				awskid_awsize, awskid_awburst, awskid_awlock,
+				awskid_prot }));
+
+	//
+	// On any write address request (post-skidbuffer), copy down the details
+	// of that request.  Once these details are valid (i.e. on the next
+	// clock), S_AXI_WREADY will be true.
+	always @(posedge S_AXI_ACLK)
+	if (awskid_valid && write_awskidready)
+	begin
+		write_id    <= awskid_awid;
+		write_addr  <= awskid_awaddr;
+		write_size  <= awskid_awsize;
+		write_awlen <= awskid_awlen;
+		write_burst <= awskid_awburst;
+		// write_lock  <= awskid_awlock;
+	end else if (S_AXI_WVALID && S_AXI_WREADY)
+		// Following each write beat, we need to update our address
+		write_addr <= next_waddr;
+
+	//
+	// Given the details of the address request, get the next address to
+	// write to.
+	axi_addr #(.AW(C_AXI_ADDR_WIDTH), .DW(C_AXI_DATA_WIDTH))
+	get_next_write_address(write_addr,
+			write_size, write_burst, write_awlen, next_waddr);
+
+
+	//
+	// Count through the beats of the burst in write_len.  write_topofburst
+	// indicates the first beat in any new burst, but will be zero for all
+	// subsequent burst beats.  write_request is true anytime we are trying
+	// to write.
+	initial	write_request    = 1'b0;
+	initial	write_topofburst = 1'b1;
+	initial	write_len        = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		write_request    <= 1'b0;
+		write_topofburst <= 1'b1;
+		write_len        <= 0;
+	end else if (awskid_valid && write_awskidready)
+	begin
+		write_request    <= 1'b1;
+		write_topofburst <= 1'b1;
+		write_len        <= awskid_awlen;
+	end else if (S_AXI_WVALID && S_AXI_WREADY)
+	begin
+		write_topofburst <= 1'b0;
+		if (S_AXI_WLAST)
+			write_request <= 1'b0;
+		if (write_len > 0)
+			write_len <= write_len - 1;
+	end
+
+	// Decode our incoming address in order to determine the next
+	// slave the address addresses
+	addrdecode #(.AW(AW), .DW(3), .NS(NS),
+		.SLAVE_ADDR(SLAVE_ADDR),
+		.SLAVE_MASK(SLAVE_MASK),
+		.OPT_REGISTERED(1'b1))
+	wraddr(.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_valid(awskid_valid && write_awskidready), .o_stall(awskd_stall),
+			// .i_addr(awskid_valid && write_awskidready
+			//	? awskid_awaddr : next_waddr),
+			.i_addr(awskid_awaddr),
+			.i_data(awskid_prot),
+		.o_valid(dcd_awvalid), .i_stall(!S_AXI_WVALID),
+			.o_decode(raw_wdecode), .o_addr(m_awaddr),
+			.o_data(m_axi_awprot));
+
+	// We only do our decode on the address request.  We need the decoded
+	// values long after the top of the burst.  Therefore, let's use
+	// dcd_awvalid to know we have a valid output from the decoder and
+	// then we'll latch that (register it really) for the rest of the burst
+	always @(posedge S_AXI_ACLK)
+	if (dcd_awvalid)
+		last_wdecode <= raw_wdecode;
+
+	always @(*)
+	begin
+		if (dcd_awvalid)
+			wdecode = raw_wdecode;
+		else
+			wdecode = last_wdecode;
+	end
+
+	//
+	// It's now time to create our write request for the slave.  Slave
+	// writes take place on the clock after address valid is true as long
+	// as S_AXI_WVALID is true.  This places combinatorial logic onto the
+	// outgoing AWVALID.  The sign that we are in the middle of a burst
+	// will specifically be that WREADY is true.
+	//
+
+	//
+	// If there were any part of this algorithm I disliked it would be the
+	// AWVALID logic here.  It shouldn't nearly be this loaded.
+	assign	S_AXI_WREADY  = write_request;
+	assign	M_AXI_AWVALID = (S_AXI_WVALID && write_request
+			&& (!locked_burst || locked_write)) ? wdecode[NS-1:0] : 0;
+	assign	M_AXI_AWADDR  = write_addr;
+	assign	M_AXI_AWPROT  = m_axi_awprot;
+	assign	M_AXI_AWSIZE  = write_size;
+	assign	M_AXI_WDATA   = S_AXI_WDATA;
+	assign	M_AXI_WSTRB   = S_AXI_WSTRB;
+
+	// We can accept a new value from the skid buffer as soon as the last
+	// write value comes in, or equivalently if we are not in the middle
+	// of a write.  This is all subject, of course, to our backpressure
+	// FIFO not being full.
+	assign	write_awskidready = ((S_AXI_WVALID&&S_AXI_WLAST)
+						|| !S_AXI_WREADY) && !bfull;
+
+	// Back out an index from our decoded slave value
+	always @(*)
+	begin
+		write_windex = 0;
+		for(k=0; k<NS; k=k+1)
+		if (wdecode[k])
+			write_windex = write_windex | k[LGNS-1:0];
+	end
+
+	always @(posedge S_AXI_ACLK)
+	begin
+		write_bindex <= write_windex;
+		write_no_index <= wdecode[NS];
+	end
+
+	always @(posedge S_AXI_ACLK)
+	// if (write_top_of_burst) // -- not necessary
+		write_bid <= write_id;
+
+	// write_bvalid will be true one clock after the last write is accepted.
+	// This is the internal signal that would've come from a subordinate
+	// slave's BVALID, save that we are generating it internally.
+	initial	{ write_response, write_bvalid } = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		{ write_response, write_bvalid } <= 0;
+	else
+		{ write_response, write_bvalid } <= { write_bvalid,
+			(S_AXI_WVALID && S_AXI_WREADY&& S_AXI_WLAST) };
+
+	//
+	// Examine write beats, not just write bursts
+	always @(posedge S_AXI_ACLK)
+	begin
+		write_top_beat    <= write_topofburst;
+		write_beat_bvalid <= S_AXI_WVALID && S_AXI_WREADY;
+	end
+
+	// The response from any burst should be an DECERR (interconnect
+	// error) if ever the addressed slave doesn't exist in our address map.
+	// This is sticky: any attempt to generate a request to a non-existent
+	// slave will generate an interconnect error.  Likewise, if the slave
+	// ever returns a slave error, we'll propagate it back in the burst
+	// return.  Finally, on an exclusive access burst, we'll return EXOKAY
+	// if we could write the values.
+	always @(posedge S_AXI_ACLK)
+	if (write_beat_bvalid)
+	begin
+		if (write_no_index)
+			write_resp <= INTERCONNECT_ERROR;
+		else if (M_AXI_BRESP[2*write_bindex])
+			write_resp <= { 1'b1, (write_top_beat)
+						? 1'b0 : write_resp[0] };
+		else if (write_top_beat || !write_resp[1])
+			write_resp <= { 1'b0, (write_top_beat && locked_burst && locked_write) };
+	end
+
+	always @(posedge S_AXI_ACLK)
+		write_retid <= write_bid;
+
+	//
+	// The pseudo-FIFO for the write side.  This counter will let us know
+	// if any write response will ever overflow our write response FIFO,
+	// allowing us to be able to confidently deal with any backpressure.
+	initial	write_count = 0;
+	initial	bfull = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		write_count <= 0;
+		bfull <= 0;
+	end else case({ (awskid_valid && write_awskidready),
+			(S_AXI_BVALID & S_AXI_BREADY) })
+	2'b01:	begin
+		write_count <= write_count - 1;
+		bfull <= 1'b0;
+		end
+	2'b10:	begin
+		write_count <= write_count + 1;
+		bfull <= (&write_count[LGFLEN-1:0]);
+		end
+	default: begin end
+	endcase
+
+	//
+	// Backpressure FIFO on write response returns
+	sfifo #(.BW(C_AXI_ID_WIDTH+2), .OPT_ASYNC_READ(0), .LGFLEN(LGFLEN))
+	bfifo ( .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_wr(write_response), .i_data({ write_retid, write_resp }),
+			.o_full(bffull), .o_fill(bfill),
+		.i_rd(S_AXI_BVALID && S_AXI_BREADY),
+			.o_data({ S_AXI_BID, S_AXI_BRESP }),
+			.o_empty(bempty));
+
+	assign	S_AXI_BVALID = !bempty;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read logic
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	wire				rempty, rdfull;
+	wire	[LGFLEN:0]		rfill;
+	reg	[LGNS-1:0]		read_index, last_read_index;
+	reg	[1:0]			read_resp;
+	reg	[DW-1:0]		read_rdata;
+	wire				read_rwait, arskd_stall;
+	reg				read_rvalid, read_result, read_no_index;
+	wire	[AW-1:0]		m_araddr;
+	reg	[AW-1:0]		araddr;
+	reg	[3-1:0]			arprot;
+	wire	[NS:0]			raw_rdecode;
+
+	reg	[C_AXI_ID_WIDTH-1:0]	arid, read_rvid, read_retid;
+	reg	[3-1:0]			arsize;
+	reg	[2-1:0]			arburst;
+	reg				arlock, read_rvlock;
+	reg				read_rvlast, read_retlast;
+	reg	[8-1:0]			arlen, rlen;
+	wire	[C_AXI_ADDR_WIDTH-1:0]	next_araddr;
+	wire				issue_read;
+	reg			read_full;
+	reg	[LGFLEN:0]	read_count;
+	reg			arvalid;
+	reg	[NS:0]		last_rdecode, rdecode;
+
+
+	//
+	// Copy the burst information, for use in determining the next address
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARVALID && S_AXI_ARREADY)
+	begin
+		araddr  <= S_AXI_ARADDR;
+		arid    <= S_AXI_ARID;
+		arlen   <= S_AXI_ARLEN;
+		arsize  <= S_AXI_ARSIZE;
+		arburst <= S_AXI_ARBURST;
+		arlock  <= S_AXI_ARLOCK;
+		arprot  <= S_AXI_ARPROT;
+	end else if (issue_read)
+		araddr  <= next_araddr;
+
+	// Count the number of remaining items in a burst.  Note that rlen
+	// counts from N-1 to 0, not from N to 1.
+	initial	rlen = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		rlen   <= 0;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY)
+		rlen    <= S_AXI_ARLEN;
+	else if (issue_read && (rlen > 0))
+		rlen <= rlen - 1;
+
+	// Should the slave M_AXI_ARVALID be true in general?  Based upon
+	// rlen above, but still needs to be gated across all slaves.
+	initial	arvalid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		arvalid <= 1'b0;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY)
+		arvalid <= 1'b1;
+	else if (issue_read && (rlen == 0))
+		arvalid <= 1'b0;
+
+	// Get the next AXI address
+	axi_addr #(.AW(C_AXI_ADDR_WIDTH), .DW(C_AXI_DATA_WIDTH))
+	get_next_read_address(araddr,
+			arsize, arburst, arlen, next_araddr);
+
+	//
+	// Decode which slave is being addressed by this read.
+	wire	[0:0]	unused_pin;
+	addrdecode #(.AW(AW), .DW(1), .NS(NS),
+		.SLAVE_ADDR(SLAVE_ADDR),
+		.SLAVE_MASK(SLAVE_MASK),
+		.OPT_REGISTERED(1'b1))
+	rdaddr(.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_valid(S_AXI_ARVALID && S_AXI_ARREADY || rlen>0),
+			// Warning: there's no skid on this stall
+			.o_stall(arskd_stall),
+			.i_addr((S_AXI_ARVALID & S_AXI_ARREADY)
+				? S_AXI_ARADDR : next_araddr),
+			.i_data(1'b0),
+		.o_valid(read_rwait), .i_stall(!issue_read),
+			.o_decode(raw_rdecode), .o_addr(m_araddr),
+			.o_data(unused_pin[0]));
+
+	//
+	// We want the value from the decoder on the first clock cycle.  It
+	// may not be valid after that, so we'll hold on to it in last_rdecode
+	initial	last_rdecode = 0;
+	always @(posedge S_AXI_ACLK)
+	if (read_rwait)
+		last_rdecode <= raw_rdecode;
+
+	always @(*)
+	if (read_rwait)
+		rdecode = raw_rdecode;
+	else
+		rdecode = last_rdecode;
+
+	//
+	// Finally, issue our read request any time the FIFO isn't full
+	assign	issue_read    = !read_full;
+
+	assign	M_AXI_ARVALID = issue_read ? rdecode[NS-1:0] : 0;
+	assign	M_AXI_ARADDR  = m_araddr;
+	assign	M_AXI_ARPROT  = arprot;
+	assign	M_AXI_ARSIZE  = arsize;
+
+	//
+	// read_rvalid would be the RVALID response from the slave that would
+	// be returned if we checked it.  read_result is the same thing--one
+	// clock later.
+	initial	{ read_result, read_rvalid } = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		{ read_result, read_rvalid } <= 2'b00;
+	else
+		{ read_result, read_rvalid } <= { read_rvalid,
+				(arvalid&issue_read) };
+
+	// On the same clock when rvalid is true, we'll also want to know
+	// if RLAST should be true (decoded here, not in the slave), and
+	// whether or not the transaction is locked.  These values are valid
+	// any time read_rvalid is true.
+	always @(posedge S_AXI_ACLK)
+	if (arvalid && issue_read)
+	begin
+		read_rvid   <= arid;
+		read_rvlast <= (rlen == 0);
+		read_rvlock <= OPT_EXCLUSIVE_ACCESS && arlock && lock_valid;
+	end
+
+	// read_result is true one clock after read_rvalid is true.  Copy
+	// the ID and LAST values into this pipeline clock cycle
+	always @(posedge S_AXI_ACLK)
+	begin
+		read_retid   <= read_rvid;
+		read_retlast <= read_rvlast;
+	end
+
+	//
+	// Decode the read value.
+	//
+
+	//
+	// First step is to calculate the index of the slave
+	always @(*)
+	begin
+		read_index = 0;
+
+		for(k=0; k<NS; k=k+1)
+		if (rdecode[k])
+			read_index = read_index | k[LGNS-1:0];
+	end
+
+	//
+	// Keep this index into the RVALID cycle
+	always @(posedge S_AXI_ACLK)
+		last_read_index <= read_index;
+
+	// read_no_index is a flag to indicate that no slave was indexed.
+	always @(posedge S_AXI_ACLK)
+		read_no_index <= rdecode[NS];
+
+	// Now we can use last_read_index to determine the return data.
+	// read_rdata will be valid on the same clock $past(RVALID) or
+	// read_return cycle
+	always @(posedge S_AXI_ACLK)
+		read_rdata <= M_AXI_RDATA[DW*last_read_index +: DW];
+
+	//
+	// As with read_rdata, read_resp is the response from the slave
+	always @(posedge S_AXI_ACLK)
+	if (read_no_index)
+		read_resp <= INTERCONNECT_ERROR;
+	else if (M_AXI_RRESP[2*last_read_index + 1])
+		read_resp <= SLVERR;	// SLVERR
+	else if (OPT_EXCLUSIVE_ACCESS && read_rvlock)
+		read_resp <= EXOKAY;	// Exclusive access Okay
+	else
+		read_resp <= OKAY;	// OKAY
+
+	//
+	// Since we can't allow the incoming requests to overflow in the
+	// presence of any back pressure, let's create a phantom FIFO here
+	// counting the number of values either in the final pipeline or in
+	// final read FIFO.  If read_full is true, the FIFO is full and we
+	// cannot move any more data forward.
+	initial	{ read_count, read_full } = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		{ read_count, read_full } <= 0;
+	else case({ read_rwait && issue_read, S_AXI_RVALID & S_AXI_RREADY})
+	2'b10: begin
+		read_count <= read_count + 1;
+		read_full  <= &read_count[LGFLEN-1:0];
+		end
+	2'b01: begin
+		read_count <= read_count - 1;
+		read_full <= 1'b0;
+		end
+	default: begin end
+	endcase
+
+	assign	S_AXI_ARREADY = (rlen == 0) && !read_full;
+
+	//
+	// Send the return results through a synchronous FIFO to handle
+	// back-pressure.  Doing this costs us one clock of latency.
+	sfifo #(.BW(C_AXI_ID_WIDTH+DW+1+2), .OPT_ASYNC_READ(0), .LGFLEN(LGFLEN))
+	rfifo ( .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_wr(read_result), .i_data({ read_retid, read_rdata,
+						read_retlast, read_resp }),
+			.o_full(rdfull), .o_fill(rfill),
+		.i_rd(S_AXI_RVALID && S_AXI_RREADY),
+			.o_data({ S_AXI_RID, S_AXI_RDATA, S_AXI_RLAST, S_AXI_RRESP }),.o_empty(rempty));
+
+	assign	S_AXI_RVALID = !rempty;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Exclusive access / Bus locking logic
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate if (OPT_EXCLUSIVE_ACCESS)
+	begin : EXCLUSIVE_ACCESS
+
+		reg	[AW-1:0]	lock_addr, lock_last;
+		reg	[4-1:0]		lock_len;
+		reg	[3-1:0]		lock_size;
+
+		initial	lock_valid   = 1'b0;
+		initial	locked_burst = 1'b0;
+		initial	locked_write = 1'b0;
+		always @(posedge S_AXI_ACLK)
+		begin
+
+			//
+			// Step one: Set the lock_valid signal.  This means
+			// that a read request has been successful requesting
+			// the lock for this address.
+			//
+			if (awskid_valid && write_awskidready)
+			begin
+				// On any write to the value inside our lock
+				// range, disable the lock_valid signal
+				if ((awskid_awaddr
+					+ ({ {(AW-4){1'b0}},awskid_awlen[3:0]} << S_AXI_AWSIZE)
+						>= lock_addr)
+					&&(S_AXI_AWADDR <= lock_last))
+					lock_valid <= 0;
+			end
+
+			if (S_AXI_ARVALID && S_AXI_ARREADY && S_AXI_ARLOCK)
+			begin
+				lock_valid <= !locked_write;
+				lock_addr  <= S_AXI_ARADDR;
+				lock_size  <= S_AXI_ARSIZE;
+				lock_len   <= S_AXI_ARLEN[3:0];
+				lock_last  <= S_AXI_ARADDR
+					+ ({ {(AW-4){1'b0}}, lock_len }
+							<< S_AXI_ARSIZE);
+			end
+
+			if (awskid_valid && write_awskidready)
+			begin
+				locked_burst <= 1'b0;
+				locked_write <= awskid_awlock;
+
+				if (awskid_awlock)
+				begin
+					locked_burst <= lock_valid;
+					if (lock_addr != awskid_awaddr)
+						locked_burst <= 1'b0;
+					if (lock_size != awskid_awsize)
+						locked_burst <= 1'b0;
+					if ({ 4'h0, lock_len } != awskid_awlen)
+						locked_burst <= 1'b0;
+				end
+
+				// Write if !locked_write || write_burst
+				// EXOKAY on locked_write && write_burst
+				// OKAY on all other writes where the slave
+				//   does not assert an error
+			end else if (S_AXI_WVALID && S_AXI_WREADY && S_AXI_WLAST)
+				locked_burst <= 1'b0;
+
+			if (!S_AXI_ARESETN)
+			begin
+				lock_valid  <= 1'b0;
+				locked_burst <= 1'b0;
+			end
+		end
+	end else begin : NO_EXCLUSIVE_ACCESS
+
+		// Keep track of whether or not the current burst requests
+		// exclusive access or not.  locked_write is an important
+		// signal used to make certain that we do not write to our
+		// slave on any locked write requests.  (Shouldn't happen,
+		// since we aren't returning any EXOKAY's from reads ...)
+		always @(posedge S_AXI_ACLK)
+		if (awskid_valid && write_awskidready)
+			locked_write <= awskid_awlock;
+		else if (S_AXI_WVALID && S_AXI_WREADY && S_AXI_WLAST)
+			locked_write <= 1'b0;
+
+		always @(*)
+			locked_burst <= 1'b0;
+
+		always @(*)
+			lock_valid = 1'b0;
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+
+	// Make Verilator happy
+	//
+	// verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0,
+			S_AXI_AWCACHE, S_AXI_ARCACHE,
+			S_AXI_AWQOS,   S_AXI_ARQOS,
+			dcd_awvalid, m_awaddr, unused_pin,
+			bffull, rdfull, bfill, rfill,
+			awskd_stall, arskd_stall };
+	// verilator lint_on  UNUSED
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal verification properties
+//
+// The following are a subset of the formal properties used to verify this
+// module.
+//
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	localparam	F_LGDEPTH = LGFLEN+9;
+
+	//
+	// ...
+	//
+
+	faxi_slave #(	.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+			.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+			.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+			.F_AXI_MAXDELAY(5),
+			.F_LGDEPTH(F_LGDEPTH))
+		properties (
+		.i_clk(S_AXI_ACLK),
+		.i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXI_AWVALID),
+		.i_axi_awready(S_AXI_AWREADY),
+		.i_axi_awid(   S_AXI_AWID),
+		.i_axi_awaddr( S_AXI_AWADDR),
+		.i_axi_awlen(  S_AXI_AWLEN),
+		.i_axi_awsize( S_AXI_AWSIZE),
+		.i_axi_awburst(S_AXI_AWBURST),
+		.i_axi_awlock( S_AXI_AWLOCK),
+		.i_axi_awcache(S_AXI_AWCACHE),
+		.i_axi_awprot( S_AXI_AWPROT),
+		.i_axi_awqos(  S_AXI_AWQOS),
+		//
+		.i_axi_wvalid(S_AXI_WVALID),
+		.i_axi_wready(S_AXI_WREADY),
+		.i_axi_wdata( S_AXI_WDATA),
+		.i_axi_wstrb( S_AXI_WSTRB),
+		.i_axi_wlast( S_AXI_WLAST),
+		//
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+		.i_axi_bid(   S_AXI_BID),
+		.i_axi_bresp( S_AXI_BRESP),
+		//
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+		.i_axi_arid(   S_AXI_ARID),
+		.i_axi_araddr( S_AXI_ARADDR),
+		.i_axi_arlen(  S_AXI_ARLEN),
+		.i_axi_arsize( S_AXI_ARSIZE),
+		.i_axi_arburst(S_AXI_ARBURST),
+		.i_axi_arlock( S_AXI_ARLOCK),
+		.i_axi_arcache(S_AXI_ARCACHE),
+		.i_axi_arprot( S_AXI_ARPROT),
+		.i_axi_arqos(  S_AXI_ARQOS),
+		//
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rready(S_AXI_RREADY),
+		.i_axi_rid(   S_AXI_RID),
+		.i_axi_rdata( S_AXI_RDATA),
+		.i_axi_rlast( S_AXI_RLAST),
+		.i_axi_rresp( S_AXI_RRESP)
+		//
+		// ...
+		//
+		);
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (!OPT_EXCLUSIVE_ACCESS)
+	begin
+		assert(!S_AXI_BVALID || S_AXI_BRESP != EXOKAY);
+		assert(!S_AXI_RVALID || S_AXI_RRESP != EXOKAY);
+	end
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Properties necessary to pass induction
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(*)
+		assert($onehot0(M_AXI_AWVALID));
+
+	always @(*)
+		assert($onehot0(M_AXI_ARVALID));
+
+	//
+	//
+	// Write properties
+	//
+	//
+
+	always @(*)
+	if (S_AXI_WVALID && S_AXI_WREADY)
+	begin
+		if (locked_burst && !locked_write)
+			assert(M_AXI_AWVALID == 0);
+		else if (wdecode[NS])
+			assert(M_AXI_AWVALID == 0);
+		else begin
+			assert($onehot(M_AXI_AWVALID));
+			assert(M_AXI_AWVALID == wdecode[NS-1:0]);
+		end
+	end else
+		assert(M_AXI_AWVALID == 0);
+
+	//
+	// ...
+	//
+
+	//
+	//
+	// Read properties
+	//
+	//
+
+	//
+	// ...
+	//
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Simplifying (careless) assumptions
+	//
+	// Caution: these might void your proof
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	localparam	[0:0]	F_CHECK_WRITES = 1'b1;
+	localparam	[0:0]	F_CHECK_READS  = 1'b1;
+
+	generate if (!F_CHECK_WRITES)
+	begin
+		always @(*)
+			assume(!S_AXI_AWVALID);
+		always @(*)
+			assert(!S_AXI_BVALID);
+		always @(*)
+			assert(!M_AXI_AWVALID);
+
+		// ...
+	end endgenerate
+
+	generate if (!F_CHECK_READS)
+	begin
+		always @(*)
+			assume(!S_AXI_ARVALID);
+		always @(*)
+			assert(!S_AXI_RVALID);
+		always @(*)
+			assert(M_AXI_ARVALID == 0);
+		always @(*)
+			assert(rdecode == 0);
+		// ...
+	end endgenerate
+
+	//
+	// ...
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	[3:0]	cvr_arvalids, cvr_awvalids, cvr_reads, cvr_writes;
+	(* anyconst *)	reg	cvr_burst;
+
+	always @(*)
+	if (cvr_burst && S_AXI_AWVALID)
+		assume(S_AXI_AWLEN > 2);
+
+	always @(*)
+	if (cvr_burst && S_AXI_ARVALID)
+		assume(S_AXI_ARLEN > 2);
+
+	initial	cvr_awvalids = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!cvr_burst || !S_AXI_ARESETN)
+		cvr_awvalids <= 0;
+	else if (S_AXI_AWVALID && S_AXI_AWREADY && !(&cvr_awvalids))
+		cvr_awvalids <= cvr_awvalids + 1;
+
+	initial	cvr_arvalids = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!cvr_burst || !S_AXI_ARESETN)
+		cvr_arvalids <= 0;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY && !(&cvr_arvalids))
+		cvr_arvalids <= cvr_arvalids + 1;
+
+	initial	cvr_writes = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!cvr_burst || !S_AXI_ARESETN)
+		cvr_writes <= 0;
+	else if (S_AXI_BVALID && S_AXI_BREADY && !(&cvr_writes))
+		cvr_writes <= cvr_writes + 1;
+
+	initial	cvr_reads = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_reads <= 0;
+	else if (S_AXI_RVALID && S_AXI_RREADY && S_AXI_RLAST
+				&& !(&cvr_arvalids))
+		cvr_reads <= cvr_reads + 1;
+
+	generate if (F_CHECK_WRITES)
+	begin : COVER_WRITES
+
+		always @(*)
+			cover(cvr_awvalids > 2);
+
+		always @(*)
+			cover(cvr_writes > 2);
+
+		always @(*)
+			cover(cvr_writes > 4);
+	end endgenerate
+
+	generate if (F_CHECK_READS)
+	begin : COVER_READS
+		always @(*)
+			cover(cvr_arvalids > 2);
+
+		always @(*)
+			cover(cvr_reads > 2);
+
+		always @(*)
+			cover(cvr_reads > 4);
+	end endgenerate
+
+	always @(*)
+		cover((cvr_writes > 2) && (cvr_reads > 2));
+
+	generate if (OPT_EXCLUSIVE_ACCESS)
+	begin : COVER_EXCLUSIVE_ACCESS
+
+		always @(*)
+			cover(S_AXI_BVALID && S_AXI_BRESP == EXOKAY);
+
+	end endgenerate
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axiempty.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axiempty.v
new file mode 100644
index 0000000..f780ac3
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axiempty.v
@@ -0,0 +1,437 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename:	axiempty.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	A basic AXI core to provide a response to an AXI master when
+//		no other slaves are connected to the bus.  All results are
+//	bus errors.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+//
+`default_nettype	none
+//
+module axiempty #(
+	parameter integer C_AXI_ID_WIDTH	= 2,
+	parameter integer C_AXI_DATA_WIDTH	= 32,
+	parameter integer C_AXI_ADDR_WIDTH	= 6,
+	// Some useful short-hand definitions
+	localparam	AW = C_AXI_ADDR_WIDTH,
+	localparam	DW = C_AXI_DATA_WIDTH,
+	localparam	IW = C_AXI_ID_WIDTH,
+	localparam	LSB = $clog2(C_AXI_DATA_WIDTH)-3
+	) (
+		input	wire				S_AXI_ACLK,
+		input	wire				S_AXI_ARESETN,
+		//
+		input	wire				S_AXI_AWVALID,
+		output	wire				S_AXI_AWREADY,
+		input	wire [C_AXI_ID_WIDTH-1:0]	S_AXI_AWID,
+		//
+		input	wire				S_AXI_WVALID,
+		output	wire				S_AXI_WREADY,
+		input	wire				S_AXI_WLAST,
+		//
+		output	wire				S_AXI_BVALID,
+		input	wire				S_AXI_BREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_BID,
+		output	wire	[1:0]			S_AXI_BRESP,
+		//
+		input	wire				S_AXI_ARVALID,
+		output	wire				S_AXI_ARREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_ARID,
+		input	wire	[7:0]			S_AXI_ARLEN,
+		//
+		output	wire				S_AXI_RVALID,
+		input	wire				S_AXI_RREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_RID,
+		output	wire [C_AXI_DATA_WIDTH-1:0]	S_AXI_RDATA,
+		output	wire				S_AXI_RLAST,
+		output	wire	[1:0]			S_AXI_RRESP
+	);
+
+	// Double buffer the write response channel only
+	reg	[IW-1 : 0]	axi_bid;
+	reg			axi_bvalid;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write logic
+	//
+
+	//
+	// Start with the two skid buffers
+	//
+	wire			m_awvalid, m_wvalid;
+	wire			m_awready, m_wready, m_wlast;
+	wire	[IW-1:0]	m_awid;
+	//
+	skidbuffer #(.DW(IW), .OPT_OUTREG(1'b0))
+	awskd(S_AXI_ACLK, !S_AXI_ARESETN,
+		S_AXI_AWVALID, S_AXI_AWREADY, S_AXI_AWID,
+		m_awvalid, m_awready, m_awid );
+
+	skidbuffer #(.DW(1), .OPT_OUTREG(1'b0))
+	wskd(S_AXI_ACLK, !S_AXI_ARESETN,
+		S_AXI_WVALID, S_AXI_WREADY, S_AXI_WLAST,
+		m_wvalid, m_wready, m_wlast );
+
+	//
+	// The logic here is pretty simple--accept a write address burst
+	// into the skid buffer, then leave it there while the write data comes
+	// on.  Once we get to the last write data element, accept both it and
+	// the address.  This spares us the trouble of counting out the elements
+	// in the write burst.
+	//
+	assign	m_awready= (m_awvalid && m_wvalid && m_wlast)
+			&& (!S_AXI_BVALID || S_AXI_BREADY);
+	assign	m_wready = !m_wlast || m_awready;
+
+	//
+	// As soon as m_awready above, a packet has come through successfully.
+	// Acknowledge  it with a bus error.
+	//
+	initial	axi_bvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_bvalid <= 1'b0;
+	else if (m_awready)
+		axi_bvalid <= 1'b1;
+	else if (S_AXI_BREADY)
+		axi_bvalid <= 1'b0;
+
+	always @(posedge S_AXI_ACLK)
+	if (m_awready)
+		axi_bid <= m_awid;
+
+	assign	S_AXI_BVALID = axi_bvalid;
+	assign	S_AXI_BID    = axi_bid;
+	assign	S_AXI_BRESP  = 2'b11;	// An interconnect bus error
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read half
+	//
+	reg	[IW-1:0]	rid, axi_rid;
+	reg			axi_arready, axi_rlast, axi_rvalid;
+	reg	[8:0]		axi_rlen;
+
+	initial axi_arready = 1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_arready <= 1;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY)
+		axi_arready <= (S_AXI_ARLEN==0)&&(!S_AXI_RVALID|| S_AXI_RREADY);
+	else if (!S_AXI_RVALID || S_AXI_RREADY)
+	begin
+		if ((!axi_arready)&&(S_AXI_RVALID))
+			axi_arready <= (axi_rlen <= 2);
+	end
+
+	initial	axi_rlen = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_rlen <= 0;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY)
+		axi_rlen <= (S_AXI_ARLEN+1)
+				+ ((S_AXI_RVALID && !S_AXI_RREADY) ? 1:0);
+	else if (S_AXI_RREADY && S_AXI_RVALID)
+		axi_rlen <= axi_rlen - 1;
+
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARREADY)
+		rid      <= S_AXI_ARID;
+
+	initial	axi_rvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_rvalid <= 0;
+	else if (S_AXI_ARVALID || (axi_rlen > 1))
+		axi_rvalid <= 1;
+	else if (S_AXI_RREADY)
+		axi_rvalid <= 0;
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_RVALID || S_AXI_RREADY)
+	begin
+		if (S_AXI_ARVALID && S_AXI_ARREADY)
+			axi_rid <= S_AXI_ARID;
+		else
+			axi_rid <= rid;
+	end
+
+	initial axi_rlast   = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_RVALID || S_AXI_RREADY)
+	begin
+		if (S_AXI_ARVALID && S_AXI_ARREADY)
+			axi_rlast <= (S_AXI_ARLEN == 0);
+		else if (S_AXI_RVALID)
+			axi_rlast <= (axi_rlen == 2);
+		else
+			axi_rlast <= (axi_rlen == 1);
+	end
+
+	//
+	assign	S_AXI_ARREADY = axi_arready;
+	assign	S_AXI_RVALID  = axi_rvalid;
+	assign	S_AXI_RID     = axi_rid;
+	assign	S_AXI_RDATA   = 0;
+	assign	S_AXI_RRESP   = 2'b11;
+	assign	S_AXI_RLAST   = axi_rlast;
+	//
+
+	// Make Verilator happy
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0 };
+	// Verilator lint_on  UNUSED
+
+`ifdef	FORMAL
+	//
+	// The following properties are only some of the properties used
+	// to verify this core
+	//
+	reg	f_past_valid;
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+
+	always @(*)
+	if (!f_past_valid)
+		assume(!S_AXI_ARESETN);
+
+	faxi_slave	#(
+		// {{{
+		.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH)
+		// }}}
+	f_slave(
+		// {{{
+		.i_clk(S_AXI_ACLK),
+		.i_axi_reset_n(S_AXI_ARESETN),
+		//
+		// Address write channel
+		//
+		.i_axi_awvalid(S_AXI_AWVALID),
+		.i_axi_awready(S_AXI_AWREADY),
+		.i_axi_awid(   S_AXI_AWID),
+		.i_axi_awaddr( {(C_AXI_ADDR_WIDTH){1'b0}}),
+		.i_axi_awlen(  S_AXI_AWLEN),
+		.i_axi_awsize( LSB[2:0]),
+		.i_axi_awburst(2'b0),
+		.i_axi_awlock( 1'b0),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot( 3'h0),
+		.i_axi_awqos(  4'h0),
+	//
+	//
+		//
+		// Write Data Channel
+		//
+		// Write Data
+		.i_axi_wdata({(C_AXI_DATA_WIDTH){1'b0}}),
+		.i_axi_wstrb({(C_AXI_DATA_WIDTH/8){1'b0}}),
+		.i_axi_wlast(S_AXI_WLAST),
+		.i_axi_wvalid(S_AXI_WVALID),
+		.i_axi_wready(S_AXI_WREADY),
+	//
+	//
+		// Response ID tag. This signal is the ID tag of the
+		// write response.
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+		.i_axi_bid(   S_AXI_BID),
+		.i_axi_bresp( S_AXI_BRESP),
+	//
+	//
+		//
+		// Read address channel
+		//
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+		.i_axi_arid(   S_AXI_ARID),
+		.i_axi_araddr( {(C_AXI_ADDR_WIDTH){1'b0}}),
+		.i_axi_arlen(  S_AXI_ARLEN),
+		.i_axi_arsize( LSB[2:0]),
+		.i_axi_arburst(2'b00),
+		.i_axi_arlock( 1'b0),
+		.i_axi_arcache(4'h0),
+		.i_axi_arprot( 3'h0),
+		.i_axi_arqos(  4'h0),
+	//
+	//
+		//
+		// Read data return channel
+		//
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rready(S_AXI_RREADY),
+		.i_axi_rid(S_AXI_RID),
+		.i_axi_rdata(S_AXI_RDATA),
+		.i_axi_rresp(S_AXI_RRESP),
+		.i_axi_rlast(S_AXI_RLAST),
+		//
+		// ...
+		// }}}
+	);
+
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write induction properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+
+	//
+	// ...
+	//
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read induction properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	//
+	// ...
+	//
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $rose(S_AXI_RLAST))
+		assert(S_AXI_ARREADY);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Contract checking
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	//
+	// ...
+	//
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	reg	f_wr_cvr_valid, f_rd_cvr_valid;
+
+	initial	f_wr_cvr_valid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_wr_cvr_valid <= 0;
+	else if (S_AXI_AWVALID && S_AXI_AWREADY && S_AXI_AWLEN > 4)
+		f_wr_cvr_valid <= 1;
+
+	always @(*)
+		cover(!S_AXI_BVALID && axi_awready && !m_awvalid
+			&& f_wr_cvr_valid /* && ... */));
+
+	initial	f_rd_cvr_valid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_rd_cvr_valid <= 0;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY && S_AXI_ARLEN > 4)
+		f_rd_cvr_valid <= 1;
+
+	always @(*)
+		cover(S_AXI_ARREADY && f_rd_cvr_valid /* && ... */);
+
+	//
+	// Generate cover statements associated with multiple successive bursts
+	//
+	// These will be useful for demonstrating the throughput of the core.
+	//
+	reg	[4:0]	f_dbl_rd_count, f_dbl_wr_count;
+
+	initial	f_dbl_wr_count = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_dbl_wr_count = 0;
+	else if (S_AXI_AWVALID && S_AXI_AWREADY && S_AXI_AWLEN == 3)
+	begin
+		if (!(&f_dbl_wr_count))
+			f_dbl_wr_count <= f_dbl_wr_count + 1;
+	end
+
+	always @(*)
+		cover(S_AXI_ARESETN && (f_dbl_wr_count > 1));	//!
+
+	always @(*)
+		cover(S_AXI_ARESETN && (f_dbl_wr_count > 3));	//!
+
+	always @(*)
+		cover(S_AXI_ARESETN && (f_dbl_wr_count > 3) && !m_awvalid
+			&&(!S_AXI_AWVALID && !S_AXI_WVALID && !S_AXI_BVALID)
+			&& (f_axi_awr_nbursts == 0)
+			&& (f_axi_wr_pending == 0));	//!!
+
+	initial	f_dbl_rd_count = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_dbl_rd_count = 0;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY && S_AXI_ARLEN == 3)
+	begin
+		if (!(&f_dbl_rd_count))
+			f_dbl_rd_count <= f_dbl_rd_count + 1;
+	end
+
+	always @(*)
+		cover(!S_AXI_ARESETN && (f_dbl_rd_count > 3)
+			/* && ... */
+			&& !S_AXI_ARVALID && !S_AXI_RVALID);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Assumptions necessary to pass a formal check
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// No limiting assumptions at present, check is currently full and
+	// complete
+	//
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axil2apb.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axil2apb.v
new file mode 100644
index 0000000..2821fbf
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axil2apb.v
@@ -0,0 +1,720 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axil2apb.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	High throughput AXI-lite bridge to APB.  With both skid
+//		buffers enabled, it can handle 50% throughput--the maximum
+//	that APB can handle.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+// }}}
+module	axil2apb #(
+		// {{{
+		parameter	C_AXI_ADDR_WIDTH = 32,
+		parameter	C_AXI_DATA_WIDTH = 32,
+		// OPT_OUTGOING_SKIDBUFFER: required for 50% throughput
+		parameter [0:0]	OPT_OUTGOING_SKIDBUFFER = 1'b0,
+		localparam	AW = C_AXI_ADDR_WIDTH,
+		localparam	DW = C_AXI_DATA_WIDTH,
+		localparam	AXILLSB = $clog2(C_AXI_DATA_WIDTH)-3
+		// }}}
+	) (
+		// {{{
+		input	wire	S_AXI_ACLK,
+		input	wire	S_AXI_ARESETN,
+		//
+		// The AXI-lite interface
+		// {{{
+		input	wire				S_AXI_AWVALID,
+		output	wire				S_AXI_AWREADY,
+		input	wire [C_AXI_ADDR_WIDTH-1:0]	S_AXI_AWADDR,
+		input	wire	[2:0]			S_AXI_AWPROT,
+		//
+		input	wire				S_AXI_WVALID,
+		output	wire				S_AXI_WREADY,
+		input	wire [C_AXI_DATA_WIDTH-1 : 0]	S_AXI_WDATA,
+		input	wire [(C_AXI_DATA_WIDTH/8)-1:0]	S_AXI_WSTRB,
+		//
+		output	reg				S_AXI_BVALID,
+		input	wire				S_AXI_BREADY,
+		output	reg	[1:0]			S_AXI_BRESP,
+		//
+		input	wire				S_AXI_ARVALID,
+		output	wire				S_AXI_ARREADY,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_ARADDR,
+		input	wire	[2:0]			S_AXI_ARPROT,
+		//
+		output	reg				S_AXI_RVALID,
+		input	wire				S_AXI_RREADY,
+		output	reg	[C_AXI_DATA_WIDTH-1:0]	S_AXI_RDATA,
+		output	reg	[1:0]			S_AXI_RRESP,
+		// }}}
+		//
+		// The APB interface
+		// {{{
+		output	reg 				M_APB_PSEL,
+		output	reg 				M_APB_PENABLE,
+		input	wire				M_APB_PREADY,
+		output	reg [C_AXI_ADDR_WIDTH-1:0]	M_APB_PADDR,
+		output	reg 				M_APB_PWRITE,
+		output	reg [C_AXI_DATA_WIDTH-1:0]	M_APB_PWDATA,
+		output	reg [C_AXI_DATA_WIDTH/8-1:0]	M_APB_PWSTRB,
+		output	reg	[2:0]			M_APB_PPROT,
+		input	wire [C_AXI_DATA_WIDTH-1:0]	M_APB_PRDATA,
+		input	wire				M_APB_PSLVERR
+		// }}}
+		// }}}
+	);
+
+	// Register declarations
+	// {{{
+	wire				awskd_valid, wskd_valid, arskd_valid;
+	reg				axil_write_ready, axil_read_ready,
+					write_grant, apb_idle;
+	wire	[AW-AXILLSB-1:0]	awskd_addr, arskd_addr;
+	wire	[DW-1:0]		wskd_data;
+	wire	[DW/8-1:0]		wskd_strb;
+	wire	[2:0]			awskd_prot, arskd_prot;
+	reg	apb_bvalid, apb_rvalid, apb_error, out_skid_full;
+	reg	[DW-1:0]	apb_data;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Incoming AXI-lite write interface
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// awskd - write address skid buffer
+	// {{{
+	skidbuffer #(.DW(C_AXI_ADDR_WIDTH-AXILLSB + 3),
+		.OPT_OUTREG(0)
+	) awskd (.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_valid(S_AXI_AWVALID), .o_ready(S_AXI_AWREADY),
+		.i_data({ S_AXI_AWADDR[AW-1:AXILLSB], S_AXI_AWPROT }),
+		.o_valid(awskd_valid), .i_ready(axil_write_ready),
+		.o_data({ awskd_addr, awskd_prot }));
+	// }}}
+
+	// wskd - write data skid buffer
+	// {{{
+	skidbuffer #(.DW(DW+(DW/8)),
+		.OPT_OUTREG(0)
+	) wskd (.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_valid(S_AXI_WVALID), .o_ready(S_AXI_WREADY),
+		.i_data({ S_AXI_WDATA, S_AXI_WSTRB }),
+		.o_valid(wskd_valid), .i_ready(axil_write_ready),
+		.o_data({ wskd_data, wskd_strb }));
+	// }}}
+
+	// apb_idle
+	// {{{
+	always @(*)
+	begin
+		apb_idle = !M_APB_PSEL;// || (M_APB_PENABLE && M_APB_PREADY);
+		if (OPT_OUTGOING_SKIDBUFFER && (M_APB_PENABLE && M_APB_PREADY))
+			apb_idle = 1'b1;
+	end
+	// }}}
+
+	// axil_write_ready
+	// {{{
+	always @(*)
+	begin
+		axil_write_ready = apb_idle;
+		if (S_AXI_BVALID && !S_AXI_BREADY)
+			axil_write_ready = 1'b0;
+		if (!awskd_valid || !wskd_valid)
+			axil_write_ready = 1'b0;
+		if (!write_grant && arskd_valid)
+			axil_write_ready = 1'b0;
+	end
+	// }}}
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Incoming AXI-lite read interface
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// arskd buffer
+	// {{{
+	skidbuffer #(.DW(C_AXI_ADDR_WIDTH-AXILLSB+3),
+		.OPT_OUTREG(0)
+	) arskd (.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_valid(S_AXI_ARVALID), .o_ready(S_AXI_ARREADY),
+		.i_data({ S_AXI_ARADDR[AW-1:AXILLSB], S_AXI_ARPROT }),
+		.o_valid(arskd_valid), .i_ready(axil_read_ready),
+		.o_data({ arskd_addr, arskd_prot }));
+	// }}}
+
+	// axil_read_ready
+	// {{{
+	always @(*)
+	begin
+		axil_read_ready = apb_idle;
+		if (S_AXI_RVALID && !S_AXI_RREADY)
+			axil_read_ready = 1'b0;
+		if (write_grant && awskd_valid && wskd_valid)
+			axil_read_ready = 1'b0;
+		if (!arskd_valid)
+			axil_read_ready = 1'b0;
+	end
+	// }}}
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Arbitrate among reads and writes --- alternating arbitration
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// write_grant -- alternates
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (apb_idle)
+	begin
+		if (axil_write_ready)
+			write_grant <= 1'b0;
+		else if (axil_read_ready)
+			write_grant <= 1'b1;
+	end
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Drive the APB bus
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// APB bus
+	// {{{
+	initial	M_APB_PSEL    = 1'b0;
+	initial	M_APB_PENABLE = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	begin
+		if (apb_idle)
+		begin
+			M_APB_PSEL   <= 1'b0;
+			if (axil_read_ready)
+			begin
+				M_APB_PSEL   <= 1'b1;
+				M_APB_PADDR  <= { arskd_addr, {(AXILLSB){1'b0}} };
+				M_APB_PWRITE <= 1'b0;
+				M_APB_PPROT  <= arskd_prot;
+			end else if (axil_write_ready)
+			begin
+				M_APB_PSEL   <= 1'b1;
+				M_APB_PADDR  <= { awskd_addr, {(AXILLSB){1'b0}} };
+				M_APB_PWRITE <= 1'b1;
+				M_APB_PPROT  <= awskd_prot;
+			end
+
+			if (wskd_valid)
+			begin
+				M_APB_PWDATA <= wskd_data;
+				M_APB_PWSTRB <= wskd_strb;
+			end
+
+			M_APB_PENABLE <= 1'b0;
+		end else if (!M_APB_PENABLE)
+			M_APB_PENABLE <= 1'b1;
+		else if (M_APB_PREADY)
+		begin // if (M_APB_PSEL && M_APB_ENABLE)
+			M_APB_PENABLE <= 1'b0;
+			M_APB_PSEL <= 1'b0;
+		end
+
+		if (!S_AXI_ARESETN)
+		begin
+			M_APB_PSEL    <= 1'b0;
+			M_APB_PENABLE <= 1'b0;
+		end
+	end
+	// }}}
+
+	reg			r_apb_bvalid, r_apb_rvalid, r_apb_error;
+	reg	[DW-1:0]	r_apb_data;
+
+	generate if (OPT_OUTGOING_SKIDBUFFER)
+	begin
+		// {{{
+		// r_apb_bvalid, r_apb_rvalid, r_apb_error, r_apb_data
+		// {{{
+		initial	r_apb_bvalid = 1'b0;
+		initial	r_apb_rvalid = 1'b0;
+		always @(posedge S_AXI_ACLK)
+		begin
+			if (M_APB_PSEL && M_APB_PENABLE && M_APB_PREADY)
+			begin
+			r_apb_bvalid <= (S_AXI_BVALID && !S_AXI_BREADY) && M_APB_PWRITE;
+			r_apb_rvalid <= (S_AXI_RVALID && !S_AXI_RREADY) && !M_APB_PWRITE;
+				if (!M_APB_PWRITE)
+					r_apb_data  <= M_APB_PRDATA;
+				r_apb_error <= M_APB_PSLVERR;
+			end else begin
+				if (S_AXI_BREADY)
+					r_apb_bvalid <= 1'b0;
+				if (S_AXI_RREADY)
+					r_apb_rvalid <= 1'b0;
+			end
+
+			if (!S_AXI_ARESETN)
+			begin
+				r_apb_bvalid <= 1'b0;
+				r_apb_rvalid <= 1'b0;
+			end
+		end
+		// }}}
+
+		// apb_bvalid
+		// {{{
+		always @(*)
+			apb_bvalid = (M_APB_PSEL && M_APB_PENABLE
+				&& M_APB_PREADY && M_APB_PWRITE)|| r_apb_bvalid;
+		// }}}
+
+		// apb_bvalid
+		// {{{
+		always @(*)
+			apb_rvalid = (M_APB_PSEL && M_APB_PENABLE
+				&& M_APB_PREADY && !M_APB_PWRITE)||r_apb_rvalid;
+		// }}}
+
+		// apb_data
+		// {{{
+		always @(*)
+		if (out_skid_full)
+			apb_data = r_apb_data;
+		else
+			apb_data = M_APB_PRDATA;
+		// }}}
+
+		// apb_error
+		// {{{
+		always @(*)
+		if (out_skid_full)
+			apb_error = r_apb_error;
+		else
+			apb_error = M_APB_PSLVERR;
+		// }}}
+
+		always @(*)
+			out_skid_full = r_apb_bvalid || r_apb_rvalid;
+		// }}}
+	end else begin
+		// {{{
+		always @(*)
+			r_apb_bvalid = 1'b0;
+
+		always @(*)
+			r_apb_rvalid = 1'b0;
+
+		always @(*)
+			r_apb_error = 1'b0;
+
+		always @(*)
+			r_apb_data = 0;
+
+		always @(*)
+			apb_bvalid = M_APB_PSEL && M_APB_PENABLE
+				&& M_APB_PREADY && M_APB_PWRITE;
+		always @(*)
+			apb_rvalid = M_APB_PSEL && M_APB_PENABLE
+				&& M_APB_PREADY && !M_APB_PWRITE;
+		always @(*)
+			apb_data = M_APB_PRDATA;
+		always @(*)
+			apb_error = M_APB_PSLVERR;
+
+		always @(*)
+			out_skid_full = 1'b0;
+
+		// Verilator lint_off UNUSED
+		wire	skd_unused;
+		assign	skd_unused = &{ 1'b0, r_apb_bvalid, r_apb_rvalid,
+				r_apb_data, r_apb_error, out_skid_full };
+		// Verilator lint_on  UNUSED
+		// }}}
+	end endgenerate
+
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite write return signaling
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// BVALID
+	// {{{
+	initial	S_AXI_BVALID = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		S_AXI_BVALID <= 1'b0;
+	else if (!S_AXI_BVALID || S_AXI_BREADY)
+		S_AXI_BVALID <= apb_bvalid;
+	// }}}
+
+	// BRESP
+	// {{{
+	initial	S_AXI_BRESP  = 2'b00;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		S_AXI_BRESP  <= 2'b00;
+	else if (!S_AXI_BVALID || S_AXI_BREADY)
+		S_AXI_BRESP <= { apb_error, 1'b0 };
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite read return signaling
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+
+	// RVALID
+	// {{{
+	initial	S_AXI_RVALID = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		S_AXI_RVALID <= 1'b0;
+	else if (!S_AXI_RVALID || S_AXI_RREADY)
+		S_AXI_RVALID <= apb_rvalid;
+	// }}}
+
+	// RRESP
+	// {{{
+	initial	S_AXI_RRESP  = 2'b00;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		S_AXI_RRESP  <= 2'b00;
+	else if (!S_AXI_RVALID || S_AXI_RREADY)
+		S_AXI_RRESP <= { apb_error, 1'b0 };
+	// }}}
+
+	// RDATA
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if ((!S_AXI_RVALID || S_AXI_RREADY) && apb_rvalid)
+		S_AXI_RDATA <= apb_data;
+	// }}}
+
+	// }}}
+
+	// Make Verilator happy
+	// {{{
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, S_AXI_AWPROT, S_AXI_ARPROT,
+		S_AXI_AWADDR[AXILLSB-1:0], S_AXI_ARADDR[AXILLSB-1:0]
+		};
+	// Verilator lint_on  UNUSED
+	// }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	localparam	F_LGDEPTH = 3;
+
+	wire	[F_LGDEPTH-1:0]	faxi_rd_outstanding,
+				faxi_wr_outstanding,
+				faxi_awr_outstanding;
+	reg	f_past_valid;
+
+	initial	f_past_valid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1'b1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite interface properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	faxil_slave #(
+		// {{{
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.C_AXI_DATA_WIDTH (C_AXI_DATA_WIDTH),
+		.F_OPT_COVER_BURST(4),
+		.F_AXI_MAXWAIT(17),
+		.F_AXI_MAXDELAY(17),
+		.F_AXI_MAXRSTALL(3),
+		.F_LGDEPTH(F_LGDEPTH)
+		// }}}
+	) faxil (
+		// {{{
+		.i_clk(S_AXI_ACLK),	// System clock
+		.i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXI_AWVALID),
+		.i_axi_awready(S_AXI_AWREADY),
+		.i_axi_awaddr(S_AXI_AWADDR),
+		.i_axi_awprot(S_AXI_AWPROT),
+		.i_axi_awcache(4'h0),
+		//
+		.i_axi_wready(S_AXI_WREADY),
+		.i_axi_wdata(S_AXI_WDATA),
+		.i_axi_wstrb(S_AXI_WSTRB),
+		.i_axi_wvalid(S_AXI_WVALID),
+		//
+		.i_axi_bresp(S_AXI_BRESP),
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+		//
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+		.i_axi_araddr(S_AXI_ARADDR),
+		.i_axi_arprot(S_AXI_ARPROT),
+		.i_axi_arcache(4'h0),
+		//
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rready(S_AXI_RREADY),
+		.i_axi_rresp(S_AXI_RRESP),
+		.i_axi_rdata(S_AXI_RDATA),
+		//
+		.f_axi_rd_outstanding(faxi_rd_outstanding),
+		.f_axi_wr_outstanding(faxi_wr_outstanding),
+		.f_axi_awr_outstanding(faxi_awr_outstanding)
+		// }}}
+	);
+
+	// Correlate outstanding counters against our state
+	// {{{
+	always @(*)
+	if (S_AXI_ARESETN)
+	begin
+		assert(faxi_awr_outstanding == (S_AXI_AWREADY ? 0:1)
+				+ (r_apb_bvalid ? 1:0)
+				+ (S_AXI_BVALID ? 1:0)
+				+ ((M_APB_PSEL && M_APB_PWRITE) ? 1:0));
+
+		assert(faxi_wr_outstanding == (S_AXI_WREADY ? 0:1)
+				+ (r_apb_bvalid ? 1:0)
+				+ (S_AXI_BVALID ? 1:0)
+				+ ((M_APB_PSEL && M_APB_PWRITE) ? 1:0));
+
+		assert(faxi_rd_outstanding == (S_AXI_ARREADY ? 0:1)
+				+ (r_apb_rvalid ? 1:0)
+				+ (S_AXI_RVALID ? 1:0)
+				+ ((M_APB_PSEL && !M_APB_PWRITE) ? 1:0));
+
+		if (r_apb_bvalid)
+			assert(S_AXI_BVALID);
+		if (r_apb_rvalid)
+			assert(S_AXI_RVALID);
+	end
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// APB interface properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	fapb_master #(
+		// {{{
+		.AW(C_AXI_ADDR_WIDTH),
+		.DW(C_AXI_DATA_WIDTH),
+		.F_OPT_MAXSTALL(3)
+		// }}}
+	) fapb (
+		// {{{
+		.PCLK(S_AXI_ACLK), .PRESETn(S_AXI_ARESETN),
+		.PSEL(   M_APB_PSEL),
+		.PENABLE(M_APB_PENABLE),
+		.PREADY( M_APB_PREADY),
+		.PADDR(  M_APB_PADDR),
+		.PWRITE( M_APB_PWRITE),
+		.PWDATA( M_APB_PWDATA),
+		.PWSTRB( M_APB_PWSTRB),
+		.PPROT(  M_APB_PPROT),
+		.PRDATA( M_APB_PRDATA),
+		.PSLVERR(M_APB_PSLVERR)
+		// }}}
+	);
+
+	always @(*)
+	if (!M_APB_PSEL)
+		assert(!M_APB_PENABLE);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Induction invariants
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	always @(*)
+		assert(!axil_write_ready || !axil_read_ready);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Contract properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	(* anyconst *)	reg			f_never_test;
+	(* anyconst *)	reg	[AW-1:0]	f_never_addr;
+	(* anyconst *)	reg	[DW-1:0]	f_never_data;
+	(* anyconst *)	reg	[DW/8-1:0]	f_never_strb;
+	(* anyconst *)	reg	[2:0]		f_never_prot;
+
+	// Assume the never values are never received
+	// {{{
+	always @(*)
+	if (f_never_test)
+	begin
+		assume(f_never_addr[AXILLSB-1:0] == 0);
+
+		if (S_AXI_AWVALID)
+		begin
+			assume(S_AXI_AWADDR[AW-1:AXILLSB] != f_never_addr[AW-1:AXILLSB]);
+			assume(S_AXI_AWPROT != f_never_prot);
+		end
+
+		if (S_AXI_WVALID)
+		begin
+			assume(S_AXI_WDATA != f_never_data);
+			assume(S_AXI_WSTRB != f_never_strb);
+		end
+
+		if (S_AXI_ARVALID)
+		begin
+			assume(S_AXI_ARADDR[AW-1:AXILLSB] != f_never_addr[AW-1:AXILLSB]);
+			assume(S_AXI_ARPROT != f_never_prot);
+		end
+
+		if (M_APB_PSEL && M_APB_PENABLE && M_APB_PREADY&& !M_APB_PWRITE)
+			assume(M_APB_PRDATA != f_never_data);
+	end
+	// }}}
+
+	// Assert the never values are never in the incoming skid buffers
+	// {{{
+	always @(*)
+	if (f_never_test)
+	begin
+		if (awskd_valid)
+		begin
+			assert(awskd_addr != f_never_addr[AW-1:AXILLSB]);
+			assert(awskd_prot != f_never_prot);
+		end
+
+		if (wskd_valid)
+		begin
+			assert(wskd_data != f_never_data);
+			assert(wskd_strb != f_never_strb);
+		end
+
+		if (arskd_valid)
+		begin
+			assert(arskd_addr != f_never_addr[AW-1:AXILLSB]);
+			assert(arskd_prot != f_never_prot);
+		end
+
+		if (r_apb_rvalid)
+			assert(r_apb_data != f_never_data);
+	end
+	// }}}
+
+	// Assert the never values are never output
+	// {{{
+	always @(*)
+	if (f_never_test)
+	begin
+		if (M_APB_PSEL)
+		begin
+			assert(M_APB_PADDR != f_never_addr);
+			assert(M_APB_PPROT != f_never_prot);
+			if (M_APB_PWRITE)
+			begin
+				assert(M_APB_PWDATA != f_never_data);
+				assert(M_APB_PWSTRB != f_never_strb);
+			end
+		end
+
+		if (S_AXI_RVALID)
+			assert(S_AXI_RDATA != f_never_data);
+	end
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// None (yet)
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Careless assumptions
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// }}}
+`endif
+// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axil2axis.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axil2axis.v
new file mode 100644
index 0000000..12bf8e9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axil2axis.v
@@ -0,0 +1,880 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axil2axis
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Demonstrates a simple AXI-Lite interface to drive an AXI-Stream
+//		channel.  This can then be used to debug DSP processing.
+//
+// Registers:	This AXI-lite to AXI-Stream core supports four word-sized
+//		addresses.  Byte enables are ignored.
+//
+//   2'b00, ADDR_SINK
+//		Writes to this register will send data to the stream master,
+//		with TLAST clear.  Data goes first through a FIFO.  If the
+//		FIFO is full, the write will stall.  If it stalls OPT_TIMEOUT
+//		cycles, the write will fail and return a bus error.
+//
+//		Reads from this register will return data from the stream slave,
+//		but without consuming it.  Values read here may still be read
+//		from the ADDR_SOURCE register later.
+//
+//   2'b01, ADDR_SOURCE
+//		Writes to this register will send data downstream to the stream
+//		master as well, but this time with TLAST set.
+//
+//		Reads from this register will accept a value from the stream
+//		slave interface.  The read value contains TDATA.  TLAST is
+//		ignored in this read.  If you want access to TLAST, you can get
+//		it from the ADDR_FIFO register.
+//
+//		If there is no data to be read, the read will not and does not
+//		stall.  It will instead return a bus error.
+//
+//   2'b10, ADDR_STATS
+//		Since we can, we'll handle some statistics  here.  The top half
+//		word contains two counters: a 4-bit counter of TLAST's issued
+//		from the stream master, and a 12-bit counter of TDATA values
+//		issued.  Neither counter includes data still contained in the
+//		FIFO.  If the OPT_SOURCE option is clear, these values will
+//		always be zero.
+//
+//		The second (bottom, or least-significant) halfword contains the
+//		same regarding the stream slave.  If OPT_SINK is set, these
+//		counters count values read from the core.  If OPT_SINK is clear,
+//		so that the stream sink is not truly implemented, then TREADY
+//		will be held high and the counter will just count values coming
+//		into the core never going into the FIFO.
+//
+//   2'b11, ADDR_FIFO
+//		Working with the core can be a challenge.  You want to make
+//		certain that writing to the core  doesn't hang the design, and
+//		that reading from the core doesn't cause a bus error.
+//
+//		Bits 31:16 contain the number of items in the write FIFO, and
+//		bits 14:0 contain the number of items in the read FIFO.
+//
+//		Bit 15 contains whether or not the next item to be read is
+//		the last item in a packet, i.e. with TLAST set.
+//		
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+//
+`default_nettype none
+//
+module	axil2axis #(
+		// {{{
+		//
+		// Size of the AXI-lite bus.  These are fixed, since 1) AXI-lite
+		// is fixed at a width of 32-bits by Xilinx def'n, and 2) since
+		// we only ever have 4 configuration words.
+		parameter	C_AXI_ADDR_WIDTH = 4,
+		localparam	C_AXI_DATA_WIDTH = 32,
+		parameter	C_AXIS_DATA_WIDTH = 16,
+		//
+		// OPT_SOURCE enables the AXI stream master logic.  If not
+		// enabled, M_AXI_TVALID will be held at zero, and the stream
+		// master logic may be ignored.
+		parameter [0:0] OPT_SOURCE = 1'b1,
+		//
+		// OPT_SINK enables the AXI stream slave logic.  If not enabled,
+		// reads will always return zero, and S_AXIS_TREADY will be
+		// held high.
+		parameter [0:0] OPT_SINK = 1'b1,
+		//
+		// If OPT_SIGN_EXTEND is set, values received will be sign
+		// extended to fill the full data width on read.  Otherwise
+		// the most significant of any unused bits will remain clear.
+		parameter [0:0] OPT_SIGN_EXTEND = 1'b0,
+		//
+		// Data written to this core will be placed into a FIFO before
+		// entering the AXI stream master.  LGFIFO is the log, based
+		// two, of the number of words in this FIFO.  Similarly, data
+		// consumed by AXI stream slave contained in this core will go
+		// first into a read FIFO.  Reads from the core will then return
+		// data from this FIFO, or a bus error if none is available.
+		parameter 	LGFIFO = 5,
+		//
+		// OPT_TIMEOUT, if non-zero, will allow writes to the stream
+		// master, or reads from the stream slave, to stall the core
+		// for OPT_TIMEOUT cycles for the stream to be ready.  If the
+		// stream isn't ready at this time (i.e. if the write FIFO is
+		// still full, or the read FIFO still empty), the result will
+		// be returned as a bus error.  Likewise, if OPT_TIMEOUT==0,
+		// the core will always return a bus error if ever the write
+		// FIFO is full or the read FIFO empty.
+		parameter	OPT_TIMEOUT = 5,
+		//
+		// OPT_LOWPOWER sets outputs to zero if not valid.  This applies
+		// to the AXI-lite bus, however, and not the AXI stream FIFOs,
+		// since those don't have LOWPOWER support (currently).
+		parameter [0:0]	OPT_LOWPOWER = 0,
+		//
+		// This design currently ignores WSTRB, beyond checking that it
+		// is not zero.  I see no easy way to add it.  (I'll leave that
+		// to you to implement, if you wish.)
+		// parameter [0:0]	OPT_WSTRB = 0,
+		//
+		localparam	ADDRLSB = $clog2(C_AXI_DATA_WIDTH)-3
+		// }}}
+	) (
+		// {{{
+		input	wire					S_AXI_ACLK,
+		input	wire					S_AXI_ARESETN,
+		// AXI-lite signals
+		// {{{
+		input	wire					S_AXI_AWVALID,
+		output	wire					S_AXI_AWREADY,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]		S_AXI_AWADDR,
+		input	wire	[2:0]				S_AXI_AWPROT,
+		//
+		input	wire					S_AXI_WVALID,
+		output	wire					S_AXI_WREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]		S_AXI_WDATA,
+		input	wire	[C_AXI_DATA_WIDTH/8-1:0]	S_AXI_WSTRB,
+		//
+		output	wire					S_AXI_BVALID,
+		input	wire					S_AXI_BREADY,
+		output	wire	[1:0]				S_AXI_BRESP,
+		//
+		input	wire					S_AXI_ARVALID,
+		output	wire					S_AXI_ARREADY,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]		S_AXI_ARADDR,
+		input	wire	[2:0]				S_AXI_ARPROT,
+		//
+		output	wire					S_AXI_RVALID,
+		input	wire					S_AXI_RREADY,
+		output	wire	[C_AXI_DATA_WIDTH-1:0]		S_AXI_RDATA,
+		output	wire	[1:0]				S_AXI_RRESP,
+		// }}}
+		// AXI stream slave (sink) signals
+		// {{{
+		input	wire				S_AXIS_TVALID,
+		output	reg				S_AXIS_TREADY,
+		input	wire	[C_AXIS_DATA_WIDTH-1:0]	S_AXIS_TDATA,
+		input	wire				S_AXIS_TLAST,
+		// }}}
+		// AXI stream master (source) signals
+		// {{{
+		output	reg				M_AXIS_TVALID,
+		input	wire				M_AXIS_TREADY,
+		output	reg	[C_AXIS_DATA_WIDTH-1:0]	M_AXIS_TDATA,
+		output	reg				M_AXIS_TLAST
+		// }}}
+		// }}}
+	);
+
+	localparam	[1:0]	ADDR_SINK = 2'b00,	// Read from stream
+				ADDR_SOURCE = 2'b01, // Write, also sets TLAST
+				ADDR_STATS  = 2'b10,
+				ADDR_FIFO   = 2'b11;
+	localparam	SW = C_AXIS_DATA_WIDTH;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Register/wire signal declarations
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	wire	i_reset = !S_AXI_ARESETN;
+
+	wire				axil_write_ready;
+	wire	[C_AXI_ADDR_WIDTH-ADDRLSB-1:0]	awskd_addr;
+	//
+	wire	[C_AXI_DATA_WIDTH-1:0]	wskd_data;
+	wire [C_AXI_DATA_WIDTH/8-1:0]	wskd_strb;
+	reg				axil_bvalid, axil_berr;
+	//
+	wire				axil_read_ready;
+	wire	[C_AXI_ADDR_WIDTH-ADDRLSB-1:0]	arskd_addr;
+	reg	[C_AXI_DATA_WIDTH-1:0]	axil_read_data;
+	reg				axil_read_valid;
+
+	wire			awskd_valid, wskd_valid;
+	wire			wfifo_full, wfifo_write, wfifo_empty;
+	wire	[LGFIFO:0]	wfifo_fill;
+	reg			write_timeout;
+
+	reg			read_timeout;
+	reg			axil_rerr;
+	reg	[3:0]		read_bursts_completed;
+	reg	[11:0]		reads_completed;
+
+	reg	[3:0]	write_bursts_completed;
+	reg	[11:0]	writes_completed;
+
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite signaling
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	//
+	// Write signaling
+	//
+	// {{{
+	skidbuffer #(.OPT_OUTREG(0),
+			.OPT_LOWPOWER(OPT_LOWPOWER),
+			.DW(C_AXI_ADDR_WIDTH-ADDRLSB))
+	axilawskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXI_AWVALID), .o_ready(S_AXI_AWREADY),
+		.i_data(S_AXI_AWADDR[C_AXI_ADDR_WIDTH-1:ADDRLSB]),
+		.o_valid(awskd_valid), .i_ready(axil_write_ready),
+		.o_data(awskd_addr));
+
+	skidbuffer #(.OPT_OUTREG(0),
+			.OPT_LOWPOWER(OPT_LOWPOWER),
+			.DW(C_AXI_DATA_WIDTH+C_AXI_DATA_WIDTH/8))
+	axilwskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXI_WVALID), .o_ready(S_AXI_WREADY),
+		.i_data({ S_AXI_WDATA, S_AXI_WSTRB }),
+		.o_valid(wskd_valid), .i_ready(axil_write_ready),
+		.o_data({ wskd_data, wskd_strb }));
+
+	assign	axil_write_ready = awskd_valid && wskd_valid
+			&& (!S_AXI_BVALID || S_AXI_BREADY)
+			&& ((awskd_addr[1] != ADDR_SOURCE[1])
+				|| (!wfifo_full || write_timeout));
+
+	//
+	// Write timeout generation
+	//
+	// {{{
+	generate if ((OPT_TIMEOUT > 1) && OPT_SOURCE)
+	begin
+
+		reg [$clog2(OPT_TIMEOUT)-1:0] write_timer;
+
+		initial	write_timer = OPT_TIMEOUT-1;
+		initial	write_timeout = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+		begin
+			write_timer <= OPT_TIMEOUT-1;
+			write_timeout<= 1'b0;
+		end else if (!awskd_valid || !wfifo_full || !wskd_valid
+				|| (awskd_addr[1] != ADDR_SOURCE[1])
+				|| (S_AXI_BVALID && !S_AXI_BREADY))
+		begin
+			write_timer <= OPT_TIMEOUT-1;
+			write_timeout<= 1'b0;
+		end else begin
+			if (write_timer > 0)
+				write_timer <= write_timer - 1;
+			write_timeout <= (write_timer <= 1);
+		end
+
+`ifdef	FORMAL
+		always @(*)
+			assert(write_timer <= OPT_TIMEOUT-1);
+		always @(*)
+			assert(write_timeout == (write_timer == 0));
+`endif
+	end else begin
+
+		always @(*)
+			write_timeout<= 1'b1;
+
+	end endgenerate
+	// }}}
+	
+
+	initial	axil_bvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		axil_bvalid <= 0;
+	else if (axil_write_ready)
+		axil_bvalid <= 1;
+	else if (S_AXI_BREADY)
+		axil_bvalid <= 0;
+
+	assign	S_AXI_BVALID = axil_bvalid;
+
+	initial	axil_berr = 0;
+	always @(posedge S_AXI_ACLK)
+	if (OPT_LOWPOWER && i_reset)
+		axil_berr <= 0;
+	else if (axil_write_ready)
+		axil_berr <= (wfifo_full)&&(awskd_addr[1]==ADDR_SOURCE[1]);
+	else if (OPT_LOWPOWER && S_AXI_BREADY)
+		axil_berr <= 1'b0;
+
+	assign	S_AXI_BRESP = { axil_berr, 1'b0 };
+	// }}}
+
+	//
+	// AXI-stream source (Write) FIFO
+	//
+	// {{{
+	assign	wfifo_write = axil_write_ready && awskd_addr[1]==ADDR_SOURCE[1]
+			&& wskd_strb != 0 && !wfifo_full;
+
+	generate if (OPT_SOURCE)
+	begin
+
+		sfifo #(.BW(SW+1), .LGFLEN(LGFIFO))
+		source(.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+			.i_wr(wfifo_write),
+			.i_data({awskd_addr[0]==ADDR_SOURCE[0],
+					wskd_data[SW-1:0]}),
+			.o_full(wfifo_full), .o_fill(wfifo_fill),
+			.i_rd(M_AXIS_TREADY),
+				.o_data({ M_AXIS_TLAST, M_AXIS_TDATA }),
+				.o_empty(wfifo_empty));
+
+		always @(*)
+			M_AXIS_TVALID = !wfifo_empty;
+
+	end else begin
+
+		always @(*)
+		begin
+			M_AXIS_TVALID = 1'b0;
+			M_AXIS_TDATA  = 0;
+			M_AXIS_TLAST  = 0;
+		end
+
+		assign	wfifo_full = 1'b0;
+		assign	wfifo_fill = 0;
+
+	end endgenerate
+	// }}}
+
+	//
+	// AXI-stream consumer/sink (Read) FIFO
+	//
+	// {{{
+	wire			rfifo_empty, rfifo_full, rfifo_last, read_rfifo;
+	wire	[LGFIFO:0]	rfifo_fill;
+	wire	[SW-1:0]	rfifo_data;
+
+	generate if (OPT_SINK)
+	begin
+
+		sfifo #(.BW(SW+1), .LGFLEN(LGFIFO))
+		sink(.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+			.i_wr(S_AXIS_TVALID && S_AXIS_TREADY),
+			.i_data({S_AXIS_TLAST, S_AXIS_TDATA}),
+			.o_full(rfifo_full), .o_fill(rfifo_fill),
+			.i_rd(read_rfifo),
+				.o_data({ rfifo_last, rfifo_data }),
+				.o_empty(rfifo_empty));
+
+		always @(*)
+			S_AXIS_TREADY = !rfifo_full;
+		assign	read_rfifo =(axil_read_ready && arskd_addr== ADDR_SINK)
+				&& !rfifo_empty;
+
+	end else begin
+
+		always @(*)
+			S_AXIS_TREADY = 1'b1;
+
+		assign rfifo_empty = 1'b1;
+		assign rfifo_data  = 0;
+		assign rfifo_last  = 1'b1;
+		assign rfifo_fill  = 0;
+
+	end endgenerate
+	// }}}
+
+	//
+	// Read timeout generation
+	//
+	// {{{
+	generate if (OPT_SINK && OPT_TIMEOUT > 1)
+	begin
+		reg [$clog2(OPT_TIMEOUT)-1:0] read_timer;
+
+		initial	read_timer = OPT_TIMEOUT-1;
+		initial	read_timeout = 1'b0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+		begin
+			read_timer <= OPT_TIMEOUT-1;
+			read_timeout<= 1'b0;
+		end else if (!arskd_valid || (S_AXI_RVALID && !S_AXI_RREADY)
+				||!rfifo_empty
+				||(arskd_addr[1] != ADDR_SINK[1]))
+		begin
+			read_timer <= OPT_TIMEOUT-1;
+			read_timeout<= 1'b0;
+		end else begin
+			if (read_timer > 0)
+				read_timer <= read_timer - 1;
+			read_timeout <= (read_timer <= 1);
+		end
+
+`ifdef	FORMAL
+		always @(*)
+			assert(read_timer <= OPT_TIMEOUT-1);
+		always @(*)
+			assert(read_timeout == (read_timer == 0));
+`endif
+	end else begin
+
+		always @(*)
+			read_timeout = 1'b1;
+
+	end endgenerate
+	// }}}
+
+	//
+	// Read signaling
+	//
+	// {{{
+	wire	arskd_valid;
+
+	skidbuffer #(.OPT_OUTREG(0),
+			.OPT_LOWPOWER(OPT_LOWPOWER),
+			.DW(C_AXI_ADDR_WIDTH-ADDRLSB))
+	axilarskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXI_ARVALID), .o_ready(S_AXI_ARREADY),
+		.i_data(S_AXI_ARADDR[C_AXI_ADDR_WIDTH-1:ADDRLSB]),
+		.o_valid(arskd_valid), .i_ready(axil_read_ready),
+		.o_data(arskd_addr));
+
+	assign	axil_read_ready = arskd_valid
+			&& (!S_AXI_RVALID || S_AXI_RREADY)
+			&& ((arskd_addr[1] != ADDR_SINK[1])
+				|| (!rfifo_empty || read_timeout));
+
+	initial	axil_read_valid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		axil_read_valid <= 1'b0;
+	else if (axil_read_ready)
+		axil_read_valid <= 1'b1;
+	else if (S_AXI_RREADY)
+		axil_read_valid <= 1'b0;
+
+	assign	S_AXI_RVALID = axil_read_valid;
+
+	always @(posedge S_AXI_ACLK)
+	if (OPT_LOWPOWER && !S_AXI_ARESETN)
+		axil_rerr <= 1'b0;
+	else if (axil_read_ready)
+		axil_rerr <= rfifo_empty && (arskd_addr[1] == ADDR_SINK[1]);
+	else if (OPT_LOWPOWER && S_AXI_RREADY)
+		axil_rerr <= 1'b0;
+
+	assign	S_AXI_RRESP = { axil_rerr, 1'b0 };
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite register logic
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+
+	//
+	// Read data counting
+	// {{{
+	initial	reads_completed = 0;
+	initial	read_bursts_completed = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		reads_completed <= 0;
+		read_bursts_completed <= 0;
+	end else if (!OPT_SINK)
+	begin
+		reads_completed <= reads_completed + (S_AXIS_TVALID ? 1:0);
+		read_bursts_completed <= read_bursts_completed
+				+ ((S_AXIS_TVALID && S_AXIS_TLAST) ? 1:0);
+	end else if (read_rfifo && !rfifo_empty)
+	begin
+		reads_completed <= reads_completed + 1;
+		read_bursts_completed <= read_bursts_completed + (rfifo_last ? 1:0);
+	end
+	// }}}
+
+	//
+	// Write data counting
+	// {{{
+	generate if (OPT_SOURCE)
+	begin
+
+		initial	writes_completed = 0;
+		initial	write_bursts_completed = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+		begin
+			writes_completed <= 0;
+			write_bursts_completed <= 0;
+		end else if (M_AXIS_TVALID && M_AXIS_TREADY)
+		begin
+			writes_completed <= writes_completed + 1;
+			write_bursts_completed <= write_bursts_completed
+					+ (M_AXIS_TLAST ? 1:0);
+		end
+
+	end else begin
+
+		always @(*)
+		begin
+			writes_completed = 0;
+			write_bursts_completed = 0;
+		end
+
+	end endgenerate
+	// }}}
+
+	//
+	// Read data register
+	// {{{
+	initial	axil_read_data = 0;
+	always @(posedge S_AXI_ACLK)
+	if (OPT_LOWPOWER && !S_AXI_ARESETN)
+		axil_read_data <= 0;
+	else if (!S_AXI_RVALID || S_AXI_RREADY)
+	begin
+		axil_read_data <= 0;
+		casez(arskd_addr)
+		{ ADDR_SINK[1], 1'b? }:	begin
+			if (OPT_SIGN_EXTEND && rfifo_data[SW-1])
+				axil_read_data <= -1;
+			axil_read_data[SW-1:0] <= rfifo_data;
+			end
+		ADDR_STATS: begin
+			axil_read_data[31:28] <= write_bursts_completed;
+			axil_read_data[27:16] <= writes_completed;
+			axil_read_data[15:12] <= read_bursts_completed;
+			axil_read_data[11:0]  <= reads_completed;
+			end
+		ADDR_FIFO:	begin
+			// FIFO information
+			axil_read_data[16 +: LGFIFO+1] <= wfifo_fill;
+			axil_read_data[15] <= rfifo_last;
+			axil_read_data[LGFIFO:0] <= rfifo_fill;
+			end
+		endcase
+
+		if (OPT_LOWPOWER && !axil_read_ready)
+			axil_read_data <= 0;
+	end
+
+	assign	S_AXI_RDATA  = axil_read_data;
+	// }}}
+
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, S_AXI_AWPROT, S_AXI_ARPROT,
+			S_AXI_ARADDR[ADDRLSB-1:0],
+			S_AXI_AWADDR[ADDRLSB-1:0],
+			wskd_data[C_AXI_DATA_WIDTH-1:SW] };
+	// Verilator lint_on  UNUSED
+	// }}}
+`ifdef	FORMAL
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Formal properties used in verfiying this core
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	// {{{
+	reg	f_past_valid;
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+
+	always @(*)
+	if (!f_past_valid)
+		assume(!S_AXI_ARESETN);
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The AXI-lite control interface
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	localparam	F_AXIL_LGDEPTH = 4;
+	wire	[F_AXIL_LGDEPTH-1:0]	faxil_rd_outstanding,
+					faxil_wr_outstanding,
+					faxil_awr_outstanding;
+
+	faxil_slave #(
+		// {{{
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.F_LGDEPTH(F_AXIL_LGDEPTH),
+		.F_AXI_MAXWAIT(OPT_TIMEOUT + 2),
+		.F_AXI_MAXDELAY(OPT_TIMEOUT + 2),
+		.F_AXI_MAXRSTALL(2),
+		.F_OPT_COVER_BURST(4)
+		// }}}
+	) faxil(
+		// {{{
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXI_AWVALID),
+		.i_axi_awready(S_AXI_AWREADY),
+		.i_axi_awaddr( S_AXI_AWADDR),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot( S_AXI_AWPROT),
+		//
+		.i_axi_wvalid(S_AXI_WVALID),
+		.i_axi_wready(S_AXI_WREADY),
+		.i_axi_wdata( S_AXI_WDATA),
+		.i_axi_wstrb( S_AXI_WSTRB),
+		//
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+		.i_axi_bresp( S_AXI_BRESP),
+		//
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+		.i_axi_araddr( S_AXI_ARADDR),
+		.i_axi_arcache(4'h0),
+		.i_axi_arprot( S_AXI_ARPROT),
+		//
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rready(S_AXI_RREADY),
+		.i_axi_rdata( S_AXI_RDATA),
+		.i_axi_rresp( S_AXI_RRESP),
+		//
+		.f_axi_rd_outstanding(faxil_rd_outstanding),
+		.f_axi_wr_outstanding(faxil_wr_outstanding),
+		.f_axi_awr_outstanding(faxil_awr_outstanding)
+		// }}}
+		);
+
+	always @(*)
+	begin
+		assert(faxil_awr_outstanding== (S_AXI_BVALID ? 1:0)
+			+(S_AXI_AWREADY ? 0:1));
+
+		assert(faxil_wr_outstanding == (S_AXI_BVALID ? 1:0)
+			+(S_AXI_WREADY ? 0:1));
+
+		assert(faxil_rd_outstanding == (S_AXI_RVALID ? 1:0)
+			+(S_AXI_ARREADY ? 0:1));
+	end
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Verifying the packet counters
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	reg	[11:0]	f_reads, f_writes;
+	reg	[3:0]	f_read_pkts, f_write_pkts;
+
+	//
+	// Mirror the read counter
+	//
+	initial	f_reads      = 0;
+	initial	f_read_pkts  = 0;
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		f_reads <= 0;
+		f_read_pkts <= 0;
+	end else if (OPT_SINK && (axil_read_ready
+			&& arskd_addr == ADDR_SINK && !rfifo_empty))
+	begin
+		f_reads <= f_reads + 1;
+		f_read_pkts <= f_read_pkts + (rfifo_last ? 1:0);
+	end else if (!OPT_SINK && S_AXIS_TVALID)
+	begin
+		f_reads <= f_reads + 1;
+		f_read_pkts <= f_read_pkts + (S_AXIS_TLAST ? 1:0);
+	end
+
+	always @(*)
+		assert(f_reads == reads_completed);
+	always @(*)
+		assert(f_read_pkts == read_bursts_completed);
+
+	always @(*)
+	if (!OPT_SINK)
+		assert(S_AXIS_TREADY);
+
+	//
+	// Mirror the write counter
+	//
+	initial	f_writes     = 0;
+	initial	f_write_pkts = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		f_writes <= 0;
+		f_write_pkts <= 0;
+	end else if (OPT_SOURCE && M_AXIS_TVALID && M_AXIS_TREADY)
+	begin
+		f_writes <= f_writes + 1;
+		f_write_pkts <= f_write_pkts + (M_AXIS_TLAST ? 1:0);
+	end
+
+	always @(*)
+	if (!OPT_SOURCE)
+	begin
+		assert(f_writes == 0);
+		assert(f_write_pkts == 0);
+	end
+
+	always @(*)
+	begin
+		assert(f_writes == writes_completed);
+		assert(f_write_pkts == write_bursts_completed);
+	end
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Verify the read result
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $past(S_AXI_ARESETN && axil_read_ready))
+	begin
+		assert(S_AXI_RVALID);
+		case($past(arskd_addr))
+		ADDR_SINK: begin
+			assert(S_AXI_RDATA[SW-1:0] == $past(rfifo_data));
+			if (SW < C_AXI_DATA_WIDTH)
+			begin
+				if (OPT_SIGN_EXTEND && $past(rfifo_data[SW-1]))
+					assert(&S_AXI_RDATA[C_AXI_DATA_WIDTH-1:SW]);
+				else
+					assert(S_AXI_RDATA[C_AXI_DATA_WIDTH-1:SW] == 0);
+			end end
+		// 1: assert(S_AXI_RDATA == $past(r1));
+		ADDR_STATS: begin
+			assert(S_AXI_RRESP == 2'b00);
+			assert(S_AXI_RDATA[31:28]
+					== $past(write_bursts_completed));
+			assert(S_AXI_RDATA[27:16] == $past(writes_completed));
+
+			assert(S_AXI_RDATA[15:12]
+					== $past(read_bursts_completed));
+			assert(S_AXI_RDATA[11:0] == $past(reads_completed));
+			end
+		ADDR_FIFO: begin
+			assert(S_AXI_RRESP == 2'b00);
+			if (LGFIFO < 16)
+				assert(S_AXI_RDATA[31:16+LGFIFO+1] == 0);
+			assert(S_AXI_RDATA[16+: LGFIFO+1]==$past(wfifo_fill));
+			assert(S_AXI_RDATA[15] == $past(rfifo_last));
+			if (LGFIFO < 15)
+				assert(S_AXI_RDATA[14:LGFIFO+1] == 0);
+			assert(S_AXI_RDATA[ 0+: LGFIFO+1]==$past(rfifo_fill));
+			end
+		default: begin end
+		endcase
+	end
+
+	//
+	// Check that our low-power only logic works by verifying that anytime
+	// S_AXI_RVALID is inactive, then the outgoing data is also zero.
+	//
+	always @(*)
+	if (OPT_LOWPOWER && !S_AXI_RVALID)
+		assert(S_AXI_RDATA == 0);
+
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The AXI-stream interfaces
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	// Slave/consumer properties
+	always @(posedge S_AXI_ACLK)
+	if (!f_past_valid || !$past(S_AXI_ARESETN))
+	begin
+		assume(!S_AXIS_TVALID);
+	end else if ($past(S_AXIS_TVALID && !S_AXIS_TREADY))
+	begin
+		assume(S_AXIS_TVALID);
+		assume($stable(S_AXIS_TDATA));
+		assume($stable(S_AXIS_TLAST));
+	end
+
+	// Master/producer/source properties
+	always @(posedge S_AXI_ACLK)
+	if (!f_past_valid || !$past(S_AXI_ARESETN))
+	begin
+		assert(!M_AXIS_TVALID);
+	end else if ($past(M_AXIS_TVALID && !M_AXIS_TREADY))
+	begin
+		assert(M_AXIS_TVALID);
+		assert($stable(M_AXIS_TDATA));
+		assert($stable(M_AXIS_TLAST));
+	end
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	always @(*)
+		cover(S_AXI_ARESETN && writes_completed == 16);
+
+	always @(*)
+		cover(S_AXI_ARESETN && reads_completed == 16);
+
+	always @(*)
+		cover(S_AXI_ARESETN && writes_completed == 16
+				&& reads_completed == 16);
+
+	always @(*)
+		cover(S_AXI_BVALID && S_AXI_BRESP != 2'b00);
+
+	always @(*)
+		cover(S_AXI_RVALID && S_AXI_RRESP != 2'b00);
+
+	// }}}
+	// }}}
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axildouble.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axildouble.v
new file mode 100644
index 0000000..e5f7be2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axildouble.v
@@ -0,0 +1,740 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axildouble.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Create a special slave which can be used to reduce crossbar
+//		logic for multiple simplified slaves.  This is a companion
+//	core to the similar axilsingle core, but allowing the slave to
+//	decode the clock between multiple possible addresses.
+//
+//	To use this, the slave must follow specific (simplified AXI) rules:
+//
+//	Write interface
+//	1. The slave must guarantee that AWREADY == WREADY = 1
+//		(This core doesn't have AWREADY or WREADY inputs)
+//	2. The slave must also guarantee that BVALID == $past(AWVALID)
+//		(This core internally generates BVALID)
+//	3. The controller will guarantee that AWVALID == WVALID
+//		(You can connect AWVALID to WVALID when connecting to your core)
+//	4. The controller will also guarantee that BREADY = 1
+//		(This core doesn't have a BVALID input)
+//
+//	Read interface
+//	1. The slave must guarantee that ARREADY == 1
+//		(This core doesn't have an ARREADY input)
+//	2. The slave must also guarantee that RVALID == $past(ARVALID)
+//		(This core doesn't have an RVALID input, trusting the slave
+//			instead)
+//	3. The controller will guarantee that RREADY = 1
+//		(This core doesn't have an RREADY output)
+//
+//
+//	Why?  This simplifies slave logic.  Slaves may interact with the bus
+//	using only the logic below:
+//
+//		always @(posedge S_AXI_ACLK)
+//		if (AWVALID) case(AWADDR)
+//		R1:	slvreg_1 <= WDATA;
+//		R2:	slvreg_2 <= WDATA;
+//		R3:	slvreg_3 <= WDATA;
+//		R4:	slvreg_4 <= WDATA;
+//		endcase
+//
+//		always @(*)
+//			BRESP = 2'b00;
+//
+//		always @(posedge S_AXI_ACLK)
+//		if (ARVALID)
+//		case(ARADDR)
+//			R1: RDATA <= slvreg_1;
+//			R2: RDATA <= slvreg_2;
+//			R3: RDATA <= slvreg_3;
+//			R4: RDATA <= slvreg_4;
+//		endcase
+//
+//		always @(*)
+//			RRESP = 2'b00;
+//
+//	This core will then keep track of the more complex bus logic,
+//	simplifying both slaves and connection logic.  Slaves with the more
+//	complicated (and proper/accurate) logic, that follow the rules above,
+//	should have no problems with this additional logic.
+//
+// Performance:
+//
+//	This core can sustain one read/write per clock as long as the upstream
+//	AXI master keeps S_AXI_[BR]READY high.  If S_AXI_[BR]READY ever drops,
+//	there's some flexibility provided by the return FIFO, so the master
+//	might not notice a drop in throughput until the FIFO fills.
+//
+//	The more practical performance measure is the latency of this core.
+//	That I've measured at four clocks.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+// `ifdef	VERILATOR
+// `define	FORMAL
+// `endif
+//
+module	axildouble #(
+		parameter integer C_AXI_DATA_WIDTH = 32,
+		parameter integer C_AXI_ADDR_WIDTH = 32,
+		//
+		// NS is the number of slave interfaces
+		parameter	NS = 8,
+		//
+		//
+		parameter	[NS*AW-1:0]	SLAVE_ADDR = {
+			{ 3'b111, {(AW-3){1'b0}} },
+			{ 3'b110, {(AW-3){1'b0}} },
+			{ 3'b101, {(AW-3){1'b0}} },
+			{ 3'b100, {(AW-3){1'b0}} },
+			{ 3'b011, {(AW-3){1'b0}} },
+			{ 3'b010, {(AW-3){1'b0}} },
+			{ 4'b0001,{(AW-4){1'b0}} },
+			{ 4'b0000,{(AW-4){1'b0}} } },
+		//
+		//
+		parameter	[NS*AW-1:0]	SLAVE_MASK =
+			(NS <= 1) ? 0
+			: {	{(NS-2){ 3'b111, {(AW-3){1'b0}} }},
+				{(2){   4'b1111, {(AW-4){1'b0}} }}
+			},
+		//
+		//
+		// AW, and DW, are short-hand abbreviations used locally.
+		localparam	AW = C_AXI_ADDR_WIDTH,
+		localparam	DW = C_AXI_DATA_WIDTH,
+		//
+		// LGFLEN specifies the log (based two) of the number of
+		// transactions that may need to be held outstanding internally.
+		// If you really want high throughput, and if you expect any
+		// back pressure at all, then increase LGFLEN.  Otherwise the
+		// default value of 3 (FIFO size = 8) should be sufficient
+		// to maintain full loading
+		parameter	LGFLEN=3,
+		//
+		// If set, OPT_LOWPOWER will set all unused registers, both
+		// internal and external, to zero anytime their corresponding
+		// *VALID bit is clear
+		parameter [0:0]	OPT_LOWPOWER = 0
+	) (
+		input	wire				S_AXI_ACLK,
+		input	wire				S_AXI_ARESETN,
+		//
+		input	wire				S_AXI_AWVALID,
+		output	wire				S_AXI_AWREADY,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_AWADDR,
+		input	wire	[3-1:0]			S_AXI_AWPROT,
+		//
+		input	wire				S_AXI_WVALID,
+		output	wire				S_AXI_WREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]	S_AXI_WDATA,
+		input	wire [C_AXI_DATA_WIDTH/8-1:0]	S_AXI_WSTRB,
+		//
+		output	wire	[2-1:0]			S_AXI_BRESP,
+		output	wire				S_AXI_BVALID,
+		input	wire				S_AXI_BREADY,
+		//
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_ARADDR,
+		input	wire	[3-1:0]			S_AXI_ARPROT,
+		input	wire				S_AXI_ARVALID,
+		output	wire				S_AXI_ARREADY,
+		//
+		output	wire	[C_AXI_DATA_WIDTH-1:0]	S_AXI_RDATA,
+		output	wire	[2-1:0]			S_AXI_RRESP,
+		output	wire				S_AXI_RVALID,
+		input	wire				S_AXI_RREADY,
+		//
+		//
+		//
+		output	wire	[NS-1:0]		M_AXI_AWVALID,
+		output	wire	[AW-1:0]		M_AXI_AWADDR,
+		output	wire	[3-1:0]			M_AXI_AWPROT,
+		//
+		output	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_WDATA,
+		output	wire [C_AXI_DATA_WIDTH/8-1:0]	M_AXI_WSTRB,
+		//
+		input	wire	[NS*2-1:0]		M_AXI_BRESP,
+		//
+		output	wire	[NS-1:0]		M_AXI_ARVALID,
+		output	wire	[AW-1:0]		M_AXI_ARADDR,
+		output	wire	[3-1:0]			M_AXI_ARPROT,
+		//
+		input	wire [NS*C_AXI_DATA_WIDTH-1:0]	M_AXI_RDATA,
+		input	wire	[NS*2-1:0]		M_AXI_RRESP
+	);
+	//
+	//
+	localparam	LGNS = $clog2(NS);
+	//
+	localparam	INTERCONNECT_ERROR = 2'b11;
+	localparam	ADDR_LSBS = $clog2(DW)-3;
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write logic:
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	wire			awskid_valid, bffull, bempty, write_awskidready,
+				dcd_awvalid;
+	reg			write_bvalid, write_response;
+	reg			bfull, write_wready, write_no_index;
+	wire	[NS:0]		wdecode;
+	wire	[AW-1:0]	awskid_addr;
+	wire	[AW-1:0]	m_awaddr;
+	reg	[LGNS-1:0]	write_windex, write_bindex;
+	wire	[3-1:0]		awskid_prot, m_axi_awprot;
+	wire	[LGFLEN:0]	bfill;
+	reg	[LGFLEN:0]	write_count;
+	reg	[1:0]		write_resp;
+	integer			k;
+
+	skidbuffer #(.OPT_LOWPOWER(OPT_LOWPOWER), .OPT_OUTREG(0),
+			.DW(AW+3))
+	awskid(	.i_clk(S_AXI_ACLK),
+		.i_reset(!S_AXI_ARESETN),
+		.i_valid(S_AXI_AWVALID),
+			.o_ready(S_AXI_AWREADY),
+			.i_data({ S_AXI_AWPROT, S_AXI_AWADDR }),
+		.o_valid(awskid_valid), .i_ready(write_awskidready),
+			.o_data({ awskid_prot, awskid_addr }));
+	
+	wire		awskd_stall;
+
+	addrdecode #(.AW(AW), .DW(3), .NS(NS),
+		.SLAVE_ADDR(SLAVE_ADDR),
+		.SLAVE_MASK(SLAVE_MASK),
+		.OPT_REGISTERED(1'b1))
+	wraddr(.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_valid(awskid_valid && write_awskidready), .o_stall(awskd_stall),
+			.i_addr(awskid_addr),
+			.i_data(awskid_prot),
+		.o_valid(dcd_awvalid), .i_stall(!S_AXI_WVALID),
+			.o_decode(wdecode), .o_addr(m_awaddr),
+			.o_data(m_axi_awprot));
+
+	always @(*)
+		write_wready = dcd_awvalid;
+	assign	S_AXI_WREADY  = write_wready;
+	assign	M_AXI_AWVALID = (S_AXI_WVALID) ? wdecode[NS-1:0] : 0;
+	assign	M_AXI_AWADDR  = m_awaddr;
+	assign	M_AXI_AWPROT  = m_axi_awprot;
+	assign	M_AXI_WDATA   = S_AXI_WDATA;
+	assign	M_AXI_WSTRB   = S_AXI_WSTRB;
+	assign	write_awskidready = (S_AXI_WVALID || !S_AXI_WREADY) && !bfull;
+
+	always @(*)
+	begin
+		write_windex = 0;
+		for(k=0; k<NS; k=k+1)
+		if (wdecode[k])
+			write_windex = write_windex | k[LGNS-1:0];
+	end
+
+	always @(posedge S_AXI_ACLK)
+	begin
+		write_bindex <= write_windex;
+		write_no_index <= wdecode[NS];
+	end
+
+	initial	{ write_response, write_bvalid } = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		{ write_response, write_bvalid } <= 0;
+	else
+		{ write_response, write_bvalid }
+			<= { write_bvalid, (S_AXI_WVALID && S_AXI_WREADY) };
+
+	always @(posedge S_AXI_ACLK)
+	if (write_no_index)
+		write_resp <= INTERCONNECT_ERROR;
+	else
+		write_resp <= M_AXI_BRESP[2*write_bindex +: 2];
+
+	initial	write_count = 0;
+	initial	bfull = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		write_count <= 0;
+		bfull <= 0;
+	end else case({ (awskid_valid && write_awskidready),
+			(S_AXI_BVALID & S_AXI_BREADY) })
+	2'b01:	begin
+		write_count <= write_count - 1;
+		bfull <= 1'b0;
+		end
+	2'b10:	begin
+		write_count <= write_count + 1;
+		bfull <= (&write_count[LGFLEN-1:0]);
+		end
+	default: begin end
+	endcase
+
+`ifdef	FORMAL
+	always @(*)
+		assert(write_count <= { 1'b1, {(LGFLEN){1'b0}} });
+	always @(*)
+		assert(bfull == (write_count == { 1'b1, {(LGFLEN){1'b0}} }));
+`endif
+
+	sfifo #(.BW(2), .OPT_ASYNC_READ(0), .LGFLEN(LGFLEN))
+	bfifo ( .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_wr(write_response), .i_data(write_resp), .o_full(bffull),
+			.o_fill(bfill),
+		.i_rd(S_AXI_BVALID && S_AXI_BREADY), .o_data(S_AXI_BRESP),
+			.o_empty(bempty));
+
+`ifdef	FORMAL
+	always @(*)
+		assert(write_count == bfill
+			+ (write_response ? 1:0)
+			+ (write_bvalid ? 1:0)
+			+ (write_wready ? 1:0));
+
+`ifdef	VERIFIC
+	always @(*)
+	if (bfifo.f_first_in_fifo)
+		assert(bfifo.f_first_data != 2'b01);
+	always @(*)
+	if (bfifo.f_second_in_fifo)
+		assert(bfifo.f_second_data != 2'b01);
+	always @(*)
+	if (!bempty && (!bfifo.f_first_in_fifo
+				|| bfifo.rd_addr != bfifo.f_first_addr)
+			&&(!bfifo.f_second_in_fifo
+				|| bfifo.rd_addr != bfifo.f_second_addr))
+		assume(S_AXI_BRESP != 2'b01);
+`else
+	always @(*)
+	if (!bempty)
+		assume(S_AXI_BRESP != 2'b01);
+`endif
+`endif
+
+	assign	S_AXI_BVALID = !bempty;
+
+`ifdef	FORMAL
+	always @(*)
+		assert(!bffull || !write_bvalid);
+`endif
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read logic
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	wire				rempty, rdfull;
+	wire	[LGFLEN:0]		rfill;
+	reg	[LGNS-1:0]		read_index, last_read_index;
+	reg	[1:0]			read_resp;
+	reg	[DW-1:0]		read_rdata;
+	wire				read_rwait, arskd_stall;
+	reg				read_rvalid, read_result, read_no_index;
+	wire	[AW-1:0]		m_araddr;
+	wire	[3-1:0]			m_axi_arprot;
+	wire	[NS:0]			rdecode;
+
+	addrdecode #(.AW(AW), .DW(3), .NS(NS),
+		.SLAVE_ADDR(SLAVE_ADDR),
+		.SLAVE_MASK(SLAVE_MASK),
+		.OPT_REGISTERED(1'b1))
+	rdaddr(.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_valid(S_AXI_ARVALID && S_AXI_ARREADY), .o_stall(arskd_stall),
+			.i_addr(S_AXI_ARADDR), .i_data(S_AXI_ARPROT),
+		.o_valid(read_rwait), .i_stall(1'b0),
+			.o_decode(rdecode), .o_addr(m_araddr),
+			.o_data(m_axi_arprot));
+
+	assign	M_AXI_ARVALID = rdecode[NS-1:0];
+	assign	M_AXI_ARADDR  = m_araddr;
+	assign	M_AXI_ARPROT  = m_axi_arprot;
+
+	initial	{ read_result, read_rvalid } = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		{ read_result, read_rvalid } <= 2'b00;
+	else
+		{ read_result, read_rvalid } <= { read_rvalid, read_rwait };
+
+	always @(*)
+	begin
+		read_index = 0;
+
+		for(k=0; k<NS; k=k+1)
+		if (rdecode[k])
+			read_index = read_index | k[LGNS-1:0];
+	end
+
+	always @(posedge S_AXI_ACLK)
+		last_read_index <= read_index;
+
+	always @(posedge S_AXI_ACLK)
+		read_no_index <= rdecode[NS];
+
+	always @(posedge S_AXI_ACLK)
+		read_rdata <= M_AXI_RDATA[DW*last_read_index +: DW];
+
+	always @(posedge S_AXI_ACLK)
+	if (read_no_index)
+		read_resp <= INTERCONNECT_ERROR;
+	else
+		read_resp <= M_AXI_RRESP[2*last_read_index +: 2];
+
+	reg			read_full;
+	reg	[LGFLEN:0]	read_count;
+
+	initial	{ read_count, read_full } = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		{ read_count, read_full } <= 0;
+	else case({ S_AXI_ARVALID & S_AXI_ARREADY, S_AXI_RVALID & S_AXI_RREADY})
+	2'b10: begin
+		read_count <= read_count + 1;
+		read_full  <= &read_count[LGFLEN-1:0];
+		end
+	2'b01: begin
+		read_count <= read_count - 1;
+		read_full <= 1'b0;
+		end
+	default: begin end
+	endcase
+
+`ifdef	FORMAL
+	always @(*)
+		assert(read_count <= { 1'b1, {(LGFLEN){1'b0}} });
+	always @(*)
+		assert(read_full == (read_count == { 1'b1, {(LGFLEN){1'b0}} }));
+`endif
+	assign	S_AXI_ARREADY = !read_full;
+
+	sfifo #(.BW(DW+2), .OPT_ASYNC_READ(0), .LGFLEN(LGFLEN))
+	rfifo ( .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_wr(read_result), .i_data({ read_rdata, read_resp }),
+			.o_full(rdfull), .o_fill(rfill),
+		.i_rd(S_AXI_RVALID && S_AXI_RREADY),
+			.o_data({ S_AXI_RDATA, S_AXI_RRESP }),.o_empty(rempty));
+
+`ifdef	FORMAL
+	always @(*)
+		assert(read_count == rfill + read_result + read_rvalid + read_rwait);
+`ifdef	VERIFIC
+	always @(*)
+	if (rfifo.f_first_in_fifo)
+		assert(rfifo.f_first_data[1:0] != 2'b01);
+	always @(*)
+	if (rfifo.f_second_in_fifo)
+		assert(rfifo.f_second_data[1:0] != 2'b01);
+	always @(*)
+	if (!rempty && (!rfifo.f_first_in_fifo
+				|| rfifo.rd_addr != rfifo.f_first_addr)
+			&&(!rfifo.f_second_in_fifo
+				|| rfifo.rd_addr != rfifo.f_second_addr))
+		assume(S_AXI_RRESP != 2'b01);
+`else
+	always @(*)
+	if (!rempty)
+		assume(S_AXI_RRESP != 2'b01);
+`endif
+`endif
+
+	assign	S_AXI_RVALID = !rempty;
+
+	// verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0,
+			bffull, rdfull, bfill, rfill,
+			awskd_stall, arskd_stall };
+	// verilator lint_on  UNUSED
+`ifdef	FORMAL
+	localparam	F_LGDEPTH = LGFLEN+1;
+	reg	f_past_valid;
+	reg	[F_LGDEPTH-1:0]	count_awr_outstanding, count_wr_outstanding,
+				count_rd_outstanding;
+
+
+	wire	[(F_LGDEPTH-1):0]	f_axi_awr_outstanding,
+					f_axi_wr_outstanding,
+					f_axi_rd_outstanding;
+
+	wire	[1:0]	fm_axi_awr_outstanding [0:NS-1];
+	wire	[1:0]	fm_axi_wr_outstanding [0:NS-1];
+	wire	[1:0]	fm_axi_rd_outstanding [0:NS-1];
+
+	reg [NS-1:0]	m_axi_rvalid, m_axi_bvalid;
+
+	faxil_slave #(// .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+			.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+			// .F_OPT_NO_READS(1'b0),
+			// .F_OPT_NO_WRITES(1'b0),
+			.F_OPT_XILINX(1),
+			.F_LGDEPTH(F_LGDEPTH))
+		properties (
+		.i_clk(S_AXI_ACLK),
+		.i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXI_AWVALID),
+		.i_axi_awready(S_AXI_AWREADY),
+		.i_axi_awaddr(S_AXI_AWADDR),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot(S_AXI_AWPROT),
+		//
+		.i_axi_wvalid(S_AXI_WVALID),
+		.i_axi_wready(S_AXI_WREADY),
+		.i_axi_wdata(S_AXI_WDATA),
+		.i_axi_wstrb(S_AXI_WSTRB),
+		//
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+		.i_axi_bresp(S_AXI_BRESP),
+		//
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+		.i_axi_araddr(S_AXI_ARADDR),
+		.i_axi_arprot(S_AXI_ARPROT),
+		.i_axi_arcache(4'h0),
+		//
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rready(S_AXI_RREADY),
+		.i_axi_rdata(S_AXI_RDATA),
+		.i_axi_rresp(S_AXI_RRESP),
+		//
+		.f_axi_rd_outstanding(f_axi_rd_outstanding),
+		.f_axi_wr_outstanding(f_axi_wr_outstanding),
+		.f_axi_awr_outstanding(f_axi_awr_outstanding));
+
+	initial	f_past_valid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1'b1;
+
+	genvar	M;
+	generate for(M=0; M<NS; M=M+1)
+	begin : CONSTRAIN_SLAVE_INTERACTIONS
+
+		faxil_master #(// .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+				.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+				.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+				// .F_OPT_NO_READS(1'b0),
+				// .F_OPT_NO_WRITES(1'b0),
+				.F_OPT_NO_RESET(1'b1),
+				.F_LGDEPTH(2))
+			properties (
+			.i_clk(S_AXI_ACLK),
+			.i_axi_reset_n(S_AXI_ARESETN),
+			//
+			.i_axi_awvalid(M_AXI_AWVALID[M]),
+			.i_axi_awready(1'b1),
+			.i_axi_awaddr(M_AXI_AWADDR),
+			.i_axi_awcache(4'h0),
+			.i_axi_awprot(M_AXI_AWPROT),
+			//
+			.i_axi_wvalid(M_AXI_AWVALID[M]),
+			.i_axi_wready(1'b1),
+			.i_axi_wdata(M_AXI_WDATA[C_AXI_DATA_WIDTH-1:0]),
+			.i_axi_wstrb(M_AXI_WSTRB[C_AXI_DATA_WIDTH/8-1:0]),
+			//
+			.i_axi_bvalid(m_axi_bvalid[M]),
+			.i_axi_bready(1'b1),
+			.i_axi_bresp(M_AXI_BRESP[2*M +: 2]),
+			//
+			.i_axi_arvalid(M_AXI_ARVALID[M]),
+			.i_axi_arready(1'b1),
+			.i_axi_araddr(M_AXI_ARADDR),
+			.i_axi_arprot(M_AXI_ARPROT),
+			.i_axi_arcache(4'h0),
+			//
+			.i_axi_rdata(M_AXI_RDATA[M*C_AXI_DATA_WIDTH +: C_AXI_DATA_WIDTH]),
+			.i_axi_rresp(M_AXI_RRESP[2*M +: 2]),
+			.i_axi_rvalid(m_axi_rvalid[M]),
+			.i_axi_rready(1'b1),
+			//
+			.f_axi_rd_outstanding(fm_axi_rd_outstanding[M]),
+			.f_axi_wr_outstanding(fm_axi_wr_outstanding[M]),
+			.f_axi_awr_outstanding(fm_axi_awr_outstanding[M]));
+
+		initial	m_axi_bvalid <= 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			m_axi_bvalid[M] <= 1'b0;
+		else
+			m_axi_bvalid[M] <= M_AXI_AWVALID[M];
+
+		initial	m_axi_rvalid[M] <= 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			m_axi_rvalid[M] <= 1'b0;
+		else
+			m_axi_rvalid[M] <= M_AXI_ARVALID[M];
+
+		always @(*)
+			assert(fm_axi_awr_outstanding[M] == fm_axi_wr_outstanding[M]);
+
+		always @(*)
+			assert(fm_axi_wr_outstanding[M]== (m_axi_bvalid[M] ? 1:0));
+
+		always @(*)
+			assert(fm_axi_rd_outstanding[M]== (m_axi_rvalid[M] ? 1:0));
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Properties necessary to pass induction
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(*)
+		assert(S_AXI_WREADY == (wdecode != 0));
+`ifdef	VERIFIC
+	always @(*)
+		assert($onehot0(M_AXI_AWVALID));
+
+	always @(*)
+		assert($onehot0(m_axi_bvalid));
+
+	always @(*)
+		assert($onehot0(m_axi_rvalid));
+`endif
+	always @(*)
+	if (S_AXI_WREADY)
+		assert(M_AXI_AWPROT == 0);
+	always @(*)
+	begin
+		count_awr_outstanding = 0;
+		if (!S_AXI_AWREADY)
+			count_awr_outstanding = count_awr_outstanding + 1;
+		if (write_wready)
+			count_awr_outstanding = count_awr_outstanding + 1;
+		if (write_bvalid)
+			count_awr_outstanding = count_awr_outstanding + 1;
+		if (write_response)
+			count_awr_outstanding = count_awr_outstanding + 1;
+		count_awr_outstanding = count_awr_outstanding + bfill;
+	end
+
+	always @(*)
+	if (S_AXI_ARESETN)
+		assert(f_axi_awr_outstanding == count_awr_outstanding);
+
+	always @(*)
+	begin
+		count_wr_outstanding = 0;
+		if (write_bvalid)
+			count_wr_outstanding = count_wr_outstanding + 1;
+		if (write_response)
+			count_wr_outstanding = count_wr_outstanding + 1;
+		count_wr_outstanding = count_wr_outstanding + bfill;
+	end
+
+	always @(*)
+	if (S_AXI_ARESETN)
+		assert(f_axi_wr_outstanding == count_wr_outstanding);
+
+	//
+	//
+	//
+	always @(*)
+	begin
+		count_rd_outstanding = 0;
+		if (read_rwait)
+			count_rd_outstanding = count_rd_outstanding + 1;
+		if (read_rvalid)
+			count_rd_outstanding = count_rd_outstanding + 1;
+		if (read_result)
+			count_rd_outstanding = count_rd_outstanding + 1;
+		count_rd_outstanding = count_rd_outstanding + rfill;
+	end
+
+	always @(*)
+	if (S_AXI_ARESETN)
+		assert(f_axi_rd_outstanding == count_rd_outstanding);
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	[3:0]	cvr_arvalids, cvr_awvalids, cvr_reads, cvr_writes;
+
+	initial	cvr_awvalids = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_awvalids <= 0;
+	else if (S_AXI_AWVALID && S_AXI_AWREADY && !(&cvr_awvalids))
+		cvr_awvalids <= cvr_awvalids + 1;
+
+	initial	cvr_arvalids = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_arvalids <= 0;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY && !(&cvr_arvalids))
+		cvr_arvalids <= cvr_arvalids + 1;
+
+	initial	cvr_writes = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_writes <= 0;
+	else if (S_AXI_BVALID && S_AXI_BREADY && !(&cvr_writes))
+		cvr_writes <= cvr_writes + 1;
+
+	initial	cvr_reads = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_reads <= 0;
+	else if (S_AXI_RVALID && S_AXI_RREADY && !(&cvr_arvalids))
+		cvr_reads <= cvr_reads + 1;
+
+	always @(*)
+		cover(cvr_awvalids > 4);
+
+	always @(*)
+		cover(cvr_arvalids > 4);
+
+	always @(*)
+		cover(cvr_reads > 4);
+
+	always @(*)
+		cover(cvr_writes > 4);
+
+	always @(*)
+		cover((cvr_writes > 4) && (cvr_reads > 4));
+`endif
+endmodule
+// `ifndef	YOSYS
+// `default_nettype wire
+// `endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axilempty.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilempty.v
new file mode 100644
index 0000000..c5f8621
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilempty.v
@@ -0,0 +1,356 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axilempty.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Modifies the simple AXI-lite interface to be an empty shell
+//
+//	This is useful for a bus with masters but no slaves.  When used,
+//	the interconnect can connect those masters to this slave to know
+//	that requests will still be properly handled--and get proper error
+//	returns.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+//
+`default_nettype none
+//
+module	axilempty #(
+		// {{{
+		//
+		// Size of the AXI-lite bus.  These are fixed, since 1) AXI-lite
+		// is fixed at a width of 32-bits by Xilinx def'n, and 2) since
+		// we only ever have 4 configuration words.
+		parameter	C_AXI_ADDR_WIDTH = 4,
+		localparam	C_AXI_DATA_WIDTH = 32,
+		parameter [0:0]	OPT_SKIDBUFFER = 1'b0,
+		parameter [0:0]	OPT_LOWPOWER = 0,
+		localparam	ADDRLSB = $clog2(C_AXI_DATA_WIDTH)-3
+		// }}}
+	) (
+		// {{{
+		input	wire					S_AXI_ACLK,
+		input	wire					S_AXI_ARESETN,
+		//
+		input	wire					S_AXI_AWVALID,
+		output	wire					S_AXI_AWREADY,
+		//
+		input	wire					S_AXI_WVALID,
+		output	wire					S_AXI_WREADY,
+		//
+		output	wire					S_AXI_BVALID,
+		input	wire					S_AXI_BREADY,
+		output	wire	[1:0]				S_AXI_BRESP,
+		//
+		input	wire					S_AXI_ARVALID,
+		output	wire					S_AXI_ARREADY,
+		//
+		output	wire					S_AXI_RVALID,
+		input	wire					S_AXI_RREADY,
+		output	wire	[C_AXI_DATA_WIDTH-1:0]		S_AXI_RDATA,
+		output	wire	[1:0]				S_AXI_RRESP
+		// }}}
+	);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Register/wire signal declarations
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	wire	i_reset = !S_AXI_ARESETN;
+
+	wire				axil_write_ready;
+	//
+	reg				axil_bvalid;
+	//
+	wire				axil_read_ready;
+	reg				axil_read_valid;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite signaling
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	//
+	// Write signaling
+	//
+	// {{{
+
+	generate if (OPT_SKIDBUFFER)
+	begin : SKIDBUFFER_WRITE
+
+		wire	awskd_valid, wskd_valid, awskd_unused, wskd_unused;
+
+		skidbuffer #(.OPT_OUTREG(0),
+				.OPT_LOWPOWER(OPT_LOWPOWER), .DW(1))
+		axilawskid(//
+			.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+			.i_valid(S_AXI_AWVALID), .o_ready(S_AXI_AWREADY),
+			.i_data(1'b0),
+			.o_valid(awskd_valid), .i_ready(axil_write_ready),
+			.o_data(awskd_unused));
+
+		skidbuffer #(.OPT_OUTREG(0), .OPT_LOWPOWER(OPT_LOWPOWER),
+				.DW(1))
+		axilwskid(//
+			.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+			.i_valid(S_AXI_WVALID), .o_ready(S_AXI_WREADY),
+			.i_data({ 1'b0 }),
+			.o_valid(wskd_valid), .i_ready(axil_write_ready),
+			.o_data(wskd_unused));
+
+		assign	axil_write_ready = awskd_valid && wskd_valid
+				&& (!S_AXI_BVALID || S_AXI_BREADY);
+
+		// Verilator lint_off UNUSED
+		wire	unused;
+		assign	unused = &{ 1'b0, awskd_unused, wskd_unused };
+		// Verilator lint_on  UNUSED
+	end else begin : SIMPLE_WRITES
+
+		reg	axil_awready;
+
+		initial	axil_awready = 1'b0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			axil_awready <= 1'b0;
+		else
+			axil_awready <= !axil_awready
+				&& (S_AXI_AWVALID && S_AXI_WVALID)
+				&& (!S_AXI_BVALID || S_AXI_BREADY);
+
+		assign	S_AXI_AWREADY = axil_awready;
+		assign	S_AXI_WREADY  = axil_awready;
+
+		assign	axil_write_ready = axil_awready;
+
+	end endgenerate
+
+	initial	axil_bvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		axil_bvalid <= 0;
+	else if (axil_write_ready)
+		axil_bvalid <= 1;
+	else if (S_AXI_BREADY)
+		axil_bvalid <= 0;
+
+	assign	S_AXI_BVALID = axil_bvalid;
+	assign	S_AXI_BRESP = 2'b11;
+	// }}}
+
+	//
+	// Read signaling
+	//
+	// {{{
+
+	generate if (OPT_SKIDBUFFER)
+	begin : SKIDBUFFER_READ
+
+		wire	arskd_valid, arskd_unused;
+
+		skidbuffer #(.OPT_OUTREG(0),
+				.OPT_LOWPOWER(OPT_LOWPOWER),
+				.DW(C_AXI_ADDR_WIDTH-ADDRLSB))
+		axilarskid(//
+			.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+			.i_valid(S_AXI_ARVALID), .o_ready(S_AXI_ARREADY),
+			.i_data( 1'b0 ),
+			.o_valid(arskd_valid), .i_ready(axil_read_ready),
+			.o_data(arskd_unused));
+
+		assign	axil_read_ready = arskd_valid
+				&& (!axil_read_valid || S_AXI_RREADY);
+
+		// Verilator lint_off UNUSED
+		wire	unused;
+		assign	unused = &{ 1'b0, arskd_unused };
+		// Verilator lint_on  UNUSED
+	end else begin : SIMPLE_READS
+
+		reg	axil_arready;
+
+		always @(*)
+			axil_arready = !S_AXI_RVALID;
+
+		assign	S_AXI_ARREADY = axil_arready;
+		assign	axil_read_ready = (S_AXI_ARVALID && S_AXI_ARREADY);
+
+	end endgenerate
+
+	initial	axil_read_valid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		axil_read_valid <= 1'b0;
+	else if (axil_read_ready)
+		axil_read_valid <= 1'b1;
+	else if (S_AXI_RREADY)
+		axil_read_valid <= 1'b0;
+
+	assign	S_AXI_RVALID = axil_read_valid;
+	assign	S_AXI_RDATA  = 0;
+	assign	S_AXI_RRESP = 2'b11;
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite register logic
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+
+	// }}}
+
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0 };
+	// Verilator lint_on  UNUSED
+	// }}}
+`ifdef	FORMAL
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Formal properties used in verfiying this core
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	reg	f_past_valid;
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The AXI-lite control interface
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	localparam	F_AXIL_LGDEPTH = 4;
+	wire	[F_AXIL_LGDEPTH-1:0]	faxil_rd_outstanding,
+					faxil_wr_outstanding,
+					faxil_awr_outstanding;
+
+	faxil_slave #(
+		// {{{
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.F_LGDEPTH(F_AXIL_LGDEPTH),
+		.F_AXI_MAXWAIT(2),
+		.F_AXI_MAXDELAY(2),
+		.F_AXI_MAXRSTALL(3),
+		.F_OPT_COVER_BURST(0)
+		// }}}
+	) faxil(
+		// {{{
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXI_AWVALID),
+		.i_axi_awready(S_AXI_AWREADY),
+		.i_axi_awaddr({(C_AXI_ADDR_WIDTH){1'b0}}),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot( 3'h0),
+		//
+		.i_axi_wvalid(S_AXI_WVALID),
+		.i_axi_wready(S_AXI_WREADY),
+		.i_axi_wdata( {(C_AXI_DATA_WIDTH){1'b0}}),
+		.i_axi_wstrb( {(C_AXI_DATA_WIDTH/8){1'b0}}),
+		//
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+		.i_axi_bresp( S_AXI_BRESP),
+		//
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+		.i_axi_araddr( {(C_AXI_ADDR_WIDTH){1'b0}}),
+		.i_axi_arcache(4'h0),
+		.i_axi_arprot( 3'h0),
+		//
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rready(S_AXI_RREADY),
+		.i_axi_rdata( S_AXI_RDATA),
+		.i_axi_rresp( S_AXI_RRESP),
+		//
+		.f_axi_rd_outstanding(faxil_rd_outstanding),
+		.f_axi_wr_outstanding(faxil_wr_outstanding),
+		.f_axi_awr_outstanding(faxil_awr_outstanding)
+		// }}}
+		);
+
+	always @(*)
+	if (OPT_SKIDBUFFER)
+	begin
+		assert(faxil_awr_outstanding== (S_AXI_BVALID ? 1:0)
+			+(S_AXI_AWREADY ? 0:1));
+		assert(faxil_wr_outstanding == (S_AXI_BVALID ? 1:0)
+			+(S_AXI_WREADY ? 0:1));
+
+		assert(faxil_rd_outstanding == (S_AXI_RVALID ? 1:0)
+			+(S_AXI_ARREADY ? 0:1));
+	end else begin
+		assert(faxil_wr_outstanding == (S_AXI_BVALID ? 1:0));
+		assert(faxil_awr_outstanding == faxil_wr_outstanding);
+
+		assert(faxil_rd_outstanding == (S_AXI_RVALID ? 1:0));
+	end
+
+	//
+	// Check that our low-power only logic works by verifying that anytime
+	// S_AXI_RVALID is inactive, then the outgoing data is also zero.
+	//
+	always @(*)
+		assert(S_AXI_RDATA == 0);
+	always @(*)
+		assert(S_AXI_RRESP == 2'b11);
+	always @(*)
+		assert(S_AXI_BRESP == 2'b11);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	// While there are already cover properties in the formal property
+	// set above, you'll probably still want to cover something
+	// application specific here
+
+	// }}}
+	// }}}
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axilfetch.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilfetch.v
new file mode 100644
index 0000000..942ea08
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilfetch.v
@@ -0,0 +1,377 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	This is a very simple instruction fetch approach based around
+//		AXI-lite.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+//
+//
+`default_nettype	none
+//
+//
+module	axilfetch #(
+	parameter	C_AXI_ADDR_WIDTH = 32,
+	parameter	C_AXI_DATA_WIDTH = 64,
+	parameter	DATA_WIDTH=32,
+	parameter	FETCH_LIMIT=16,
+	parameter [0:0]	SWAP_ENDIANNESS = 1'b1,
+	localparam	AW=C_AXI_ADDR_WIDTH,
+	localparam	DW=DATA_WIDTH,
+	localparam	AXILLSB = $clog2(C_AXI_DATA_WIDTH/8),
+	localparam	INSNS_PER_WORD = C_AXI_DATA_WIDTH / DATA_WIDTH
+	) (
+	input	wire		S_AXI_ACLK,
+	input	wire		S_AXI_ARESETN,
+	//
+	// CPU interaction wires
+	input	wire		i_cpu_reset,
+	input	wire		i_new_pc,
+	input	wire		i_clear_cache,
+	input	wire		i_ready,
+	input	wire [AW-1:0]	i_pc,	// Ignored unless i_new_pc as well
+	output	reg [DATA_WIDTH-1:0]	o_insn,	// Instruction read from bus
+	output	reg [AW-1:0]	o_pc,	// Address of that instruction
+	output	reg		o_valid,	// If the output is valid
+	output	reg		o_illegal,	// Result is from a bus error
+	//
+	output	reg				M_AXI_ARVALID,
+	input	wire				M_AXI_ARREADY,
+	output	reg [C_AXI_ADDR_WIDTH-1:0]	M_AXI_ARADDR,
+	output	reg [2:0]			M_AXI_ARPROT,
+	//
+	input	reg				M_AXI_RVALID,
+	output	reg				M_AXI_RREADY,
+	input	reg [C_AXI_DATA_WIDTH-1:0]	M_AXI_RDATA,
+	input	reg [1:0]			M_AXI_RRESP
+	);
+
+	localparam	LGDEPTH = $clog2(FETCH_LIMIT)+4;
+	localparam	LGFIFO = $clog2(FETCH_LIMIT);
+	localparam	W = LGDEPTH;
+	localparam	FILLBITS = $clog2(INSNS_PER_WORD);
+			// ($clog2(INSNS_PER_WORD) > 0)
+			//			? $clog2(INSNS_PER_WORD) : 1);
+
+	reg	[W:0]			new_flushcount, outstanding,
+					next_outstanding, flushcount;
+	reg				flushing, flush_request, full_bus;
+	reg	[((AXILLSB>2)?(AXILLSB-3):0):0]	shift;
+	wire				fifo_reset, fifo_wr, fifo_rd;
+	wire				ign_fifo_full, fifo_empty;
+	wire	[LGFIFO:0]		ign_fifo_fill;
+	wire	[C_AXI_DATA_WIDTH:0]	fifo_data;
+	reg				pending_new_pc;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	pending_pc;
+	reg	[W-1:0]			fill;
+	reg [FILLBITS:0]	out_fill;
+	reg	[C_AXI_DATA_WIDTH-1:0]	out_data;
+	reg	[C_AXI_DATA_WIDTH-1:0]	endian_swapped_rdata;
+
+
+	assign	fifo_reset = i_cpu_reset || i_clear_cache || i_new_pc;
+	assign	fifo_wr = M_AXI_RVALID && !flushing;
+
+
+	// ARPROT = 3'b100 for an unprivileged, secure instruction access
+	// (not sure what unprivileged or secure mean--even after reading the
+	//  spec)
+	always @(*)
+		M_AXI_ARPROT = 3'b100;
+
+	always @(*)
+	begin
+		next_outstanding = outstanding;
+
+		case({ M_AXI_ARVALID && M_AXI_ARREADY, M_AXI_RVALID })
+		2'b10: next_outstanding = outstanding + 1;
+		2'b01: next_outstanding = outstanding - 1;
+		default: begin end
+		endcase
+	end
+
+	initial	outstanding = 0;
+	initial	full_bus    = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		outstanding <= 0;
+		full_bus <= 0;
+	end else begin
+		outstanding <= next_outstanding;
+		full_bus <= (next_outstanding
+			// + (((M_AXI_ARVALID && !M_AXI_ARREADY) ? 1:0)
+						>= (1<<LGDEPTH)-1);
+	end
+
+	initial	fill = 0;
+	always @(posedge S_AXI_ACLK)
+	if (fifo_reset)
+		fill <= 0;
+	// else if (fo_reset || flushing)
+	//	fill <= 0;
+	else case({ M_AXI_ARVALID && M_AXI_ARREADY && !flush_request,
+				fifo_rd && !fifo_empty })
+	2'b10: fill <= fill + 1;
+	2'b01: fill <= fill - 1;
+	default: begin end
+	endcase
+
+	always @(*)
+		new_flushcount = outstanding + (M_AXI_ARVALID ? 1:0)
+				- (M_AXI_RVALID ? 1:0);
+
+	initial	flushcount = 0;
+	initial	flushing   = 0;
+	initial	flush_request = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		flushcount <= 0;
+		flushing   <= 0;
+		flush_request <= 0;
+	end else if (fifo_reset)
+	begin
+		flushcount <= new_flushcount;
+		flushing   <= (new_flushcount > 0);
+		flush_request <= (M_AXI_ARVALID && !M_AXI_ARREADY);
+	end else begin
+		if (M_AXI_RVALID && flushcount > 0)
+		begin
+			flushcount <= flushcount - 1;
+			// Verilator lint_off CMPCONST
+			flushing   <= (flushcount > 1);
+			// Verilator lint_on  CMPCONST
+		end
+
+		if (M_AXI_ARREADY)
+			flush_request <= 0;
+	end
+
+	initial	M_AXI_ARVALID = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		M_AXI_ARVALID <= 1'b0;
+	else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+	begin
+		M_AXI_ARVALID <= 1;
+		if (i_new_pc || pending_new_pc)
+			M_AXI_ARVALID <= 1'b1;
+
+		//
+		// Throttle the number of requests we make
+		if (fill + (M_AXI_ARVALID ? 1:0)
+				+ ((o_valid &&(!i_ready || out_fill > 1)) ? 1:0)
+				>= FETCH_LIMIT)
+			M_AXI_ARVALID <= 1'b0;
+		if (i_cpu_reset || i_clear_cache || full_bus)
+			M_AXI_ARVALID <= 1'b0;
+	end
+
+	always @(*)
+		M_AXI_RREADY = 1'b1;
+
+	initial	pending_new_pc = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || i_clear_cache)
+		pending_new_pc <= 1'b0;
+	else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+		pending_new_pc <= 1'b0;
+	else if (i_new_pc)
+		pending_new_pc <= 1'b1;
+
+	initial	pending_pc = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_new_pc)
+		pending_pc <= i_pc;
+
+	always @(posedge S_AXI_ACLK)
+	if (!M_AXI_ARVALID || M_AXI_ARREADY)
+	begin
+		if (i_new_pc)
+			M_AXI_ARADDR <= i_pc;
+		else if (pending_new_pc)
+			M_AXI_ARADDR <= pending_pc;
+		else if (M_AXI_ARVALID)
+		begin
+			M_AXI_ARADDR[C_AXI_ADDR_WIDTH-1:AXILLSB]
+				<= M_AXI_ARADDR[C_AXI_ADDR_WIDTH-1:AXILLSB] +1;
+			M_AXI_ARADDR[AXILLSB-1:0] <= 0;
+		end
+	end
+
+	initial	o_pc = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_new_pc)
+		o_pc <= i_pc;
+	else if (o_valid && i_ready && !o_illegal)
+	begin
+		o_pc[AW-1:2] <= o_pc[AW-1:2] + 1;
+		o_pc[1:0] <= 2'b00;
+	end
+
+	generate if (AXILLSB > 2)
+	begin : BIG_WORD
+
+		always @(*)
+		begin
+			shift = o_pc[AXILLSB-1:2];
+
+			if (FETCH_LIMIT > 0 && o_valid)
+				shift = 0;
+		end
+
+	end else begin : NO_SHIFT
+
+		always @(*)
+			shift = 0;
+
+	end endgenerate
+
+	generate if (SWAP_ENDIANNESS)
+	begin : SWAPPED_ENDIANNESS
+		genvar	gw, gb;	// Word count, byte count
+
+		for(gw=0; gw<C_AXI_DATA_WIDTH/32; gw=gw+1) // For each bus word
+		for(gb=0; gb<4; gb=gb+1) // For each bus byte
+		always @(*)
+			endian_swapped_rdata[gw*32+(3-gb)*8 +: 8]
+				= M_AXI_RDATA[gw*32+gb*8 +: 8];
+
+	end else begin : NO_ENDIAN_SWAP
+
+		always @(*)
+			endian_swapped_rdata = M_AXI_RDATA;
+
+	end endgenerate
+
+	generate if (FETCH_LIMIT <= 1)
+	begin : NOCACHE
+		// No cache
+
+		// assign	fifo_rd    = fifo_wr;
+		assign	fifo_rd = !o_valid || (i_ready && (out_fill <= 1));
+		assign	fifo_empty = !fifo_wr; //(out_fill <= (i_aready ? 1:0));
+		assign	fifo_data  = { M_AXI_RRESP[1], endian_swapped_rdata };
+
+		assign	ign_fifo_fill = 1'b0;
+		assign	ign_fifo_full = 1'b0;
+`ifdef	FORMAL
+		always @(*)
+		if (M_AXI_RVALID || M_AXI_ARVALID || outstanding > 0)
+			assert(!o_valid);
+`endif	
+	end else if (FETCH_LIMIT == 2)
+	begin : DBLFETCH
+		// Single word cache
+		reg				cache_valid;
+		reg	[C_AXI_DATA_WIDTH:0]	cache_data;
+
+		assign	fifo_rd = !o_valid || (i_ready && (out_fill <= 1));
+		assign	fifo_empty =(!M_AXI_RVALID && !cache_valid) || flushing;
+		assign	fifo_data = cache_valid ? cache_data
+					: ({ M_AXI_RRESP[1], endian_swapped_rdata });
+
+
+		assign	ign_fifo_fill = cache_valid ? 1 : 0;
+		assign	ign_fifo_full = cache_valid;
+
+		initial	cache_valid = 1'b0;
+		always @(posedge S_AXI_ACLK)
+		if (fifo_reset)
+			cache_valid <= 1'b0;
+		else if (fifo_wr && o_valid && !fifo_rd)
+			cache_valid <= 1;
+		else if (fifo_rd)
+			cache_valid <= 1'b0;
+
+		always @(posedge S_AXI_ACLK)
+		if (M_AXI_RVALID)
+			cache_data <= { M_AXI_RRESP[1], endian_swapped_rdata };
+
+	end else begin : FIFO_FETCH
+		// FIFO cache
+
+		assign	fifo_rd = !o_valid || (i_ready && (out_fill <= 1));
+
+		sfifo #(.BW(1+C_AXI_DATA_WIDTH), .LGFLEN(LGFIFO))
+		fcache(.i_clk(S_AXI_ACLK), .i_reset(fifo_reset),
+			.i_wr(fifo_wr),
+			.i_data({M_AXI_RRESP[1], endian_swapped_rdata }),
+			.o_full(ign_fifo_full), .o_fill(ign_fifo_fill),
+			.i_rd(fifo_rd),.o_data(fifo_data),.o_empty(fifo_empty));
+
+	end endgenerate
+
+	initial	o_valid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (fifo_reset)
+		o_valid <= 1'b0;
+	else if (!o_valid || i_ready)
+		o_valid <= (fifo_rd && !fifo_empty)
+			|| out_fill > (o_valid ? 1:0);
+
+	initial	out_fill = 0;
+	always @(posedge S_AXI_ARESETN)
+	if (fifo_reset)
+		out_fill <= 0;
+	else if (fifo_rd)
+		// Verilator lint_off WIDTH
+		out_fill <= (fifo_empty) ? 0: (INSNS_PER_WORD - shift);
+		// Verilator lint_on  WIDTH
+	else if (i_ready && out_fill > 0)
+		out_fill <= out_fill - 1;
+
+	always @(posedge S_AXI_ARESETN)
+	if (fifo_rd)
+		out_data <= fifo_data[C_AXI_DATA_WIDTH-1:0]>>(DATA_WIDTH*shift);
+	else if (i_ready)
+		out_data <= out_data >> DATA_WIDTH;
+
+	always @(*)
+		o_insn = out_data[DATA_WIDTH-1:0];
+
+	initial	o_illegal = 1'b0;
+	always @(posedge S_AXI_ARESETN)
+	if (fifo_reset)
+		o_illegal <= 1'b0;
+	else if (!o_illegal && fifo_rd && !fifo_empty)
+		o_illegal <= fifo_data[C_AXI_DATA_WIDTH];
+	
+	// Make verilator happy
+	// verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = & { 1'b0, M_AXI_RRESP[0], ign_fifo_full, ign_fifo_fill };
+	// verilator lint_on  UNUSED
+
+
+`ifdef	FORMAL
+	// Formal properties for this module are maintained elsewhere
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axilite2axi.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilite2axi.v
new file mode 100644
index 0000000..f040375
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilite2axi.v
@@ -0,0 +1,368 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axilite2axi.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+module axilite2axi #(
+	parameter	C_AXI_ID_WIDTH	= 4,
+			C_AXI_ADDR_WIDTH= 32,
+			C_AXI_DATA_WIDTH= 32,
+	parameter [C_AXI_ID_WIDTH-1:0]	C_AXI_WRITE_ID = 0,
+					C_AXI_READ_ID = 0,
+	localparam	ADDRLSB = $clog2(C_AXI_DATA_WIDTH)-3
+	) (
+	input	wire				ACLK,
+	input	wire				ARESETN,
+	// Slave write signals
+	input	wire				S_AXI_AWVALID,
+	output	wire				S_AXI_AWREADY,
+	input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_AWADDR,
+	input	wire	[3-1:0]			S_AXI_AWPROT,
+	// Slave write data signals
+	input	wire				S_AXI_WVALID,
+	output	wire				S_AXI_WREADY,
+	input	wire	[C_AXI_DATA_WIDTH-1:0]	S_AXI_WDATA,
+	input	wire	[C_AXI_DATA_WIDTH/8-1:0] S_AXI_WSTRB,
+	// Slave return write response
+	output	wire				S_AXI_BVALID,
+	input	wire				S_AXI_BREADY,
+	output	wire	[2-1:0]			S_AXI_BRESP,
+	// Slave read signals
+	input	wire				S_AXI_ARVALID,
+	output	wire				S_AXI_ARREADY,
+	input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_ARADDR,
+	input	wire	[3-1:0]			S_AXI_ARPROT,
+	// Slave read data signals
+	output	wire				S_AXI_RVALID,
+	input	wire				S_AXI_RREADY,
+	output	wire	[C_AXI_DATA_WIDTH-1:0]	S_AXI_RDATA,
+	output	wire	[2-1:0]			S_AXI_RRESP,
+	//
+	// Master interface write address
+	output	wire				M_AXI_AWVALID,
+	input	wire				M_AXI_AWREADY,
+	output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_AWID,
+	output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_AWADDR,
+	output	wire	[8-1:0]			M_AXI_AWLEN,
+	output	wire	[3-1:0]			M_AXI_AWSIZE,
+	output	wire	[2-1:0]			M_AXI_AWBURST,
+	output	wire				M_AXI_AWLOCK,
+	output	wire	[4-1:0]			M_AXI_AWCACHE,
+	output	wire	[3-1:0]			M_AXI_AWPROT,
+	output	wire	[4-1:0]			M_AXI_AWQOS,
+	// Master write data
+	output	wire				M_AXI_WVALID,
+	input	wire				M_AXI_WREADY,
+	output	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_WDATA,
+	output	wire	[C_AXI_DATA_WIDTH/8-1:0] M_AXI_WSTRB,
+	output	wire				M_AXI_WLAST,
+	// Master write response
+	input	wire				M_AXI_BVALID,
+	output	wire				M_AXI_BREADY,
+	input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_BID,
+	input	wire	[1:0]			M_AXI_BRESP,
+	// Master interface read address
+	output	wire				M_AXI_ARVALID,
+	input	wire				M_AXI_ARREADY,
+	output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_ARID,
+	output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_ARADDR,
+	output	wire	[8-1:0]			M_AXI_ARLEN,
+	output	wire	[3-1:0]			M_AXI_ARSIZE,
+	output	wire	[2-1:0]			M_AXI_ARBURST,
+	output	wire				M_AXI_ARLOCK,
+	output	wire	[4-1:0]			M_AXI_ARCACHE,
+	output	wire	[3-1:0]			M_AXI_ARPROT,
+	output	wire	[4-1:0]			M_AXI_ARQOS,
+	// Master interface read data return
+	input	wire				M_AXI_RVALID,
+	output	wire				M_AXI_RREADY,
+	input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_RID,
+	input	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_RDATA,
+	input	wire				M_AXI_RLAST,
+	input	wire	[2-1:0]			M_AXI_RRESP
+	);
+
+	assign	M_AXI_AWID    = C_AXI_WRITE_ID;
+	assign	M_AXI_AWADDR  = S_AXI_AWADDR;
+	assign	M_AXI_AWLEN   = 0;
+	assign	M_AXI_AWSIZE  = ADDRLSB[2:0];
+	assign	M_AXI_AWBURST = 0;
+	assign	M_AXI_AWLOCK  = 0;
+	assign	M_AXI_AWCACHE = 4'b0011; // As recommended by Xilinx UG1037
+	assign	M_AXI_AWPROT  = S_AXI_AWPROT;
+	assign	M_AXI_AWQOS   = 0;
+	assign	M_AXI_AWVALID = S_AXI_AWVALID;
+	assign	S_AXI_AWREADY = M_AXI_AWREADY;
+	// Master write data
+	assign	M_AXI_WDATA   = S_AXI_WDATA;
+	assign	M_AXI_WLAST   = 1;
+	assign	M_AXI_WSTRB   = S_AXI_WSTRB;
+	assign	M_AXI_WVALID  = S_AXI_WVALID;
+	assign	S_AXI_WREADY  = M_AXI_WREADY;
+	// Master write response
+	assign	S_AXI_BRESP   = M_AXI_BRESP;
+	assign	S_AXI_BVALID  = M_AXI_BVALID;
+	assign	M_AXI_BREADY  = S_AXI_BREADY;
+	//
+	//
+	assign	M_AXI_ARID    = C_AXI_READ_ID;
+	assign	M_AXI_ARADDR  = S_AXI_ARADDR;
+	assign	M_AXI_ARLEN   = 0;
+	assign	M_AXI_ARSIZE  = ADDRLSB[2:0];
+	assign	M_AXI_ARBURST = 0;
+	assign	M_AXI_ARLOCK  = 0;
+	assign	M_AXI_ARCACHE = 4'b0011; // As recommended by Xilinx UG1037
+	assign	M_AXI_ARPROT  = S_AXI_ARPROT;
+	assign	M_AXI_ARQOS   = 0;
+	assign	M_AXI_ARVALID = S_AXI_ARVALID;
+	assign	S_AXI_ARREADY = M_AXI_ARREADY;
+	//
+	assign	S_AXI_RDATA   = M_AXI_RDATA;
+	assign	S_AXI_RRESP   = M_AXI_RRESP;
+	assign	S_AXI_RVALID  = M_AXI_RVALID;
+	assign	M_AXI_RREADY  = S_AXI_RREADY;
+
+	// Make Verilator happy
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, ACLK, ARESETN, M_AXI_RLAST, M_AXI_RID, M_AXI_BID };
+	// Verilator lint_on UNUSED
+
+`ifdef	FORMAL
+	//
+	// The following are some of the properties used to verify this design
+	//
+
+	localparam	F_LGDEPTH = 10;
+
+	wire	[F_LGDEPTH-1:0]	faxil_awr_outstanding,
+				faxil_wr_outstanding, faxil_rd_outstanding;
+
+	faxil_slave #(
+			.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+			.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+			.F_LGDEPTH(10),
+			.F_AXI_MAXRSTALL(4),
+			.F_AXI_MAXWAIT(9),
+			.F_AXI_MAXDELAY(0)
+	) faxil(.i_clk(ACLK), .i_axi_reset_n(ARESETN),
+		//
+		.i_axi_awready(S_AXI_AWREADY),
+		.i_axi_awaddr( S_AXI_AWADDR),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot( S_AXI_AWPROT),
+		.i_axi_awvalid(S_AXI_AWVALID),
+		//
+		.i_axi_wready(S_AXI_WREADY),
+		.i_axi_wdata( S_AXI_WDATA),
+		.i_axi_wstrb( S_AXI_WSTRB),
+		.i_axi_wvalid(S_AXI_WVALID),
+		//
+		.i_axi_bready(S_AXI_BREADY),
+		.i_axi_bresp( S_AXI_BRESP),
+		.i_axi_bvalid(S_AXI_BVALID),
+		//
+		.i_axi_arready(S_AXI_ARREADY),
+		.i_axi_araddr( S_AXI_ARADDR),
+		.i_axi_arcache(4'h0),
+		.i_axi_arprot( S_AXI_ARPROT),
+		.i_axi_arvalid(S_AXI_ARVALID),
+		//
+		//
+		.i_axi_rready(S_AXI_RREADY),
+		.i_axi_rresp( S_AXI_RRESP),
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rdata( S_AXI_RDATA),
+		//
+		.f_axi_awr_outstanding(faxil_awr_outstanding),
+		.f_axi_wr_outstanding(faxil_wr_outstanding),
+		.f_axi_rd_outstanding(faxil_rd_outstanding));
+
+	//
+	// ...
+	//
+
+	faxi_master #(
+			.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+			.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+			.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+			.OPT_MAXBURST(0),
+			.OPT_EXCLUSIVE(1'b0),
+			.OPT_NARROW_BURST(1'b0),
+			.F_OPT_NO_RESET(1'b1),
+			.F_LGDEPTH(10),
+			.F_AXI_MAXSTALL(4),
+			.F_AXI_MAXRSTALL(0),
+			.F_AXI_MAXDELAY(4)
+	) faxi(.i_clk(ACLK), .i_axi_reset_n(ARESETN),
+		//
+		.i_axi_awready(M_AXI_AWREADY),
+		.i_axi_awid(   M_AXI_AWID),
+		.i_axi_awaddr( M_AXI_AWADDR),
+		.i_axi_awlen(  M_AXI_AWLEN),
+		.i_axi_awsize( M_AXI_AWSIZE),
+		.i_axi_awburst(M_AXI_AWBURST),
+		.i_axi_awlock( M_AXI_AWLOCK),
+		.i_axi_awcache(M_AXI_AWCACHE),
+		.i_axi_awprot( M_AXI_AWPROT),
+		.i_axi_awqos(  M_AXI_AWQOS),
+		.i_axi_awvalid(M_AXI_AWVALID),
+		//
+		.i_axi_wready(M_AXI_WREADY),
+		.i_axi_wdata( M_AXI_WDATA),
+		.i_axi_wstrb( M_AXI_WSTRB),
+		.i_axi_wlast( M_AXI_WLAST),
+		.i_axi_wvalid(M_AXI_WVALID),
+		//
+		.i_axi_bready(M_AXI_BREADY),
+		.i_axi_bid(   M_AXI_BID),
+		.i_axi_bresp( M_AXI_BRESP),
+		.i_axi_bvalid(M_AXI_BVALID),
+		//
+		.i_axi_arready(M_AXI_ARREADY),
+		.i_axi_arid(   M_AXI_ARID),
+		.i_axi_araddr( M_AXI_ARADDR),
+		.i_axi_arlen(  M_AXI_ARLEN),
+		.i_axi_arsize( M_AXI_ARSIZE),
+		.i_axi_arburst(M_AXI_ARBURST),
+		.i_axi_arlock( M_AXI_ARLOCK),
+		.i_axi_arcache(M_AXI_ARCACHE),
+		.i_axi_arprot( M_AXI_ARPROT),
+		.i_axi_arqos(  M_AXI_ARQOS),
+		.i_axi_arvalid(M_AXI_ARVALID),
+		//
+		.i_axi_rid(   M_AXI_RID),
+		.i_axi_rdata( M_AXI_RDATA),
+		.i_axi_rready(M_AXI_RREADY),
+		.i_axi_rresp( M_AXI_RRESP),
+		.i_axi_rvalid(M_AXI_RVALID),
+		//
+		.f_axi_awr_nbursts(faxi_awr_nbursts),
+		.f_axi_wr_pending(faxi_wr_pending),
+		.f_axi_rd_nbursts(faxi_rd_nbursts),
+		.f_axi_rd_outstanding(faxi_rd_outstanding)
+		//
+		// ...
+		//
+		);
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Induction rule checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// First rule: the AXI solver isn't permitted to have any more write
+	// bursts outstanding than the AXI-lite interface has.
+	always @(*)
+		assert(faxi_awr_nbursts == faxil_awr_outstanding);
+
+	//
+	// Second: Since our bursts are limited to one value each, and since
+	// we can't send address bursts ahead of their data counterparts,
+	// (AXI property limitation) faxi_wr_pending can only ever be one or
+	// zero, and the counters must match
+	always @(*)
+	begin
+		//
+		// ...
+		//
+
+		if (faxil_awr_outstanding != 0)
+		begin
+			assert((faxil_awr_outstanding == faxil_wr_outstanding)
+			||(faxil_awr_outstanding-1 == faxil_wr_outstanding));
+		end
+
+		if (faxil_awr_outstanding == 0)
+			assert(faxil_wr_outstanding == 0);
+	end
+
+	//
+	// ...
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Known "bugs"
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// These are really more limitations in the AXI properties than
+	// bugs in the code, but they need to be documented here.
+	//
+	generate if (C_AXI_DATA_WIDTH > 8)
+	begin
+		// The AXI-lite property checker doesn't validate WSTRB
+		// values like it should.  If we don't force the AWADDR
+		// LSBs to zero, the solver will pick an invalid WSTRB.
+		//
+		always @(*)
+			assume(S_AXI_AWADDR[$clog2(C_AXI_DATA_WIDTH)-3:0] == 0);
+		always @(*)
+			assert(faxi_wr_addr[$clog2(C_AXI_DATA_WIDTH)-3:0] == 0);
+	end endgenerate
+
+	//
+	// The AXI solver can't handle write transactions without either a
+	// concurrent or proceeding write address burst.  Here we make that
+	// plain.  It's not likely to cause any problems, but still worth
+	// noting.
+	always @(*)
+	if (faxil_awr_outstanding == faxil_wr_outstanding)
+		assume(S_AXI_AWVALID || !S_AXI_WVALID);
+	else if (faxil_awr_outstanding > faxil_wr_outstanding)
+		assume(!S_AXI_AWVALID);
+
+	//
+	// We need to make certain that our counters never overflow.  This is
+	// an assertion within the property checkers, so we need an appropriate
+	// matching assumption here.  In practice, F_LGDEPTH could be set
+	// so arbitrarily large that this assumption would never get hit,
+	// but the solver doesn't know that.
+	always @(*)
+	if (faxil_rd_outstanding >= {{(F_LGDEPTH-1){1'b1}}, 1'b0 })
+		assume(!S_AXI_ARVALID);
+
+	always @(*)
+	if (faxil_awr_outstanding >= {{(F_LGDEPTH-1){1'b1}}, 1'b0 })
+		assume(!S_AXI_AWVALID);
+
+`endif
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axilrd2wbsp.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilrd2wbsp.v
new file mode 100644
index 0000000..d81fb60
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilrd2wbsp.v
@@ -0,0 +1,499 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axilrd2wbsp.v (AXI lite to wishbone slave, read channel)
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Bridge an AXI lite read channel pair to a single wishbone read
+//		channel.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2016-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module	axilrd2wbsp(i_clk, i_axi_reset_n,
+	// AXI read address channel signals
+	o_axi_arready, i_axi_araddr, i_axi_arcache, i_axi_arprot, i_axi_arvalid,
+	// AXI read data channel signals
+	o_axi_rresp, o_axi_rvalid, o_axi_rdata, i_axi_rready,
+	// We'll share the clock and the reset
+	o_wb_cyc, o_wb_stb, o_wb_addr,
+		i_wb_ack, i_wb_stall, i_wb_data, i_wb_err
+`ifdef	FORMAL
+	, f_first, f_mid, f_last
+`endif
+	);
+	localparam C_AXI_DATA_WIDTH	= 32;// Width of the AXI R&W data
+	parameter C_AXI_ADDR_WIDTH	= 28;	// AXI Address width
+	localparam AW			= C_AXI_ADDR_WIDTH-2;// WB Address width
+	parameter LGFIFO                =  3;
+
+	input	wire			i_clk;	// Bus clock
+	input	wire			i_axi_reset_n;	// Bus reset
+
+// AXI read address channel signals
+	output	reg			o_axi_arready;	// Read address ready
+	input	wire	[C_AXI_ADDR_WIDTH-1:0]	i_axi_araddr;	// Read address
+	input	wire	[3:0]		i_axi_arcache;	// Read Cache type
+	input	wire	[2:0]		i_axi_arprot;	// Read Protection type
+	input	wire			i_axi_arvalid;	// Read address valid
+
+// AXI read data channel signals
+	output	reg [1:0]		o_axi_rresp;   // Read response
+	output	reg			o_axi_rvalid;  // Read reponse valid
+	output	wire [C_AXI_DATA_WIDTH-1:0] o_axi_rdata;    // Read data
+	input	wire			i_axi_rready;  // Read Response ready
+
+	// We'll share the clock and the reset
+	output	reg				o_wb_cyc;
+	output	reg				o_wb_stb;
+	output	reg [(AW-1):0]			o_wb_addr;
+	input	wire				i_wb_ack;
+	input	wire				i_wb_stall;
+	input	wire [(C_AXI_DATA_WIDTH-1):0]	i_wb_data;
+	input	wire				i_wb_err;
+`ifdef	FORMAL
+	// Output connections only used in formal mode
+	output	wire	[LGFIFO:0]		f_first;
+	output	wire	[LGFIFO:0]		f_mid;
+	output	wire	[LGFIFO:0]		f_last;
+`endif
+
+	localparam	DW = C_AXI_DATA_WIDTH;
+	localparam	AXI_LSBS = $clog2(C_AXI_DATA_WIDTH)-3;
+
+	wire	w_reset;
+	assign	w_reset = (!i_axi_reset_n);
+
+	reg			r_stb;
+	reg	[AW-1:0]	r_addr;
+
+	localparam		FLEN=(1<<LGFIFO);
+
+	reg	[DW-1:0]	dfifo		[0:(FLEN-1)];
+	reg			fifo_full, fifo_empty;
+
+	reg	[LGFIFO:0]	r_first, r_mid, r_last;
+	wire	[LGFIFO:0]	next_first, next_last;
+	reg			wb_pending;
+	reg	[LGFIFO:0]	wb_outstanding;
+	wire	[DW-1:0]	read_data;
+	reg			err_state;
+	reg	[LGFIFO:0]	err_loc;
+
+
+
+	initial	o_wb_cyc = 1'b0;
+	initial	o_wb_stb = 1'b0;
+	always @(posedge i_clk)
+	if ((w_reset)||((o_wb_cyc)&&(i_wb_err))||(err_state))
+		o_wb_stb <= 1'b0;
+	else if (r_stb || ((i_axi_arvalid)&&(o_axi_arready)))
+		o_wb_stb <= 1'b1;
+	else if ((o_wb_cyc)&&(!i_wb_stall))
+		o_wb_stb <= 1'b0;
+
+	always @(*)
+		o_wb_cyc = (wb_pending)||(o_wb_stb);
+
+	always @(posedge i_clk)
+	if (r_stb && !i_wb_stall)
+		o_wb_addr <= r_addr;
+	else if ((o_axi_arready)&&((!o_wb_stb)||(!i_wb_stall)))
+		o_wb_addr <= i_axi_araddr[AW+1:AXI_LSBS];
+
+	// Shadow request
+	// r_stb, r_addr
+	initial	r_stb = 1'b0;
+	always @(posedge i_clk)
+	begin
+		if ((i_axi_arvalid)&&(o_axi_arready)&&(o_wb_stb)&&(i_wb_stall))
+		begin
+			r_stb  <= 1'b1;
+			r_addr <= i_axi_araddr[AW+1:AXI_LSBS];
+		end else if ((!i_wb_stall)||(!o_wb_cyc))
+			r_stb <= 1'b0;
+
+		if ((w_reset)||(o_wb_cyc)&&(i_wb_err)||(err_state))
+			r_stb <= 1'b0;
+	end
+
+	initial	wb_pending     = 0;
+	initial	wb_outstanding = 0;
+	always @(posedge i_clk)
+	if ((w_reset)||(!o_wb_cyc)||(i_wb_err)||(err_state))
+	begin
+		wb_pending     <= 1'b0;
+		wb_outstanding <= 0;
+	end else case({ (o_wb_stb)&&(!i_wb_stall), i_wb_ack })
+	2'b01: begin
+		wb_outstanding <= wb_outstanding - 1'b1;
+		wb_pending <= (wb_outstanding >= 2);
+		end
+	2'b10: begin
+		wb_outstanding <= wb_outstanding + 1'b1;
+		wb_pending <= 1'b1;
+		end
+	default: begin end
+	endcase
+
+	assign	next_first = r_first + 1'b1;
+	assign	next_last  = r_last + 1'b1;
+
+	initial	fifo_full  = 1'b0;
+	initial	fifo_empty = 1'b1;
+	always @(posedge i_clk)
+	if (w_reset)
+	begin
+		fifo_full  <= 1'b0;
+		fifo_empty <= 1'b1;
+	end else case({ (o_axi_rvalid)&&(i_axi_rready),
+				(i_axi_arvalid)&&(o_axi_arready) })
+	2'b01: begin
+		fifo_full  <= (next_first[LGFIFO-1:0] == r_last[LGFIFO-1:0])
+					&&(next_first[LGFIFO]!=r_last[LGFIFO]);
+		fifo_empty <= 1'b0;
+		end
+	2'b10: begin
+		fifo_full <= 1'b0;
+		fifo_empty <= 1'b0;
+		end
+	default: begin end
+	endcase
+
+	initial	o_axi_arready = 1'b1;
+	always @(posedge i_clk)
+	if (w_reset)
+		o_axi_arready <= 1'b1;
+	else if ((o_wb_cyc && i_wb_err) || err_state)
+		// On any error, drop the ready flag until it's been flushed
+		o_axi_arready <= 1'b0;
+	else if ((i_axi_arvalid)&&(o_axi_arready)&&(o_wb_stb)&&(i_wb_stall))
+		// On any request where we are already busy, r_stb will get
+		// set and we drop arready
+		o_axi_arready <= 1'b0;
+	else if (!o_axi_arready && o_wb_stb && i_wb_stall)
+		// If we've already stalled on o_wb_stb, remain stalled until
+		// the bus clears
+		o_axi_arready <= 1'b0;
+	else if (fifo_full && (!o_axi_rvalid || !i_axi_rready))
+		// If the FIFO is full, we must remain not ready until at
+		// least one acknowledgment is accepted
+		o_axi_arready <= 1'b0;
+	else if ( (!o_axi_rvalid || !i_axi_rready)
+			&& (i_axi_arvalid && o_axi_arready))
+		o_axi_arready  <= (next_first[LGFIFO-1:0] != r_last[LGFIFO-1:0])
+					||(next_first[LGFIFO]==r_last[LGFIFO]);
+	else
+		o_axi_arready <= 1'b1;
+
+	initial	r_first = 0;
+	always @(posedge i_clk)
+	if (w_reset)
+		r_first <= 0;
+	else if ((i_axi_arvalid)&&(o_axi_arready))
+		r_first <= r_first + 1'b1;
+
+	initial	r_mid = 0;
+	always @(posedge i_clk)
+	if (w_reset)
+		r_mid <= 0;
+	else if ((o_wb_cyc)&&((i_wb_ack)||(i_wb_err)))
+		r_mid <= r_mid + 1'b1;
+	else if ((err_state)&&(r_mid != r_first))
+		r_mid <= r_mid + 1'b1;
+
+	initial	r_last = 0;
+	always @(posedge i_clk)
+	if (w_reset)
+		r_last <= 0;
+	else if ((o_axi_rvalid)&&(i_axi_rready))
+		r_last <= r_last + 1'b1;
+
+	always @(posedge i_clk)
+	if ((o_wb_cyc)&&((i_wb_ack)||(i_wb_err)))
+		dfifo[r_mid[(LGFIFO-1):0]] <= i_wb_data;
+
+	always @(posedge i_clk)
+	if ((o_wb_cyc)&&(i_wb_err))
+		err_loc <= r_mid;
+
+	assign	read_data = dfifo[r_last[LGFIFO-1:0]];
+	assign	o_axi_rdata = read_data[DW-1:0];
+	initial	o_axi_rresp = 2'b00;
+	always @(posedge i_clk)
+	if (w_reset)
+		o_axi_rresp <= 0;
+	else if ((!o_axi_rvalid)||(i_axi_rready))
+	begin
+		if ((!err_state)&&((!o_wb_cyc)||(!i_wb_err)))
+			o_axi_rresp <= 2'b00;
+		else if ((!err_state)&&(o_wb_cyc)&&(i_wb_err))
+		begin
+			if (o_axi_rvalid)
+				o_axi_rresp <= (r_mid == next_last) ? 2'b10 : 2'b00;
+			else
+				o_axi_rresp <= (r_mid == r_last) ? 2'b10 : 2'b00;
+		end else if (err_state)
+		begin
+			if (next_last == err_loc)
+				o_axi_rresp <= 2'b10;
+			else if (o_axi_rresp[1])
+				o_axi_rresp <= 2'b11;
+		end else
+			o_axi_rresp <= 0;
+	end
+
+
+	initial err_state  = 0;
+	always @(posedge i_clk)
+	if (w_reset)
+		err_state <= 0;
+	else if (r_first == r_last)
+		err_state <= 0;
+	else if ((o_wb_cyc)&&(i_wb_err))
+		err_state <= 1'b1;
+
+	initial	o_axi_rvalid = 1'b0;
+	always @(posedge i_clk)
+	if (w_reset)
+		o_axi_rvalid <= 0;
+	else if ((o_wb_cyc)&&((i_wb_ack)||(i_wb_err)))
+		o_axi_rvalid <= 1'b1;
+	else if ((o_axi_rvalid)&&(i_axi_rready))
+	begin
+		if (err_state)
+			o_axi_rvalid <= (next_last != r_first);
+		else
+			o_axi_rvalid <= (next_last != r_mid);
+	end
+
+	// Make Verilator happy
+	// verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, i_axi_arcache, i_axi_arprot,
+			i_axi_araddr[AXI_LSBS-1:0], fifo_empty };
+	// verilator lint_on  UNUSED
+
+`ifdef	FORMAL
+	reg	f_past_valid;
+	reg	f_fifo_empty;
+	reg	[LGFIFO:0]	f_fifo_fill;
+
+	initial f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+
+	always @(*)
+	begin
+		f_fifo_fill  = (r_first - r_last);
+		f_fifo_empty = (f_fifo_fill == 0);
+	end
+
+	always @(*)
+	if (!f_past_valid)
+		assume(w_reset);
+
+	always @(*)
+	if (err_state)
+		assert(!o_axi_arready);
+
+	always @(*)
+	if (err_state)
+		assert((!o_wb_cyc)&&(!o_axi_arready));
+
+	always @(*)
+	if ((f_fifo_empty)&&(!w_reset))
+		assert((!fifo_full)&&(r_first == r_last)&&(r_mid == r_last));
+
+	always @(*)
+	if (fifo_full)
+		assert((!f_fifo_empty)
+			&&(r_first[LGFIFO-1:0] == r_last[LGFIFO-1:0])
+			&&(r_first[LGFIFO] != r_last[LGFIFO]));
+
+	always @(*)
+		assert(f_fifo_fill <= (1<<LGFIFO));
+
+	always @(*)
+	if (fifo_full)
+		assert(!o_axi_arready);
+	always @(*)
+		assert(fifo_full == (f_fifo_fill == (1<<LGFIFO)));
+	always @(*)
+	if (f_fifo_fill == (1<<LGFIFO))
+		assert(!o_axi_arready);
+	always @(*)
+		assert(wb_pending == (wb_outstanding != 0));
+
+	assign	f_first = r_first;
+	assign	f_mid   = r_mid;
+	assign	f_last  = r_last;
+
+	wire	[LGFIFO:0]	f_wb_nreqs, f_wb_nacks, f_wb_outstanding;
+	fwb_master #(
+		.AW(AW), .DW(DW), .F_LGDEPTH(LGFIFO+1)
+		) fwb(i_clk, w_reset,
+		o_wb_cyc, o_wb_stb, 1'b0, o_wb_addr, 32'h0, 4'h0,
+			i_wb_ack, i_wb_stall, i_wb_data, i_wb_err,
+		f_wb_nreqs,f_wb_nacks, f_wb_outstanding);
+
+	always @(*)
+	if (o_wb_cyc)
+		assert(f_wb_outstanding == wb_outstanding);
+
+	always @(*)
+	if (o_wb_cyc)
+		assert(wb_outstanding <= (1<<LGFIFO));
+
+	wire	[LGFIFO:0]	wb_fill;
+	assign	wb_fill = r_first - r_mid;
+	always @(*)
+		assert(wb_fill <= f_fifo_fill);
+	always @(*)
+	if (o_wb_stb)
+		assert(wb_outstanding+1+((r_stb)?1:0) == wb_fill);
+
+	else if (o_wb_cyc)
+		assert(wb_outstanding == wb_fill);
+
+	always @(*)
+	if (r_stb)
+	begin
+		assert(o_wb_stb);
+		assert(!o_axi_arready);
+	end
+
+	wire	[LGFIFO:0]	f_axi_rd_outstanding,
+				f_axi_wr_outstanding,
+				f_axi_awr_outstanding;
+
+	faxil_slave #(
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.F_LGDEPTH(LGFIFO+1),
+		.F_OPT_READ_ONLY(1'b1),
+		.F_AXI_MAXWAIT(0),
+		.F_AXI_MAXDELAY(0)
+		) faxil(i_clk, i_axi_reset_n,
+		//
+		// AXI write address channel signals
+		1'b0, i_axi_araddr, i_axi_arcache, i_axi_arprot, 1'b0,
+		// AXI write data channel signals
+		1'b0, 32'h0, 4'h0, 1'b0,
+		// AXI write response channel signals
+		2'b00, 1'b0, 1'b0,
+		// AXI read address channel signals
+		o_axi_arready, i_axi_araddr, i_axi_arcache, i_axi_arprot,
+			i_axi_arvalid,
+		// AXI read data channel signals
+		o_axi_rresp, o_axi_rvalid, o_axi_rdata, i_axi_rready,
+		f_axi_rd_outstanding, f_axi_wr_outstanding,
+		f_axi_awr_outstanding);
+
+	always @(*)
+		assert(f_axi_wr_outstanding == 0);
+	always @(*)
+		assert(f_axi_awr_outstanding == 0);
+	always @(*)
+		assert(f_axi_rd_outstanding == f_fifo_fill);
+
+	wire	[LGFIFO:0]	f_mid_minus_err, f_err_minus_last,
+				f_first_minus_err;
+	assign	f_mid_minus_err  = f_mid - err_loc;
+	assign	f_err_minus_last = err_loc - f_last;
+	assign	f_first_minus_err = f_first - err_loc;
+	always @(*)
+	if (o_axi_rvalid)
+	begin
+		if (!err_state)
+			assert(!o_axi_rresp[1]);
+		else if (err_loc == f_last)
+			assert(o_axi_rresp == 2'b10);
+		else if (f_err_minus_last < (1<<LGFIFO))
+			assert(!o_axi_rresp[1]);
+		else
+			assert(o_axi_rresp[1]);
+	end
+
+	always @(*)
+	if (err_state)
+		assert(o_axi_rvalid == (r_first != r_last));
+	else
+		assert(o_axi_rvalid == (r_mid != r_last));
+
+	always @(*)
+	if (err_state)
+		assert(f_first_minus_err <= (1<<LGFIFO));
+
+	always @(*)
+	if (err_state)
+		assert(f_first_minus_err != 0);
+
+	always @(*)
+	if (err_state)
+		assert(f_mid_minus_err <= f_first_minus_err);
+
+	always @(*)
+	if ((f_past_valid)&&(i_axi_reset_n)&&(f_axi_rd_outstanding > 0))
+	begin
+		if (err_state)
+			assert((!o_wb_cyc)&&(f_wb_outstanding == 0));
+		else if (!o_wb_cyc)
+			assert((o_axi_rvalid)&&(f_axi_rd_outstanding>0)
+					&&(wb_fill == 0));
+	end
+
+	// WB covers
+	always @(*)
+		cover(o_wb_cyc && o_wb_stb);
+
+	always @(*)
+	if (LGFIFO > 2)
+		cover(o_wb_cyc && f_wb_outstanding > 2);
+
+	always @(posedge i_clk)
+		cover(o_wb_cyc && i_wb_ack
+			&& $past(o_wb_cyc && i_wb_ack)
+			&& $past(o_wb_cyc && i_wb_ack,2));
+
+	// AXI covers
+	always @(*)
+		cover(o_axi_rvalid && i_axi_rready);
+
+	always @(posedge i_clk)
+		cover(i_axi_arvalid && o_axi_arready
+			&& $past(i_axi_arvalid && o_axi_arready)
+			&& $past(i_axi_arvalid && o_axi_arready,2));
+
+	always @(posedge i_clk)
+		cover(o_axi_rvalid && i_axi_rready
+			&& $past(o_axi_rvalid && i_axi_rready)
+			&& $past(o_axi_rvalid && i_axi_rready,2));
+`endif
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axilsafety.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilsafety.v
new file mode 100644
index 0000000..902c1d8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilsafety.v
@@ -0,0 +1,1393 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axilsafety.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	A AXI-Lite bus fault isolator.  This core will isolate any
+//		downstream AXI-liite slave faults from the upstream channel.
+//	It sits as a bump in the wire between upstream and downstream channels,
+//	and so it will consume two clocks--slowing down the slave, but
+//	potentially allowing developer to recover in case of a fault.
+//
+//	This core is configured by a couple parameters, which are key to its
+//	functionality.
+//
+//	OPT_TIMEOUT	Set this to a number to be roughly the longest time
+//		period you expect the slave to stall the bus, or likewise
+//		the longest time period you expect it to wait for a response.
+//		If the slave takes longer for either task, a fault will be
+//		detected and reported.
+//
+//	OPT_SELF_RESET	If set, this will send a reset signal to the downstream
+//		core so that you can attempt to restart it without reloading
+//		the FPGA.  If set, the o_reset signal will be used to reset
+//		the downstream core.
+//
+//	A second key feature of this core are the outgoing fault indicators,
+//	o_write_fault and o_read_fault.  If either signal is ever raised, the
+//	slave has (somehow) violated protocol on either the write or the
+//	read channels respectively.  Such a violation may (or may not) return an
+//	error upstream.  For example, if the slave returns a response
+//	following no requests from the master, then no error will be returned
+//	up stream (doing so would be a protocol violation), but a fault will
+//	still be detected.  Use this line to trigger any internal logic
+//	analyzers.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// }}}
+module axilsafety #(
+	// {{{
+	parameter	C_AXI_ADDR_WIDTH = 28,
+	parameter	C_AXI_DATA_WIDTH = 32,
+	parameter	OPT_TIMEOUT = 12,
+	parameter	MAX_DEPTH = (OPT_TIMEOUT),
+	localparam	AW = C_AXI_ADDR_WIDTH,
+	localparam	DW = C_AXI_DATA_WIDTH,
+	localparam	LGTIMEOUT = $clog2(OPT_TIMEOUT+1),
+	localparam	LGDEPTH   = $clog2(MAX_DEPTH+1),
+	parameter [0:0]	OPT_SELF_RESET = 1'b1,
+	parameter 	OPT_MIN_RESET = 16
+`ifdef	FORMAL
+	, parameter [0:0] F_OPT_WRITES = 1'b1,
+	parameter [0:0] F_OPT_READS  = 1'b1,
+	parameter [0:0]	F_OPT_FAULTLESS = 1'b1
+`endif
+	// }}}
+	) (
+		// {{{
+		output	reg	o_write_fault,
+		output	reg	o_read_fault,
+		//
+		input	wire			S_AXI_ACLK,
+		input	wire			S_AXI_ARESETN,
+		output	reg			M_AXI_ARESETN,
+		//
+		input	wire			S_AXI_AWVALID,
+		output	reg			S_AXI_AWREADY,
+		input	wire	[AW-1:0]	S_AXI_AWADDR,
+		input	wire	[2:0]		S_AXI_AWPROT,
+		//
+		input	wire			S_AXI_WVALID,
+		output	reg			S_AXI_WREADY,
+		input	wire	[DW-1:0]	S_AXI_WDATA,
+		input	wire	[DW/8-1:0]	S_AXI_WSTRB,
+		//
+		output	reg			S_AXI_BVALID,
+		input	wire			S_AXI_BREADY,
+		output	reg	[1:0]		S_AXI_BRESP,
+		//
+		input	wire			S_AXI_ARVALID,
+		output	reg			S_AXI_ARREADY,
+		input	wire	[AW-1:0]	S_AXI_ARADDR,
+		input	wire	[2:0]		S_AXI_ARPROT,
+		//
+		output	reg			S_AXI_RVALID,
+		input	wire			S_AXI_RREADY,
+		output	reg	[DW-1:0]	S_AXI_RDATA,
+		output	reg	[1:0]		S_AXI_RRESP,
+		//
+		//
+		//
+		output	reg			M_AXI_AWVALID,
+		input	wire			M_AXI_AWREADY,
+		output	reg	[AW-1:0]	M_AXI_AWADDR,
+		output	reg	[2:0]		M_AXI_AWPROT,
+		//
+		output	reg			M_AXI_WVALID,
+		input	wire			M_AXI_WREADY,
+		output	reg	[DW-1:0]	M_AXI_WDATA,
+		output	reg	[DW/8-1:0]	M_AXI_WSTRB,
+		//
+		input	wire			M_AXI_BVALID,
+		output	wire			M_AXI_BREADY,
+		input	wire	[1:0]		M_AXI_BRESP,
+		//
+		output	reg			M_AXI_ARVALID,
+		input	wire			M_AXI_ARREADY,
+		output	reg	[AW-1:0]	M_AXI_ARADDR,
+		output	reg	[2:0]		M_AXI_ARPROT,
+		//
+		input	wire			M_AXI_RVALID,
+		output	reg			M_AXI_RREADY,
+		input	wire	[DW-1:0]	M_AXI_RDATA,
+		input	wire	[1:0]		M_AXI_RRESP
+		// }}}
+	);
+
+	// localparam, wire, and register declarations
+	// {{{
+	localparam	OPT_LOWPOWER = 1'b0;
+	localparam	OKAY = 2'b00,
+			EXOKAY = 2'b01,
+			SLVERR = 2'b10;
+
+	reg	[LGDEPTH-1:0]	aw_count, w_count, r_count;
+	reg			aw_zero, w_zero, r_zero,
+				aw_full, w_full, r_full,
+				aw_w_greater, w_aw_greater;
+	reg	[LGDEPTH-1:0]	downstream_aw_count, downstream_w_count, downstream_r_count;
+	reg			downstream_aw_zero, downstream_w_zero, downstream_r_zero;
+				// downstream_aw_w_greater, downstream_w_aw_greater;
+
+	wire			awskd_valid;
+	wire	[2:0]		awskd_prot;
+	wire	[AW-1:0]	awskd_addr;
+	reg			awskd_ready;
+
+	wire			wskd_valid;
+	wire	[DW-1:0]	wskd_data;
+	wire	[DW/8-1:0]	wskd_strb;
+	reg			wskd_ready;
+
+	wire			bskd_valid;
+	wire	[1:0]		bskd_resp;
+	reg			bskd_ready;
+
+	reg			last_bvalid;
+	reg	[1:0]		last_bdata;
+	reg			last_bchanged;
+
+	wire			arskd_valid;
+	wire	[2:0]		arskd_prot;
+	wire	[AW-1:0]	arskd_addr;
+	reg			arskd_ready;
+
+	reg			last_rvalid;
+	reg [DW+1:0]		last_rdata;
+	reg			last_rchanged;
+
+	wire			rskd_valid;
+	wire	[1:0]		rskd_resp;
+	wire	[DW-1:0]	rskd_data;
+	reg			rskd_ready;
+
+	reg [LGTIMEOUT-1:0]	aw_stall_counter, w_stall_counter,
+				r_stall_counter, w_ack_timer, r_ack_timer;
+	reg 			aw_stall_limit, w_stall_limit, r_stall_limit,
+				w_ack_limit, r_ack_limit;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write signaling
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// Write address channel
+	// {{{
+
+	skidbuffer #(.DW(AW+3)
+		// {{{
+`ifdef	FORMAL
+		, .OPT_PASSTHROUGH(1'b1)
+`endif
+		// }}}
+	) awskd(S_AXI_ACLK, !S_AXI_ARESETN,
+		// {{{
+		S_AXI_AWVALID, S_AXI_AWREADY, { S_AXI_AWPROT, S_AXI_AWADDR },
+		awskd_valid, awskd_ready, { awskd_prot, awskd_addr});
+		// }}}
+
+	// awskd_ready
+	// {{{
+	// awskd_ready is the critical piece here, since it determines when
+	// we accept a packet from the skid buffer.
+	//
+	always @(*)
+	if (!M_AXI_ARESETN || o_write_fault)
+		// On any fault, we'll always accept a request (and return an
+		// error).  We always accept a value if there are already
+		// more writes than write addresses accepted.
+		awskd_ready = (w_aw_greater)
+			||((aw_zero)&&(!S_AXI_BVALID || S_AXI_BREADY));
+	else
+		// Otherwise, we accept if ever our counters aren't about to
+		// overflow, and there's a place downstream to accept it
+		awskd_ready = (!M_AXI_AWVALID || M_AXI_AWREADY)&& (!aw_full);
+	// }}}
+
+	// M_AXI_AWVALID
+	// {{{
+	initial	M_AXI_AWVALID = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !M_AXI_ARESETN)
+		M_AXI_AWVALID <= 1'b0;
+	else if (!M_AXI_AWVALID || M_AXI_AWREADY)
+		M_AXI_AWVALID <= awskd_valid && awskd_ready && !o_write_fault;
+	// }}}
+
+	// M_AXI_AWADDR, M_AXI_AWPROT
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (OPT_LOWPOWER && (!M_AXI_ARESETN || o_write_fault))
+	begin
+		M_AXI_AWADDR <= 0;
+		M_AXI_AWPROT <= 0;
+	end else if (!M_AXI_AWVALID || M_AXI_AWREADY)
+	begin
+		M_AXI_AWADDR <= awskd_addr;
+		M_AXI_AWPROT <= awskd_prot;
+	end
+	// }}}
+	// }}}
+
+	//
+	// Write data channel
+	// {{{
+
+	skidbuffer #(.DW(DW+DW/8)
+		// {{{
+`ifdef	FORMAL
+		, .OPT_PASSTHROUGH(1'b1)
+`endif
+		// }}}
+	) wskd(S_AXI_ACLK, !S_AXI_ARESETN,
+		// {{{
+		S_AXI_WVALID, S_AXI_WREADY, { S_AXI_WDATA, S_AXI_WSTRB },
+		wskd_valid, wskd_ready, { wskd_data, wskd_strb});
+		// }}}
+
+	// wskd_ready
+	// {{{
+	// As with awskd_ready, this logic is the critical key.
+	//
+	always @(*)
+	if (!M_AXI_ARESETN || o_write_fault)
+		wskd_ready = (aw_w_greater)
+			|| ((w_zero)&&(!S_AXI_BVALID || S_AXI_BREADY));
+	else
+		wskd_ready = (!M_AXI_WVALID || M_AXI_WREADY) && (!w_full);
+	// }}}
+
+	// M_AXI_WVALID
+	// {{{
+	initial	M_AXI_WVALID = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !M_AXI_ARESETN)
+		M_AXI_WVALID <= 1'b0;
+	else if (!M_AXI_WVALID || M_AXI_WREADY)
+		M_AXI_WVALID <= wskd_valid && wskd_ready && !o_write_fault;
+	// }}}
+
+	// M_AXI_WDATA, M_AXI_WSTRB
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (OPT_LOWPOWER && (!M_AXI_ARESETN || o_write_fault))
+	begin
+		M_AXI_WDATA <= 0;
+		M_AXI_WSTRB <= 0;
+	end else if (!M_AXI_WVALID || M_AXI_WREADY)
+	begin
+		M_AXI_WDATA <= wskd_data;
+		M_AXI_WSTRB <= (o_write_fault) ? 0 : wskd_strb;
+	end
+	// }}}
+	// }}}
+
+	//
+	// Write return channel
+	// {{{
+
+	// bskd_valid, M_AXI_BREADY, bskd_resp
+	// {{{
+`ifdef	FORMAL
+	assign	bskd_valid = M_AXI_BVALID;
+	assign	M_AXI_BREADY= bskd_ready;
+	assign	bskd_resp  = M_AXI_BRESP;
+`else
+	skidbuffer #(.DW(2)
+	) bskd(S_AXI_ACLK, !S_AXI_ARESETN || !M_AXI_ARESETN,
+		M_AXI_BVALID, M_AXI_BREADY, M_AXI_BRESP,
+		bskd_valid, bskd_ready,  bskd_resp);
+`endif
+	// }}}
+
+	// bskd_ready
+	// {{{
+	always @(*)
+	if (o_write_fault)
+		bskd_ready = 1'b1;
+	else
+		bskd_ready = (!S_AXI_BVALID || S_AXI_BREADY);
+	// }}}
+
+	// S_AXI_BVALID
+	// {{{
+	initial	S_AXI_BVALID = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		S_AXI_BVALID <= 1'b0;
+	else if (!S_AXI_BVALID || S_AXI_BREADY)
+	begin
+		if (o_write_fault || !M_AXI_ARESETN)
+			S_AXI_BVALID <= (!S_AXI_BVALID&&(!aw_zero)&&(!w_zero));
+		else
+			S_AXI_BVALID <= (!downstream_aw_zero)
+				&&(!downstream_w_zero)&&(bskd_valid);
+	end
+	// }}}
+
+	// last_bvalid
+	// {{{
+	initial	last_bvalid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!M_AXI_ARESETN || o_write_fault)
+		last_bvalid <= 1'b0;
+	else
+		last_bvalid <= (M_AXI_BVALID && !M_AXI_BREADY);
+	// }}}
+
+	// last_bdata
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (M_AXI_BVALID)
+		last_bdata <= M_AXI_BRESP;
+	// }}}
+
+	// last_bchanged
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_write_fault)
+		last_bchanged <= 1'b0;
+	else
+		last_bchanged <= (last_bvalid && (!M_AXI_BVALID
+					|| last_bdata != M_AXI_BRESP));
+	// }}}
+
+	// S_AXI_BRESP
+	// {{{
+	initial	S_AXI_BRESP = OKAY;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_BVALID || S_AXI_BREADY)
+	begin
+		if (o_write_fault)
+			S_AXI_BRESP <= SLVERR;
+		else if (bskd_resp == EXOKAY)
+			S_AXI_BRESP <= SLVERR;
+		else
+			S_AXI_BRESP <= bskd_resp;
+	end
+	// }}}
+	// }}}
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read signaling
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// Read address channel
+	// {{{
+
+	skidbuffer #(.DW(AW+3)
+		// {{{
+`ifdef	FORMAL
+		, .OPT_PASSTHROUGH(1'b1)
+`endif
+		// }}}
+	) arskd(S_AXI_ACLK, !S_AXI_ARESETN,
+		// {{{
+		S_AXI_ARVALID, S_AXI_ARREADY, { S_AXI_ARPROT, S_AXI_ARADDR },
+		arskd_valid, arskd_ready,  { arskd_prot, arskd_addr });
+		// }}}
+
+	// arskd_ready
+	// {{{
+	always @(*)
+	if (!M_AXI_ARESETN || o_read_fault)
+		arskd_ready =((r_zero)&&(!S_AXI_RVALID || S_AXI_RREADY));
+	else
+		arskd_ready = (!M_AXI_ARVALID || M_AXI_ARREADY) && (!r_full);
+	// }}}
+
+	// M_AXI_ARVALID
+	// {{{
+	initial	M_AXI_ARVALID = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !M_AXI_ARESETN)
+		M_AXI_ARVALID <= 1'b0;
+	else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+		M_AXI_ARVALID <= arskd_valid && arskd_ready && !o_read_fault;
+	// }}}
+
+	// M_AXI_ARADDR, M_AXI_ARPROT
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (OPT_LOWPOWER && (!M_AXI_ARESETN || o_read_fault))
+	begin
+		M_AXI_ARADDR <= 0;
+		M_AXI_ARPROT <= 0;
+	end else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+	begin
+		M_AXI_ARADDR <= arskd_addr;
+		M_AXI_ARPROT <= arskd_prot;
+	end
+	// }}}
+	// }}}
+
+	//
+	// Read data channel
+	// {{{
+
+	// rskd_valid, rskd_resp, rskd_data skid buffer
+	// {{{
+`ifdef	FORMAL
+	assign	rskd_valid = M_AXI_RVALID;
+	assign	M_AXI_RREADY = rskd_ready;
+	assign	{ rskd_resp, rskd_data } = { M_AXI_RRESP, M_AXI_RDATA };
+`else
+	skidbuffer #(.DW(DW+2)
+	) rskd(S_AXI_ACLK, !S_AXI_ARESETN || !M_AXI_ARESETN,
+		M_AXI_RVALID, M_AXI_RREADY, { M_AXI_RRESP, M_AXI_RDATA },
+		rskd_valid, rskd_ready,  { rskd_resp, rskd_data });
+`endif
+	// ?}}}
+
+	// rskd_ready
+	// {{{
+	always @(*)
+	if (o_read_fault)
+		rskd_ready = 1;
+	else
+		rskd_ready = (!S_AXI_RVALID || S_AXI_RREADY);
+	// }}}
+
+	// S_AXI_RVALID
+	// {{{
+	initial	S_AXI_RVALID = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		S_AXI_RVALID <= 1'b0;
+	else if (!S_AXI_RVALID || S_AXI_RREADY)
+	begin
+		if (o_read_fault || !M_AXI_ARESETN)
+			S_AXI_RVALID <= (!S_AXI_RVALID && !r_zero)
+					|| (arskd_valid && arskd_ready);
+		else
+			S_AXI_RVALID <= (!downstream_r_zero)&&(rskd_valid);
+	end
+	// }}}
+
+	// S_AXI_RDATA, S_AXI_RRESP
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_RVALID || S_AXI_RREADY)
+	begin
+		if (o_read_fault || !M_AXI_ARESETN)
+			S_AXI_RDATA <= 0;
+		else
+			S_AXI_RDATA <= rskd_data;
+
+		S_AXI_RRESP <= OKAY;
+		if (o_read_fault || rskd_resp == EXOKAY)
+			S_AXI_RRESP <= SLVERR;
+		else if (!downstream_r_zero)
+			S_AXI_RRESP <= rskd_resp;
+	end
+	// }}}
+
+	// last_rvalid
+	// {{{
+	initial	last_rvalid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_read_fault)
+		last_rvalid <= 1'b0;
+	else
+		last_rvalid <= (M_AXI_RVALID && !M_AXI_RREADY);
+	// }}}
+
+	// last_rdata
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (M_AXI_RVALID)
+		last_rdata <= { M_AXI_RRESP, M_AXI_RDATA };
+	// }}}
+
+	// last_rchanged
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_read_fault)
+		last_rchanged <= 1'b0;
+	else
+		last_rchanged <= (last_rvalid && (!M_AXI_RVALID
+			|| last_rdata != { M_AXI_RRESP, M_AXI_RDATA }));
+	// }}}
+	// }}}
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Usage counters
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// Write address channel
+	// {{{
+
+	initial	aw_count = 0;
+	initial	aw_zero  = 1;
+	initial	aw_full  = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		aw_count <= 0;
+		aw_zero  <= 1;
+		aw_full  <= 0;
+	end else case({(awskd_valid && awskd_ready),S_AXI_BVALID&&S_AXI_BREADY})
+	2'b10: begin
+		aw_count <= aw_count + 1;
+		aw_zero <= 0;
+		aw_full <= (aw_count == { {(LGDEPTH-1){1'b1}}, 1'b0 });
+		end
+	2'b01: begin
+		aw_count <= aw_count - 1;
+		aw_zero <= (aw_count <= 1);
+		aw_full <= 0;
+		end
+	default: begin end
+	endcase
+	// }}}
+
+	//
+	// Write data channel
+	// {{{
+	initial	w_count = 0;
+	initial	w_zero  = 1;
+	initial	w_full  = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		w_count <= 0;
+		w_zero  <= 1;
+		w_full  <= 0;
+	end else case({(wskd_valid && wskd_ready), S_AXI_BVALID&& S_AXI_BREADY})
+	2'b10: begin
+		w_count <= w_count + 1;
+		w_zero <= 0;
+		w_full <= (w_count == { {(LGDEPTH-1){1'b1}}, 1'b0 });
+		end
+	2'b01: begin
+		w_count <= w_count - 1;
+		w_zero <= (w_count <= 1);
+		w_full <= 1'b0;
+		end
+	default: begin end
+	endcase
+	// }}}
+
+	// aw_w_greater, w_aw_greater
+	// {{{
+	initial	aw_w_greater = 0;
+	initial	w_aw_greater = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		aw_w_greater <= 0;
+		w_aw_greater <= 0;
+	end else case({(awskd_valid && awskd_ready),
+			(wskd_valid && wskd_ready)})
+	2'b10: begin
+		aw_w_greater <= (aw_count + 1 >  w_count);
+		w_aw_greater <= ( w_count     > aw_count + 1);
+		end
+	2'b01: begin
+		aw_w_greater <= (aw_count     >  w_count + 1);
+		w_aw_greater <= ( w_count + 1 > aw_count);
+		end
+	default: begin end
+	endcase
+	// }}}
+	//
+	// Read channel
+	// {{{
+
+	// r_count, r_zero, r_full
+	initial	r_count = 0;
+	initial	r_zero  = 1;
+	initial	r_full  = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		r_count <= 0;
+		r_zero  <= 1;
+		r_full  <= 0;
+	end else case({(arskd_valid&&arskd_ready), S_AXI_RVALID&&S_AXI_RREADY})
+	2'b10: begin
+		r_count <= r_count + 1;
+		r_zero <= 0;
+		r_full <= (r_count == { {(LGDEPTH-1){1'b1}}, 1'b0 });
+		end
+	2'b01: begin
+		r_count <= r_count - 1;
+		r_zero <= (r_count <= 1);
+		r_full <= 0;
+		end
+	default: begin end
+	endcase
+	// }}}
+
+	//
+	// Downstream write address channel
+	// {{{
+
+	initial	downstream_aw_count = 0;
+	initial	downstream_aw_zero = 1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_write_fault)
+	begin
+		downstream_aw_count <= 0;
+		downstream_aw_zero <= 1;
+	end else case({(M_AXI_AWVALID && M_AXI_AWREADY), M_AXI_BVALID && M_AXI_BREADY})
+	2'b10: begin
+		downstream_aw_count <= downstream_aw_count + 1;
+		downstream_aw_zero <= 0;
+		end
+	2'b01: begin
+		downstream_aw_count <= downstream_aw_count - 1;
+		downstream_aw_zero <= (downstream_aw_count <= 1);
+		end
+	default: begin end
+	endcase
+	// }}}
+
+	//
+	// Downstream write data channel
+	// {{{
+	initial	downstream_w_count = 0;
+	initial	downstream_w_zero  = 1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_write_fault)
+	begin
+		downstream_w_count <= 0;
+		downstream_w_zero  <= 1;
+	end else case({(M_AXI_WVALID && M_AXI_WREADY), M_AXI_BVALID && M_AXI_BREADY})
+	2'b10: begin
+		downstream_w_count <= downstream_w_count + 1;
+		downstream_w_zero <= 0;
+		end
+	2'b01: begin
+		downstream_w_count <= downstream_w_count - 1;
+		downstream_w_zero <= (downstream_w_count <= 1);
+		end
+	default: begin end
+	endcase
+	// }}}
+
+	//
+	// Downstream read channel
+	// {{{
+
+	initial	downstream_r_count = 0;
+	initial	downstream_r_zero  = 1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_read_fault)
+	begin
+		downstream_r_count <= 0;
+		downstream_r_zero  <= 1;
+	end else case({M_AXI_ARVALID && M_AXI_ARREADY, M_AXI_RVALID && M_AXI_RREADY})
+	2'b10: begin
+		downstream_r_count <= downstream_r_count + 1;
+		downstream_r_zero  <= 0;
+		end
+	2'b01: begin
+		downstream_r_count <= downstream_r_count - 1;
+		downstream_r_zero  <= (downstream_r_count <= 1);
+		end
+	default: begin end
+	endcase
+	// }}}
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Timeout checking
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// The key piece here is that we define the timeout depending upon
+	// what happens (or doesn't happen) *DOWNSTREAM*.  These timeouts
+	// will need to propagate upstream before taking place.
+
+	//
+	// Write address stall counter
+	// {{{
+	initial	aw_stall_counter = 0;
+	initial	aw_stall_limit   = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || o_write_fault || !M_AXI_ARESETN)
+	begin
+		aw_stall_counter <= 0;
+		aw_stall_limit   <= 0;
+	end else if (!M_AXI_AWVALID || M_AXI_AWREADY || M_AXI_BVALID)
+	begin
+		aw_stall_counter <= 0;
+		aw_stall_limit   <= 0;
+	end else if (aw_w_greater && !M_AXI_WVALID)
+	begin
+		aw_stall_counter <= 0;
+		aw_stall_limit   <= 0;
+	end else // if (!S_AXI_BVALID || S_AXI_BREADY)
+	begin
+		aw_stall_counter <= aw_stall_counter + 1;
+		aw_stall_limit   <= (aw_stall_counter+1 >= OPT_TIMEOUT);
+	end
+	// }}}
+
+	//
+	// Write data stall counter
+	// {{{
+	initial	w_stall_counter = 0;
+	initial	w_stall_limit   = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_write_fault)
+	begin
+		w_stall_counter <= 0;
+		w_stall_limit   <= 0;
+	end else if (!M_AXI_WVALID || M_AXI_WREADY || M_AXI_BVALID)
+	begin
+		w_stall_counter <= 0;
+		w_stall_limit   <= 0;
+	end else if (w_aw_greater && !M_AXI_AWVALID)
+	begin
+		w_stall_counter <= 0;
+		w_stall_limit   <= 0;
+	end else // if (!M_AXI_BVALID || M_AXI_BREADY)
+	begin
+		w_stall_counter <= w_stall_counter + 1;
+		w_stall_limit   <= (w_stall_counter + 1 >= OPT_TIMEOUT);
+	end
+	// }}}
+
+	//
+	// Write acknowledgment delay counter
+	// {{{
+	initial w_ack_timer = 0;
+	initial	w_ack_limit = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_write_fault)
+	begin
+		w_ack_timer <= 0;
+		w_ack_limit <= 0;
+	end else if (M_AXI_BVALID || downstream_aw_zero || downstream_w_zero)
+	begin
+		w_ack_timer <= 0;
+		w_ack_limit <= 0;
+	end else
+	begin
+		w_ack_timer <= w_ack_timer + 1;
+		w_ack_limit <= (w_ack_timer + 1 >= OPT_TIMEOUT);
+	end
+	// }}}
+
+	//
+	// Read request stall counter
+	// {{{
+	initial r_stall_counter = 0;
+	initial	r_stall_limit   = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_read_fault)
+	begin
+		r_stall_counter <= 0;
+		r_stall_limit   <= 0;
+	end else if (!M_AXI_ARVALID || M_AXI_ARREADY || M_AXI_RVALID)
+	begin
+		r_stall_counter <= 0;
+		r_stall_limit   <= 0;
+	end else begin
+		r_stall_counter <= r_stall_counter + 1;
+		r_stall_limit   <= (r_stall_counter + 1 >= OPT_TIMEOUT);
+	end
+	// }}}
+
+	//
+	// Read acknowledgement delay counter
+	// {{{
+	initial r_ack_timer = 0;
+	initial	r_ack_limit = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_read_fault)
+	begin
+		r_ack_timer <= 0;
+		r_ack_limit <= 0;
+	end else if (M_AXI_RVALID || downstream_r_zero)
+	begin
+		r_ack_timer <= 0;
+		r_ack_limit <= 0;
+	end else begin
+		r_ack_timer <= r_ack_timer + 1;
+		r_ack_limit <= (r_ack_timer + 1 >= OPT_TIMEOUT);
+	end
+	// }}}
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Fault detection
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// Determine if a write fault has taken place
+	// {{{
+	initial	o_write_fault =1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		o_write_fault <= 1'b0;
+	else if (OPT_SELF_RESET && o_write_fault)
+	begin
+		//
+		// Clear any fault on reset
+		if (!M_AXI_ARESETN)
+			o_write_fault <= 1'b0;
+	end else begin
+		//
+		// A write fault takes place if you respond without a prior
+		// bus request on both write address and write data channels.
+		if ((downstream_aw_zero || downstream_w_zero)&&(bskd_valid))
+			o_write_fault <= 1'b1;
+
+		// AXI-lite slaves are not allowed to return EXOKAY responses
+		// from the bus
+		if (bskd_valid && bskd_resp == EXOKAY)
+			o_write_fault <= 1'b1;
+
+		// If the downstream core refuses to accept either a
+		// write address request, or a write data request, or for that
+		// matter if it doesn't return an acknowledgment in a timely
+		// fashion, then a fault has been detected.
+		if (aw_stall_limit || w_stall_limit || w_ack_limit)
+			o_write_fault <= 1'b1;
+
+		// If the downstream core changes BRESP while VALID && !READY,
+		// then it isn't stalling the channel properly--that's a fault.
+		if (last_bchanged)
+			o_write_fault <= 1'b1;
+	end
+	// }}}
+
+	// o_read_fault
+	// {{{
+	initial	o_read_fault =1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		o_read_fault <= 1'b0;
+	else if (OPT_SELF_RESET && o_read_fault)
+	begin
+		//
+		// Clear any fault on reset
+		if (!M_AXI_ARESETN)
+			o_read_fault <= 1'b0;
+	end else begin
+		// Responding without a prior request is a fault.  Can only
+		// respond after a request has been made.
+		if (downstream_r_zero && rskd_valid)
+			o_read_fault <= 1'b1;
+
+		// AXI-lite slaves are not allowed to return EXOKAY.  This is
+		// an error.
+		if (rskd_valid && rskd_resp == EXOKAY)
+			o_read_fault <= 1'b1;
+
+		// The slave cannot stall the bus forever, nor should the
+		// master wait forever for a response from the slave.
+		if (r_stall_limit || r_ack_limit)
+			o_read_fault <= 1'b1;
+
+		// If the slave changes the data, or the RRESP on the wire,
+		// while the incoming bus is stalled, then that's also a fault.
+		if (last_rchanged)
+			o_read_fault <= 1'b1;
+	end
+	// }}}
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Self reset handling
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	generate if (OPT_SELF_RESET)
+	begin : SELF_RESET_GENERATION
+		// {{{
+		reg		min_reset;
+
+		if (OPT_MIN_RESET > 1)
+		begin : MIN_RESET
+			// {{{
+			reg	[$clog2(OPT_MIN_RESET+1):0]	reset_counter;
+
+			//
+			// Optionally insist that any downstream reset have a
+			// minimum duration.  Many Xilinx components require
+			// a 16-clock reset.  This ensures such reset
+			// requirements are achieved.
+			//
+
+			initial reset_counter = OPT_MIN_RESET-1;
+			initial	min_reset = 1'b0;
+			always @(posedge S_AXI_ARESETN)
+			if (M_AXI_ARESETN)
+			begin
+				reset_counter <= OPT_MIN_RESET-1;
+				min_reset <= 1'b0;
+			end else if (!M_AXI_ARESETN)
+			begin
+				if (reset_counter > 0)
+					reset_counter <= reset_counter-1;
+				min_reset <= (reset_counter <= 1);
+			end
+
+`ifdef	FORMAL
+			always @(*)
+				assert(reset_counter < OPT_MIN_RESET);
+			always @(*)
+				assert(min_reset == (reset_counter == 0));
+`endif
+			// }}}
+		end else begin
+			// {{{
+			always @(*)
+				min_reset = 1'b1;
+			// }}}
+		end
+
+		// M_AXI_ARESETN
+		// {{{
+		// Reset the downstream bus on either a write or a read fault.
+		// Once the bus returns to idle, and any minimum reset durations
+		// have been achieved, then release the downstream from reset.
+		//
+		initial	M_AXI_ARESETN = 1'b0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			M_AXI_ARESETN <= 1'b0;
+		else if (o_write_fault || o_read_fault)
+			M_AXI_ARESETN <= 1'b0;
+		else if (aw_zero && w_zero && r_zero && min_reset
+			&& !awskd_valid && !wskd_valid && !arskd_valid)
+			M_AXI_ARESETN <= 1'b1;
+		// }}}
+		// }}}
+	end else begin : SAME_RESET
+		// {{{
+		//
+		// The downstream reset equals the upstream reset
+		//
+		always @(*)
+			M_AXI_ARESETN = S_AXI_ARESETN;
+		// }}}
+	end endgenerate
+	// }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal property section
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	// {{{
+	//
+	// The following proof comes in several parts.
+	//
+	// 1. PROVE that the upstream properties will hold independent of
+	//	what the downstream slave ever does.
+	//
+	// 2. PROVE that if the downstream slave follows protocol, then
+	//	neither o_write_fault nor o_read_fault will never get raised.
+	//
+	// We then repeat these proofs again with both OPT_SELF_RESET set and
+	// clear.  Which of the four proofs is accomplished is dependent upon
+	// parameters set by the formal engine.
+	//
+	//
+	wire	[LGDEPTH:0]	faxils_awr_outstanding, faxils_wr_outstanding,
+				faxils_rd_outstanding;
+
+	reg	f_past_valid;
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Upstream master Bus properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(*)
+	if (!f_past_valid)
+	begin
+		assume(!S_AXI_ARESETN);
+		assert(!M_AXI_ARESETN);
+	end
+
+	faxil_slave #(
+		// {{{
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.F_OPT_ASSUME_RESET(1'b1),
+		.F_OPT_NO_RESET((OPT_MIN_RESET == 0) ? 1:0),
+//		.F_AXI_MAXWAIT((F_OPT_FAULTLESS) ? (2*OPT_TIMEOUT+2) : 0),
+		.F_AXI_MAXRSTALL(3),
+//		.F_AXI_MAXDELAY(OPT_TIMEOUT+OPT_TIMEOUT+5),
+		.F_LGDEPTH(LGDEPTH+1),
+		//
+		.F_AXI_MAXWAIT((F_OPT_FAULTLESS) ? (2*OPT_TIMEOUT+2) : 0),
+		.F_AXI_MAXDELAY(2*OPT_TIMEOUT+3)
+		// }}}
+	) axils (
+		// {{{
+		.i_clk(S_AXI_ACLK),
+		.i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXI_AWVALID),
+		.i_axi_awready(S_AXI_AWREADY),
+		.i_axi_awaddr( S_AXI_AWADDR),
+		.i_axi_awprot( S_AXI_AWPROT),
+		.i_axi_awcache(4'h0),
+		//
+		.i_axi_wvalid(S_AXI_WVALID),
+		.i_axi_wready(S_AXI_WREADY),
+		.i_axi_wdata( S_AXI_WDATA),
+		.i_axi_wstrb( S_AXI_WSTRB),
+		//
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+		.i_axi_bresp( S_AXI_BRESP),
+		//
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+		.i_axi_araddr( S_AXI_ARADDR),
+		.i_axi_arprot( S_AXI_ARPROT),
+		.i_axi_arcache(4'h0),
+		//
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rready(S_AXI_RREADY),
+		.i_axi_rdata( S_AXI_RDATA),
+		.i_axi_rresp( S_AXI_RRESP),
+		//
+		.f_axi_awr_outstanding(faxils_awr_outstanding),
+		.f_axi_wr_outstanding(faxils_wr_outstanding),
+		.f_axi_rd_outstanding(faxils_rd_outstanding)
+		// }}}
+	);
+
+	always @(*)
+	if (!F_OPT_WRITES)
+	begin
+		// {{{
+		assume(!S_AXI_AWVALID);
+		assume(!S_AXI_WVALID);
+		assert(aw_count == 0);
+		assert(w_count == 0);
+		assert(!M_AXI_AWVALID);
+		assert(!M_AXI_WVALID);
+		// }}}
+	end
+
+	always @(*)
+	if (!F_OPT_READS)
+	begin
+		// {{{
+		assume(!S_AXI_ARVALID);
+		assert(r_count == 0);
+		assert(!S_AXI_RVALID);
+		assert(!M_AXI_ARVALID);
+		// }}}
+	end
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// General Induction properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+
+	always @(*)
+	begin
+		// {{{
+		assert(aw_zero == (aw_count  == 0));
+		assert(w_zero  == (w_count   == 0));
+		assert(r_zero  == (r_count   == 0));
+
+		//
+		assert(aw_full == (&aw_count));
+		assert(w_full  == (&w_count));
+		assert(r_full  == (&r_count));
+		//
+		if (M_AXI_ARESETN && !o_write_fault)
+		begin
+			assert(downstream_aw_zero  == (downstream_aw_count == 0));
+			assert(downstream_w_zero   == (downstream_w_count  == 0));
+			assert(downstream_aw_count + (M_AXI_AWVALID ? 1:0)
+					+ (S_AXI_BVALID ? 1:0) == aw_count);
+			assert(downstream_w_count + (M_AXI_WVALID ? 1:0)
+					+ (S_AXI_BVALID ? 1:0) ==  w_count);
+		end
+
+		if (M_AXI_ARESETN && !o_read_fault)
+		begin
+			assert(downstream_r_zero   == (downstream_r_count  == 0));
+			assert(downstream_r_count + (M_AXI_ARVALID ? 1:0)
+					+ (S_AXI_RVALID ? 1:0) ==  r_count);
+		end
+		//
+		assert(aw_count == faxils_awr_outstanding);
+		assert(w_count  == faxils_wr_outstanding);
+		assert(r_count  == faxils_rd_outstanding);
+
+		assert(aw_w_greater == (aw_count > w_count));
+		assert(w_aw_greater == (w_count > aw_count));
+		// }}}
+	end
+	// }}}
+	generate if (F_OPT_FAULTLESS)
+	begin : ASSUME_FAULTLESS
+		// {{{
+		////////////////////////////////////////////////////////////////
+		//
+		// Assume the downstream core is protocol compliant, and
+		// prove that o_fault stays low.
+		// {{{
+		////////////////////////////////////////////////////////////////
+		//
+		wire	[LGDEPTH:0]	faxilm_awr_outstanding,
+					faxilm_wr_outstanding,
+					faxilm_rd_outstanding;
+
+		faxil_master #(
+			// {{{
+			.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+			.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+			.F_OPT_NO_RESET((OPT_MIN_RESET == 0) ? 1:0),
+			.F_AXI_MAXWAIT(OPT_TIMEOUT),
+			.F_AXI_MAXRSTALL(4),
+			.F_AXI_MAXDELAY(OPT_TIMEOUT),
+			.F_LGDEPTH(LGDEPTH+1)
+			// }}}
+		) axilm (
+			// {{{
+			.i_clk(S_AXI_ACLK),
+			.i_axi_reset_n(M_AXI_ARESETN && S_AXI_ARESETN),
+			//
+			.i_axi_awvalid(M_AXI_AWVALID),
+			.i_axi_awready(M_AXI_AWREADY),
+			.i_axi_awaddr( M_AXI_AWADDR),
+			.i_axi_awprot( M_AXI_AWPROT),
+			.i_axi_awcache(4'h0),
+			//
+			.i_axi_wvalid(M_AXI_WVALID),
+			.i_axi_wready(M_AXI_WREADY),
+			.i_axi_wdata( M_AXI_WDATA),
+			.i_axi_wstrb( M_AXI_WSTRB),
+			//
+			.i_axi_bvalid(M_AXI_BVALID),
+			.i_axi_bready(M_AXI_BREADY),
+			.i_axi_bresp( M_AXI_BRESP),
+			//
+			.i_axi_arvalid(M_AXI_ARVALID),
+			.i_axi_arready(M_AXI_ARREADY),
+			.i_axi_araddr( M_AXI_ARADDR),
+			.i_axi_arprot( M_AXI_ARPROT),
+			.i_axi_arcache(4'h0),
+			//
+			.i_axi_rvalid(M_AXI_RVALID),
+			.i_axi_rready(M_AXI_RREADY),
+			.i_axi_rdata( M_AXI_RDATA),
+			.i_axi_rresp( M_AXI_RRESP),
+			//
+			.f_axi_awr_outstanding(faxilm_awr_outstanding),
+			.f_axi_wr_outstanding(faxilm_wr_outstanding),
+			.f_axi_rd_outstanding(faxilm_rd_outstanding)
+			// }}}
+		);
+
+		//
+		// Here's the big proof
+		// {{{
+		always @(*)
+			assert(!o_write_fault);
+		always @(*)
+			assert(!o_read_fault);
+		// }}}
+		// }}}
+		////////////////////////////////////////////////////////////////
+		//
+		// The following properties are necessary for passing induction
+		// {{{
+		////////////////////////////////////////////////////////////////
+		//
+		//
+		always @(*)
+		begin
+			assert(!aw_stall_limit);
+			assert(!w_stall_limit);
+			assert(!w_ack_limit);
+
+			assert(!r_stall_limit);
+			assert(!r_ack_limit);
+
+			if (M_AXI_ARESETN)
+			begin
+			assert(downstream_aw_count == faxilm_awr_outstanding);
+			assert(downstream_w_count  == faxilm_wr_outstanding);
+			assert(downstream_r_count  == faxilm_rd_outstanding);
+			end
+		end
+
+		if (OPT_SELF_RESET)
+		begin
+			always @(posedge S_AXI_ACLK)
+			if (f_past_valid)
+				assert(M_AXI_ARESETN == $past(S_AXI_ARESETN));
+		end
+
+`ifdef	VERIFIC
+		wire	[LGDEPTH:0]	f_axi_arstall;
+		wire	[LGDEPTH:0]	f_axi_awstall;
+		wire	[LGDEPTH:0]	f_axi_wstall;
+
+		assign	f_axi_awstall = axilm.CHECK_STALL_COUNT.f_axi_awstall;
+		assign	f_axi_wstall  = axilm.CHECK_STALL_COUNT.f_axi_wstall;
+		assign	f_axi_arstall = axilm.CHECK_STALL_COUNT.f_axi_arstall;
+
+		always @(*)
+		if (M_AXI_ARESETN && S_AXI_ARESETN && !o_write_fault)
+			assert(f_axi_awstall == aw_stall_counter);
+
+		always @(*)
+		if (M_AXI_ARESETN && S_AXI_ARESETN && !o_write_fault)
+			assert(f_axi_wstall == w_stall_counter);
+
+		always @(*)
+		if (M_AXI_ARESETN && S_AXI_ARESETN && !o_read_fault)
+			assert(f_axi_arstall == r_stall_counter);
+`endif
+		// }}}
+		// }}}
+	end else begin : WILD_DOWNSTREAM
+		// {{{
+		////////////////////////////////////////////////////////////////
+		//
+		// cover() checks, checks that only make sense if faults are
+		// possible
+		//
+
+		reg		write_faulted, read_faulted, faulted;
+		reg	[3:0]	cvr_writes, cvr_reads;
+
+
+		if (OPT_SELF_RESET)
+		begin
+			////////////////////////////////////////////////////////
+			//
+			// Prove that we can actually reset the downstream
+			// bus/core as desired
+			// {{{
+			////////////////////////////////////////////////////////
+			//
+			//
+			initial	write_faulted = 0;
+			always @(posedge S_AXI_ACLK)
+			if (!S_AXI_ARESETN)
+				write_faulted <= 0;
+			else if (o_write_fault)
+				write_faulted <= 1;
+
+
+			initial	faulted = 0;
+			always @(posedge S_AXI_ACLK)
+			if (!S_AXI_ARESETN)
+				read_faulted <= 0;
+			else if (o_read_fault)
+				read_faulted <= 1;
+
+			always @(*)
+				faulted = (write_faulted || read_faulted);
+
+			always @(posedge S_AXI_ACLK)
+				cover(write_faulted && $rose(M_AXI_ARESETN));
+
+			always @(posedge S_AXI_ACLK)
+				cover(read_faulted && $rose(M_AXI_ARESETN));
+
+			always @(posedge S_AXI_ACLK)
+				cover(faulted && M_AXI_ARESETN && S_AXI_BVALID);
+
+			always @(posedge S_AXI_ACLK)
+				cover(faulted && M_AXI_ARESETN && S_AXI_RVALID);
+
+
+			initial	cvr_writes = 0;
+			always @(posedge S_AXI_ACLK)
+			if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_write_fault)
+				cvr_writes <= 0;
+			else if (write_faulted && S_AXI_BVALID && S_AXI_BREADY
+				&& S_AXI_BRESP == OKAY
+				&&(!(&cvr_writes)))
+				cvr_writes <= cvr_writes + 1;
+
+			always @(*)
+				cover(cvr_writes > 5);
+
+			initial	cvr_reads = 0;
+			always @(posedge S_AXI_ACLK)
+			if (!S_AXI_ARESETN || !M_AXI_ARESETN || o_read_fault)
+				cvr_reads <= 0;
+			else if (read_faulted && S_AXI_RVALID && S_AXI_RREADY
+				&& S_AXI_RRESP == OKAY
+				&&(!(&cvr_reads)))
+				cvr_reads <= cvr_reads + 1;
+
+			always @(*)
+				cover(cvr_reads > 5);
+			// }}}
+		end
+
+		// }}}
+	end endgenerate
+
+`endif
+// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axilsingle.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilsingle.v
new file mode 100644
index 0000000..13a9911
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilsingle.v
@@ -0,0 +1,719 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axilsingle.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Create a special AXI-lite slave which can be used to reduce
+//		crossbar logic for multiple simplified AXI-lite slaves.
+//
+//	To use this, the slave must follow specific (simplified AXI-lite) rules:
+//
+//	Write interface
+//	1. The slave must guarantee that AWREADY == WREADY = 1
+//		(This core doesn't have AWREADY or WREADY inputs)
+//	2. The slave must also guarantee that BVALID == $past(AWVALID)
+//		(This core internally generates BVALID)
+//	3. The controller will guarantee that AWVALID == WVALID
+//		(You can connect AWVALID to WVALID when connecting to your core)
+//	4. The controller will also guarantee that BREADY = 1
+//		(This core doesn't have a BVALID input)
+//
+//	Read interface
+//	1. The slave must guarantee that ARREADY == 1
+//		(This core doesn't have an ARREADY input)
+//	2. The slave must also guarantee that RVALID == $past(ARVALID)
+//		(This core doesn't have an RVALID input, trusting the slave
+//			instead)
+//	3. The controller will guarantee that RREADY = 1
+//		(This core doesn't have an RREADY output)
+//
+//	In this simplified controller, the AxADDR lines have been dropped.
+//	Slaves may only have one address, and that one will be aligned with the
+//	  bus width
+//
+//
+//	Why?  This simplifies slave logic.  Slaves may interact with the bus
+//	using only the logic below:
+//
+//		always @(posedge S_AXI_ACLK)
+//		if (AWVALID)
+//		begin
+//			if (WSTRB[0])
+//				slvreg[ 7: 0] <= WDATA[ 7: 0];
+//			if (WSTRB[1])
+//				slvreg[15: 8] <= WDATA[15: 8];
+//			if (WSTRB[2])
+//				slvreg[23:16] <= WDATA[23:16];
+//			if (WSTRB[3])
+//				slvreg[31:24] <= WDATA[31:24];
+//		end
+//
+//		always @(*)
+//			BRESP = 2'b00;	// Or other constant, such as 2'b10
+//
+//		always @(posedge S_AXI_ACLK)
+//		if (ARVALID)
+//			RDATA <= slvreg;
+//
+//		always @(*)
+//			RRESP = 2'b00;	// Or other constant, such as 2'b10
+//
+//	This core will then keep track of the more complex bus logic,
+//	simplifying both slaves and connection logic.  Slaves with the more
+//	complicated (and proper/accurate) logic, but with only one bus address,
+//	and that follow the rules above, should have no problems with this
+//	additional logic.
+//
+// Performance:
+//
+//	This core can sustain one read/write per clock as long as the upstream
+//	AXI-Lite master keeps S_AXI_[BR]READY high.  If S_AXI_[BR]READY ever
+//	drops, there's some flexibility provided by the return FIFO, so the
+//	master might not notice a drop in throughput until the FIFO fills.
+//
+//	The more practical performance measure is the latency of this core.
+//	That is measured at four clocks contingent (again) on the master holding
+//	S_AXI_[BR]READY line high.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+// `ifdef	VERILATOR
+// `define	FORMAL
+// `endif
+//
+module	axilsingle #(
+		//
+		// NS is the number of slave interfaces
+		parameter	NS = 16,
+		//
+		parameter integer C_AXI_DATA_WIDTH = 32,
+		localparam integer C_AXI_ADDR_WIDTH = $clog2(NS)+$clog2(C_AXI_DATA_WIDTH)-3,
+		//
+		// AW, and DW, are short-hand abbreviations used locally.
+		localparam	AW = C_AXI_ADDR_WIDTH,
+		localparam	DW = C_AXI_DATA_WIDTH,
+		//
+		// LGFLEN specifies the log (based two) of the number of
+		// transactions that may need to be held outstanding internally.
+		// If you really want high throughput, and if you expect any
+		// back pressure at all, then increase LGFLEN.  Otherwise the
+		// default value of 3 (FIFO size = 8) should be sufficient
+		// to maintain full loading
+		parameter	LGFLEN=3,
+		//
+		// If set, OPT_LOWPOWER will set all unused registers, both
+		// internal and external, to zero anytime their corresponding
+		// *VALID bit is clear
+		parameter [0:0]	OPT_LOWPOWER = 0
+	) (
+		input	wire				S_AXI_ACLK,
+		input	wire				S_AXI_ARESETN,
+		//
+		input	wire				S_AXI_AWVALID,
+		output	wire				S_AXI_AWREADY,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_AWADDR,
+		input	wire	[3-1:0]			S_AXI_AWPROT,
+		//
+		input	wire				S_AXI_WVALID,
+		output	wire				S_AXI_WREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]	S_AXI_WDATA,
+		input	wire [C_AXI_DATA_WIDTH/8-1:0]	S_AXI_WSTRB,
+		//
+		output	wire	[2-1:0]			S_AXI_BRESP,
+		output	wire				S_AXI_BVALID,
+		input	wire				S_AXI_BREADY,
+		//
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_ARADDR,
+		input	wire	[3-1:0]			S_AXI_ARPROT,
+		input	wire				S_AXI_ARVALID,
+		output	wire				S_AXI_ARREADY,
+		//
+		output	wire	[C_AXI_DATA_WIDTH-1:0]	S_AXI_RDATA,
+		output	wire	[2-1:0]			S_AXI_RRESP,
+		output	wire				S_AXI_RVALID,
+		input	wire				S_AXI_RREADY,
+		//
+		//
+		//
+		output	wire	[NS-1:0]		M_AXI_AWVALID,
+		output	wire	[3-1:0]			M_AXI_AWPROT,
+		//
+		output	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_WDATA,
+		output	wire [C_AXI_DATA_WIDTH/8-1:0]	M_AXI_WSTRB,
+		//
+		input	wire	[NS*2-1:0]		M_AXI_BRESP,
+		//
+		output	wire	[NS-1:0]		M_AXI_ARVALID,
+		output	wire	[3-1:0]			M_AXI_ARPROT,
+		//
+		input	wire [NS*C_AXI_DATA_WIDTH-1:0]	M_AXI_RDATA,
+		input	wire	[NS*2-1:0]		M_AXI_RRESP
+	);
+	//
+	//
+	localparam	LGNS = $clog2(NS);
+	//
+	localparam	INTERCONNECT_ERROR = 2'b11;
+	localparam	ADDR_LSBS = $clog2(DW)-3;
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write logic:
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	wire			awskid_valid, bffull, bempty, write_awskidready;
+	reg			write_bvalid, write_response;
+	reg			bfull, write_wready;
+	wire	[AW-ADDR_LSBS-1:0]	awskid_addr;
+	reg	[AW-ADDR_LSBS-1:0]	write_windex, write_bindex;
+	wire	[3-1:0]		awskid_prot;
+	reg	[3-1:0]		m_axi_awprot;
+	wire	[LGFLEN:0]	bfill;
+	reg	[LGFLEN:0]	write_count;
+	reg	[1:0]		write_resp;
+	reg	[NS-1:0]	m_axi_awvalid;
+
+	skidbuffer #(.OPT_LOWPOWER(OPT_LOWPOWER), .OPT_OUTREG(0),
+			.DW((AW-ADDR_LSBS)+3))
+	awskid(	.i_clk(S_AXI_ACLK),
+		.i_reset(!S_AXI_ARESETN),
+		.i_valid(S_AXI_AWVALID),
+			.o_ready(S_AXI_AWREADY),
+			.i_data({ S_AXI_AWPROT, S_AXI_AWADDR[AW-1:ADDR_LSBS] }),
+		.o_valid(awskid_valid), .i_ready(write_awskidready),
+			.o_data({ awskid_prot, awskid_addr }));
+
+	initial	write_wready = 0;
+	initial	m_axi_awvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		{ write_wready, m_axi_awvalid } <= 0;
+	else if (awskid_valid && write_awskidready)
+	begin
+		m_axi_awvalid <= 0;
+		m_axi_awvalid <= (1<<awskid_addr);
+		// if (awskid_addr >= NS)
+		//	m_axi_awvalid[NS] <= 1'b1;
+
+		write_wready <= 1;
+	end else if (S_AXI_WVALID)
+		{ write_wready, m_axi_awvalid } <= 0;
+
+	assign	S_AXI_WREADY = write_wready;
+
+	always @(posedge S_AXI_ACLK)
+	if (awskid_valid && write_awskidready)
+	begin
+		m_axi_awprot <= awskid_prot;
+		write_windex <= awskid_addr;
+	end
+
+	assign M_AXI_AWVALID = (S_AXI_WVALID) ? m_axi_awvalid : {(NS){1'b0}};
+	assign M_AXI_AWPROT = m_axi_awprot;
+	assign S_AXI_WREADY = write_wready;
+	assign	M_AXI_WDATA = S_AXI_WDATA;
+	assign	M_AXI_WSTRB = S_AXI_WSTRB;
+		
+	assign	write_awskidready = (!write_wready || S_AXI_WVALID) && !bfull;
+
+	initial	{ write_response, write_bvalid } = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		{ write_response, write_bvalid } <= 0;
+	else
+		{ write_response, write_bvalid }
+			<= { write_bvalid, (S_AXI_WVALID && S_AXI_WREADY) };
+
+	always @(posedge S_AXI_ACLK)
+		write_bindex <= write_windex;
+
+	generate if (LGNS == $clog2(NS+1))
+	begin
+		always @(posedge S_AXI_ACLK)
+		if (write_bindex >= NS)
+			write_resp <= INTERCONNECT_ERROR;
+		else
+			write_resp <= M_AXI_BRESP[2*write_bindex +: 2];
+	end else begin
+		always @(posedge S_AXI_ACLK)
+			write_resp <= M_AXI_BRESP[2*write_bindex +: 2];
+	end endgenerate
+
+	initial	write_count = 0;
+	initial	bfull = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		write_count <= 0;
+		bfull <= 0;
+	end else case({ (awskid_valid && write_awskidready),
+			(S_AXI_BVALID & S_AXI_BREADY) })
+	2'b01:	begin
+		write_count <= write_count - 1;
+		bfull <= 1'b0;
+		end
+	2'b10:	begin
+		write_count <= write_count + 1;
+		bfull <= (&write_count[LGFLEN-1:0]);
+		end
+	default: begin end
+	endcase
+
+`ifdef	FORMAL
+	always @(*)
+		assert(write_count <= { 1'b1, {(LGFLEN){1'b0}} });
+	always @(*)
+		assert(bfull == (write_count == { 1'b1, {(LGFLEN){1'b0}} }));
+`endif
+
+	sfifo #(.BW(2), .OPT_ASYNC_READ(0), .LGFLEN(LGFLEN))
+	bfifo ( .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_wr(write_response), .i_data(write_resp), .o_full(bffull),
+			.o_fill(bfill),
+		.i_rd(S_AXI_BVALID && S_AXI_BREADY), .o_data(S_AXI_BRESP),
+			.o_empty(bempty));
+
+`ifdef	FORMAL
+	always @(*)
+		assert(write_count == bfill
+			+ (write_response ? 1:0)
+			+ (write_bvalid ? 1:0)
+			+ (write_wready ? 1:0));
+
+`ifdef	VERIFIC
+	always @(*)
+	if (bfifo.f_first_in_fifo)
+		assert(bfifo.f_first_data != 2'b01);
+	always @(*)
+	if (bfifo.f_second_in_fifo)
+		assert(bfifo.f_second_data != 2'b01);
+	always @(*)
+	if (!bempty && (bfifo.rd_addr != bfifo.f_first_addr)
+			&&(bfifo.rd_addr != bfifo.f_second_addr))
+		assume(S_AXI_BRESP != 2'b01);
+`else
+	always @(*)
+	if (!bempty)
+		assume(S_AXI_BRESP != 2'b01);
+`endif
+`endif
+
+	assign	S_AXI_BVALID = !bempty;
+
+`ifdef	FORMAL
+	always @(*)
+		assert(!bffull || !write_bvalid);
+`endif
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read logic
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	wire				rempty, rdfull;
+	wire	[LGFLEN:0]		rfill;
+	reg	[AW-ADDR_LSBS-1:0]	read_index, last_read_index;
+	reg	[1:0]			read_resp;
+	reg	[DW-1:0]		read_rdata;
+	reg				read_rwait, read_rvalid, read_result;
+	reg	[NS-1:0]		m_axi_arvalid;
+	reg	[3-1:0]			m_axi_arprot;
+
+	initial	{ m_axi_arvalid, read_rwait } = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		{ m_axi_arvalid, read_rwait } <= 0;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY)
+	begin
+		m_axi_arvalid <= (1 << S_AXI_ARADDR[AW-1:ADDR_LSBS]);
+		read_rwait    <= 1'b1;
+	end else
+		{ m_axi_arvalid, read_rwait } <= 0;
+
+	always @(posedge S_AXI_ACLK)
+	begin
+		m_axi_arprot  <= S_AXI_ARPROT;
+		read_index    <= S_AXI_ARADDR[AW-1:ADDR_LSBS];
+	end
+
+	assign	M_AXI_ARVALID = m_axi_arvalid;
+	assign	M_AXI_ARPROT  = m_axi_arprot;
+
+	initial	{ read_result, read_rvalid } = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		{ read_result, read_rvalid } <= 2'b00;
+	else
+		{ read_result, read_rvalid } <= { read_rvalid, read_rwait };
+
+	always @(posedge S_AXI_ACLK)
+		last_read_index <= read_index;
+
+	always @(posedge S_AXI_ACLK)
+		read_rdata <= M_AXI_RDATA[DW*last_read_index +: DW];
+
+	generate if (LGNS == $clog2(NS+1))
+	begin
+		always @(posedge S_AXI_ACLK)
+		if (last_read_index >= NS)
+			read_resp <= INTERCONNECT_ERROR;
+		else
+			read_resp <= M_AXI_RRESP[2*last_read_index +: 2];
+	end else begin
+		always @(posedge S_AXI_ACLK)
+			read_resp <= M_AXI_RRESP[2*last_read_index +: 2];
+	end endgenerate
+
+	reg			read_full;
+	reg	[LGFLEN:0]	read_count;
+
+	initial	{ read_count, read_full } = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		{ read_count, read_full } <= 0;
+	else case({ S_AXI_ARVALID & S_AXI_ARREADY, S_AXI_RVALID & S_AXI_RREADY})
+	2'b10: begin
+		read_count <= read_count + 1;
+		read_full  <= &read_count[LGFLEN-1:0];
+		end
+	2'b01: begin
+		read_count <= read_count - 1;
+		read_full <= 1'b0;
+		end
+	default: begin end
+	endcase
+
+`ifdef	FORMAL
+	always @(*)
+		assert(read_count <= { 1'b1, {(LGFLEN){1'b0}} });
+	always @(*)
+		assert(read_full == (read_count == { 1'b1, {(LGFLEN){1'b0}} }));
+`endif
+	assign	S_AXI_ARREADY = !read_full;
+
+	sfifo #(.BW(DW+2), .OPT_ASYNC_READ(0), .LGFLEN(LGFLEN))
+	rfifo ( .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_wr(read_result), .i_data({ read_rdata, read_resp }),
+			.o_full(rdfull), .o_fill(rfill),
+		.i_rd(S_AXI_RVALID && S_AXI_RREADY),
+			.o_data({ S_AXI_RDATA, S_AXI_RRESP }),.o_empty(rempty));
+
+`ifdef	FORMAL
+	always @(*)
+		assert(read_count == rfill + read_result + read_rvalid + read_rwait);
+`ifdef	VERIFIC
+	always @(*)
+	if (rfifo.f_first_in_fifo)
+		assert(rfifo.f_first_data[1:0] != 2'b01);
+	always @(*)
+	if (rfifo.f_second_in_fifo)
+		assert(rfifo.f_second_data[1:0] != 2'b01);
+	always @(*)
+	if (!rempty && (rfifo.rd_addr != rfifo.f_first_addr)
+			&&(rfifo.rd_addr != rfifo.f_second_addr))
+		assume(S_AXI_RRESP != 2'b01);
+`else
+	always @(*)
+	if (!rempty)
+		assume(S_AXI_RRESP != 2'b01);
+`endif
+`endif
+
+	assign	S_AXI_RVALID = !rempty;
+
+	// verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0,
+			S_AXI_AWADDR[ADDR_LSBS-1:0],
+			S_AXI_ARADDR[ADDR_LSBS-1:0],
+			bffull, rdfull, bfill, rfill };
+	// verilator lint_on  UNUSED
+`ifdef	FORMAL
+	localparam	F_LGDEPTH = LGFLEN+1;
+	reg	f_past_valid;
+	reg	[F_LGDEPTH-1:0]	count_awr_outstanding, count_wr_outstanding,
+				count_rd_outstanding;
+
+
+	wire	[(F_LGDEPTH-1):0]	f_axi_awr_outstanding,
+					f_axi_wr_outstanding,
+					f_axi_rd_outstanding;
+
+	wire	[1:0]	fm_axi_awr_outstanding [0:NS-1];
+	wire	[1:0]	fm_axi_wr_outstanding [0:NS-1];
+	wire	[1:0]	fm_axi_rd_outstanding [0:NS-1];
+
+	reg [NS-1:0]	m_axi_rvalid, m_axi_bvalid;
+
+	faxil_slave #(// .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+			.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+			// .F_OPT_NO_READS(1'b0),
+			// .F_OPT_NO_WRITES(1'b0),
+			.F_OPT_XILINX(1),
+			.F_LGDEPTH(F_LGDEPTH))
+		properties (
+		.i_clk(S_AXI_ACLK),
+		.i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXI_AWVALID),
+		.i_axi_awready(S_AXI_AWREADY),
+		.i_axi_awaddr(S_AXI_AWADDR),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot(S_AXI_AWPROT),
+		//
+		.i_axi_wvalid(S_AXI_WVALID),
+		.i_axi_wready(S_AXI_WREADY),
+		.i_axi_wdata(S_AXI_WDATA),
+		.i_axi_wstrb(S_AXI_WSTRB),
+		//
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+		.i_axi_bresp(S_AXI_BRESP),
+		//
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+		.i_axi_araddr(S_AXI_ARADDR),
+		.i_axi_arprot(S_AXI_ARPROT),
+		.i_axi_arcache(4'h0),
+		//
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rready(S_AXI_RREADY),
+		.i_axi_rdata(S_AXI_RDATA),
+		.i_axi_rresp(S_AXI_RRESP),
+		//
+		.f_axi_rd_outstanding(f_axi_rd_outstanding),
+		.f_axi_wr_outstanding(f_axi_wr_outstanding),
+		.f_axi_awr_outstanding(f_axi_awr_outstanding));
+
+	initial	f_past_valid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1'b1;
+
+	genvar	M;
+	generate for(M=0; M<NS; M=M+1)
+	begin : CONSTRAIN_SLAVE_INTERACTIONS
+
+		faxil_master #(// .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+				.C_AXI_ADDR_WIDTH(1),
+				.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+				// .F_OPT_NO_READS(1'b0),
+				// .F_OPT_NO_WRITES(1'b0),
+				.F_OPT_NO_RESET(1'b1),
+				.F_LGDEPTH(2))
+			properties (
+			.i_clk(S_AXI_ACLK),
+			.i_axi_reset_n(S_AXI_ARESETN),
+			//
+			.i_axi_awvalid(M_AXI_AWVALID[M]),
+			.i_axi_awready(1'b1),
+			.i_axi_awaddr(1'b0),
+			.i_axi_awcache(4'h0),
+			.i_axi_awprot(M_AXI_AWPROT),
+			//
+			.i_axi_wvalid(M_AXI_AWVALID[M]),
+			.i_axi_wready(1'b1),
+			.i_axi_wdata(M_AXI_WDATA[C_AXI_DATA_WIDTH-1:0]),
+			.i_axi_wstrb(M_AXI_WSTRB[C_AXI_DATA_WIDTH/8-1:0]),
+			//
+			.i_axi_bvalid(m_axi_bvalid[M]),
+			.i_axi_bready(1'b1),
+			.i_axi_bresp(M_AXI_BRESP[2*M +: 2]),
+			//
+			.i_axi_arvalid(M_AXI_ARVALID[M]),
+			.i_axi_arready(1'b1),
+			.i_axi_araddr(1'b0),
+			.i_axi_arprot(M_AXI_ARPROT),
+			.i_axi_arcache(4'h0),
+			//
+			.i_axi_rdata(M_AXI_RDATA[M*C_AXI_DATA_WIDTH +: C_AXI_DATA_WIDTH]),
+			.i_axi_rresp(M_AXI_RRESP[2*M +: 2]),
+			.i_axi_rvalid(m_axi_rvalid[M]),
+			.i_axi_rready(1'b1),
+			//
+			.f_axi_rd_outstanding(fm_axi_rd_outstanding[M]),
+			.f_axi_wr_outstanding(fm_axi_wr_outstanding[M]),
+			.f_axi_awr_outstanding(fm_axi_awr_outstanding[M]));
+
+		initial	m_axi_bvalid <= 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			m_axi_bvalid[M] <= 1'b0;
+		else
+			m_axi_bvalid[M] <= M_AXI_AWVALID[M];
+
+		initial	m_axi_rvalid[M] <= 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			m_axi_rvalid[M] <= 1'b0;
+		else
+			m_axi_rvalid[M] <= M_AXI_ARVALID[M];
+
+		always @(*)
+			assert(fm_axi_awr_outstanding[M] == fm_axi_wr_outstanding[M]);
+
+		always @(*)
+			assert(fm_axi_wr_outstanding[M]== (m_axi_bvalid[M] ? 1:0));
+
+		always @(*)
+			assert(fm_axi_rd_outstanding[M]== (m_axi_rvalid[M] ? 1:0));
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Properties necessary to pass induction
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(*)
+		assert(S_AXI_WREADY == (m_axi_awvalid != 0));
+`ifdef	VERIFIC
+	always @(*)
+		assert($onehot0(M_AXI_AWVALID));
+
+	always @(*)
+		assert($onehot0(m_axi_bvalid));
+
+	always @(*)
+		assert($onehot0(m_axi_rvalid));
+`endif
+	always @(*)
+	if (S_AXI_WREADY)
+		assert(M_AXI_AWPROT == 0);
+	always @(*)
+	begin
+		count_awr_outstanding = 0;
+		if (!S_AXI_AWREADY)
+			count_awr_outstanding = count_awr_outstanding + 1;
+		if (write_wready)
+			count_awr_outstanding = count_awr_outstanding + 1;
+		if (write_bvalid)
+			count_awr_outstanding = count_awr_outstanding + 1;
+		if (write_response)
+			count_awr_outstanding = count_awr_outstanding + 1;
+		count_awr_outstanding = count_awr_outstanding + bfill;
+	end
+
+	always @(*)
+	if (S_AXI_ARESETN)
+		assert(f_axi_awr_outstanding == count_awr_outstanding);
+
+	always @(*)
+	begin
+		count_wr_outstanding = 0;
+		if (write_bvalid)
+			count_wr_outstanding = count_wr_outstanding + 1;
+		if (write_response)
+			count_wr_outstanding = count_wr_outstanding + 1;
+		count_wr_outstanding = count_wr_outstanding + bfill;
+	end
+
+	always @(*)
+	if (S_AXI_ARESETN)
+		assert(f_axi_wr_outstanding == count_wr_outstanding);
+
+	//
+	//
+	//
+	always @(*)
+	begin
+		count_rd_outstanding = 0;
+		if (read_rwait)
+			count_rd_outstanding = count_rd_outstanding + 1;
+		if (read_rvalid)
+			count_rd_outstanding = count_rd_outstanding + 1;
+		if (read_result)
+			count_rd_outstanding = count_rd_outstanding + 1;
+		count_rd_outstanding = count_rd_outstanding + rfill;
+	end
+
+	always @(*)
+	if (S_AXI_ARESETN)
+		assert(f_axi_rd_outstanding == count_rd_outstanding);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	[3:0]	cvr_arvalids, cvr_awvalids, cvr_reads, cvr_writes;
+
+	initial	cvr_awvalids = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_awvalids <= 0;
+	else if (S_AXI_AWVALID && S_AXI_AWREADY && !(&cvr_awvalids))
+		cvr_awvalids <= cvr_awvalids + 1;
+
+	initial	cvr_arvalids = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_arvalids <= 0;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY && !(&cvr_arvalids))
+		cvr_arvalids <= cvr_arvalids + 1;
+
+	initial	cvr_writes = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_writes <= 0;
+	else if (S_AXI_BVALID && S_AXI_BREADY && !(&cvr_writes))
+		cvr_writes <= cvr_writes + 1;
+
+	initial	cvr_reads = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_reads <= 0;
+	else if (S_AXI_RVALID && S_AXI_RREADY && !(&cvr_arvalids))
+		cvr_reads <= cvr_reads + 1;
+
+	always @(*)
+		cover(cvr_awvalids > 4);
+
+	always @(*)
+		cover(cvr_arvalids > 4);
+
+	always @(*)
+		cover(cvr_reads > 4);
+
+	always @(*)
+		cover(cvr_writes > 4);
+
+	always @(*)
+		cover((cvr_writes > 4) && (cvr_reads > 4));
+`endif
+endmodule
+// `ifndef	YOSYS
+// `default_nettype wire
+// `endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axilwr2wbsp.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilwr2wbsp.v
new file mode 100644
index 0000000..b9cc152
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilwr2wbsp.v
@@ -0,0 +1,591 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axilwr2wbsp.v (AXI lite to wishbone slave, read channel)
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Bridge an AXI lite write channel triplet to a single wishbone
+//		write channel.  A full AXI lite to wishbone bridge will also
+//	require the read channel and an arbiter.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2016-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module	axilwr2wbsp(i_clk, i_axi_reset_n,
+	// AXI write address channel signals
+	o_axi_awready, i_axi_awaddr, i_axi_awcache, i_axi_awprot, i_axi_awvalid,
+	// AXI write data channel signals
+	o_axi_wready, i_axi_wdata, i_axi_wstrb, i_axi_wvalid,
+	// AXI write response channel signals
+	o_axi_bresp, o_axi_bvalid, i_axi_bready,
+	// We'll share the clock and the reset
+	o_wb_cyc, o_wb_stb, o_wb_addr, o_wb_data, o_wb_sel,
+		i_wb_ack, i_wb_stall, i_wb_err
+`ifdef	FORMAL
+	, f_first, f_mid, f_last, f_wpending
+`endif
+	);
+	parameter C_AXI_DATA_WIDTH	= 32;// Width of the AXI R&W data
+	parameter C_AXI_ADDR_WIDTH	= 28;	// AXI Address width
+	localparam AW			= C_AXI_ADDR_WIDTH-2;// WB Address width
+	parameter LGFIFO                =  3;
+	localparam	DW = C_AXI_DATA_WIDTH;
+	localparam	FLEN=(1<<LGFIFO);
+	localparam	AXI_LSBS = $clog2(C_AXI_DATA_WIDTH)-3;
+
+
+	input	wire			i_clk;	// Bus clock
+	input	wire			i_axi_reset_n;	// Bus reset
+
+	// AXI write address channel signals
+	output	reg			o_axi_awready;//Slave is ready to accept
+	input	wire	[AW+1:0]	i_axi_awaddr;	// Write address
+	input	wire	[3:0]		i_axi_awcache;	// Write Cache type
+	input	wire	[2:0]		i_axi_awprot;	// Write Protection type
+	input	wire			i_axi_awvalid;	// Write address valid
+
+	// AXI write data channel signals
+	output	reg			o_axi_wready;  // Write data ready
+	input	wire	[DW-1:0]	i_axi_wdata;	// Write data
+	input	wire	[DW/8-1:0]	i_axi_wstrb;	// Write strobes
+	input	wire			i_axi_wvalid;	// Write valid
+
+	// AXI write response channel signals
+	output	reg	[1:0]		o_axi_bresp;	// Write response
+	output	reg			o_axi_bvalid;  // Write reponse valid
+	input	wire			i_axi_bready;  // Response ready
+
+	// We'll share the clock and the reset
+	output	reg				o_wb_cyc;
+	output	reg				o_wb_stb;
+	output	reg	[(AW-1):0]		o_wb_addr;
+	output	reg	[(DW-1):0]		o_wb_data;
+	output	reg	[(DW/8-1):0]		o_wb_sel;
+	input	wire				i_wb_ack;
+	input	wire				i_wb_stall;
+	input	wire				i_wb_err;
+`ifdef	FORMAL
+	// Output connections only used in formal mode
+	output	wire	[LGFIFO:0]		f_first;
+	output	wire	[LGFIFO:0]		f_mid;
+	output	wire	[LGFIFO:0]		f_last;
+	output	wire	[1:0]			f_wpending;
+`endif
+
+	wire	w_reset;
+	assign	w_reset = (!i_axi_reset_n);
+
+	reg			r_awvalid, r_wvalid;
+	reg	[AW-1:0]	r_addr;
+	reg	[DW-1:0]	r_data;
+	reg	[DW/8-1:0]	r_sel;
+
+	reg			fifo_full, fifo_empty;
+
+	reg	[LGFIFO:0]	r_first, r_mid, r_last;
+	wire	[LGFIFO:0]	next_first, next_last;
+	reg			wb_pending;
+	reg	[LGFIFO:0]	wb_outstanding;
+
+	reg	[LGFIFO:0]	err_loc;
+	reg			err_state;
+
+	wire	axi_write_accepted, pending_axi_write;
+
+	assign	pending_axi_write =
+		((r_awvalid) || (i_axi_awvalid && o_axi_awready))
+		&&((r_wvalid)|| (i_axi_wvalid && o_axi_wready));
+
+	assign	axi_write_accepted =
+		(!o_wb_stb || !i_wb_stall) && (!fifo_full) && (!err_state)
+			&& (pending_axi_write);
+
+	initial	o_wb_cyc = 1'b0;
+	initial	o_wb_stb = 1'b0;
+	always @(posedge i_clk)
+	if ((w_reset)||((o_wb_cyc)&&(i_wb_err))||(err_state))
+		o_wb_stb <= 1'b0;
+	else if (axi_write_accepted)
+		o_wb_stb <= 1'b1;
+	else if ((o_wb_cyc)&&(!i_wb_stall))
+		o_wb_stb <= 1'b0;
+
+	always @(*)
+		o_wb_cyc = (wb_pending)||(o_wb_stb);
+
+	always @(posedge i_clk)
+	if (!o_wb_stb || !i_wb_stall)
+	begin
+		if (r_awvalid)
+			o_wb_addr <= r_addr;
+		else
+			o_wb_addr <= i_axi_awaddr[AW+1:AXI_LSBS];
+
+		if (r_wvalid)
+		begin
+			o_wb_data <= r_data;
+			o_wb_sel  <= r_sel;
+		end else begin
+			o_wb_data <= i_axi_wdata;
+			o_wb_sel  <= i_axi_wstrb;
+		end
+	end
+
+	initial	r_awvalid = 1'b0;
+	always @(posedge i_clk)
+	begin
+		if ((i_axi_awvalid)&&(o_axi_awready))
+		begin
+			r_addr <= i_axi_awaddr[AW+1:AXI_LSBS];
+			r_awvalid <= (!axi_write_accepted);
+		end else if (axi_write_accepted)
+			r_awvalid <= 1'b0;
+
+		if (w_reset)
+			r_awvalid <= 1'b0;
+	end
+
+	initial	r_wvalid = 1'b0;
+	always @(posedge i_clk)
+	begin
+		if ((i_axi_wvalid)&&(o_axi_wready))
+		begin
+			r_data <= i_axi_wdata;
+			r_sel  <= i_axi_wstrb;
+			r_wvalid <= (!axi_write_accepted);
+		end else if (axi_write_accepted)
+			r_wvalid <= 1'b0;
+
+		if (w_reset)
+			r_wvalid <= 1'b0;
+	end
+
+	initial	o_axi_awready = 1'b1;
+	always @(posedge i_clk)
+	if (w_reset)
+		o_axi_awready <= 1'b1;
+	else if ((o_wb_stb && i_wb_stall)
+			&&(r_awvalid || (i_axi_awvalid && o_axi_awready)))
+		// Once a request has been received while the interface is
+		// stalled, we must stall and wait for it to clear
+		o_axi_awready <= 1'b0;
+	else if (err_state && (r_awvalid || (i_axi_awvalid && o_axi_awready)))
+		o_axi_awready <= 1'b0;
+	else if ((r_awvalid || (i_axi_awvalid && o_axi_awready))
+		&&(!r_wvalid && (!i_axi_wvalid || !o_axi_wready)))
+		// If the write address is given without any corresponding
+		// write data, immediately stall and wait for the write data
+		o_axi_awready <= 1'b0;
+	else if (!o_axi_awready && o_wb_stb && i_wb_stall)
+		// Once stalled, remain stalled while the WB bus is stalled
+		o_axi_awready <= 1'b0;
+	else if (fifo_full && (r_awvalid || (!o_axi_bvalid || !i_axi_bready)))
+		// Once the FIFO is full, we must remain stalled until at
+		// least one acknowledgment has been accepted
+		o_axi_awready <= 1'b0;
+	else if ((!o_axi_bvalid || !i_axi_bready)
+			&& (r_awvalid || (i_axi_awvalid && o_axi_awready)))
+		// If ever the FIFO becomes full, we must immediately drop
+		// the o_axi_awready signal
+		o_axi_awready  <= (next_first[LGFIFO-1:0] != r_last[LGFIFO-1:0])
+					&&(next_first[LGFIFO]==r_last[LGFIFO]);
+	else
+		o_axi_awready <= 1'b1;
+
+	initial	o_axi_wready = 1'b1;
+	always @(posedge i_clk)
+	if (w_reset)
+		o_axi_wready <= 1'b1;
+	else if ((o_wb_stb && i_wb_stall)
+			&&(r_wvalid || (i_axi_wvalid && o_axi_wready)))
+		// Once a request has been received while the interface is
+		// stalled, we must stall and wait for it to clear
+		o_axi_wready <= 1'b0;
+	else if (err_state && (r_wvalid || (i_axi_wvalid && o_axi_wready)))
+		o_axi_wready <= 1'b0;
+	else if ((r_wvalid || (i_axi_wvalid && o_axi_wready))
+		&&(!r_awvalid && (!i_axi_awvalid || !o_axi_awready)))
+		// If the write address is given without any corresponding
+		// write data, immediately stall and wait for the write data
+		o_axi_wready <= 1'b0;
+	else if (!o_axi_wready && o_wb_stb && i_wb_stall)
+		// Once stalled, remain stalled while the WB bus is stalled
+		o_axi_wready <= 1'b0;
+	else if (fifo_full && (r_wvalid || (!o_axi_bvalid || !i_axi_bready)))
+		// Once the FIFO is full, we must remain stalled until at
+		// least one acknowledgment has been accepted
+		o_axi_wready <= 1'b0;
+	else if ((!o_axi_bvalid || !i_axi_bready)
+			&& (i_axi_wvalid && o_axi_wready))
+		// If ever the FIFO becomes full, we must immediately drop
+		// the o_axi_wready signal
+		o_axi_wready  <= (next_first[LGFIFO-1:0] != r_last[LGFIFO-1:0])
+					&&(next_first[LGFIFO]==r_last[LGFIFO]);
+	else
+		o_axi_wready <= 1'b1;
+
+
+	initial	wb_pending     = 0;
+	initial	wb_outstanding = 0;
+	always @(posedge i_clk)
+	if ((w_reset)||(!o_wb_cyc)||(i_wb_err)||(err_state))
+	begin
+		wb_pending     <= 1'b0;
+		wb_outstanding <= 0;
+	end else case({ (o_wb_stb)&&(!i_wb_stall), i_wb_ack })
+	2'b01: begin
+		wb_outstanding <= wb_outstanding - 1'b1;
+		wb_pending <= (wb_outstanding >= 2);
+		end
+	2'b10: begin
+		wb_outstanding <= wb_outstanding + 1'b1;
+		wb_pending <= 1'b1;
+		end
+	default: begin end
+	endcase
+
+	assign	next_first = r_first + 1'b1;
+	assign	next_last  = r_last + 1'b1;
+
+	initial	fifo_full  = 1'b0;
+	initial	fifo_empty = 1'b1;
+	always @(posedge i_clk)
+	if (w_reset)
+	begin
+		fifo_full  <= 1'b0;
+		fifo_empty <= 1'b1;
+	end else case({ (o_axi_bvalid)&&(i_axi_bready),
+				(axi_write_accepted) })
+	2'b01: begin
+		fifo_full  <= (next_first[LGFIFO-1:0] == r_last[LGFIFO-1:0])
+					&&(next_first[LGFIFO]!=r_last[LGFIFO]);
+		fifo_empty <= 1'b0;
+		end
+	2'b10: begin
+		fifo_full <= 1'b0;
+		fifo_empty <= 1'b0;
+		end
+	default: begin end
+	endcase
+
+	initial	r_first = 0;
+	always @(posedge i_clk)
+	if (w_reset)
+		r_first <= 0;
+	else if (axi_write_accepted)
+		r_first <= r_first + 1'b1;
+
+	initial	r_mid = 0;
+	always @(posedge i_clk)
+	if (w_reset)
+		r_mid <= 0;
+	else if ((o_wb_cyc)&&((i_wb_ack)||(i_wb_err)))
+		r_mid <= r_mid + 1'b1;
+	else if ((err_state)&&(r_mid != r_first))
+		r_mid <= r_mid + 1'b1;
+
+	initial	r_last = 0;
+	always @(posedge i_clk)
+	if (w_reset)
+		r_last <= 0;
+	else if ((o_axi_bvalid)&&(i_axi_bready))
+		r_last <= r_last + 1'b1;
+
+	always @(posedge i_clk)
+	if ((o_wb_cyc)&&(i_wb_err))
+		err_loc <= r_mid;
+
+	initial	o_axi_bresp = 2'b00;
+	always @(posedge i_clk)
+	if (w_reset)
+		o_axi_bresp <= 0;
+	else if ((!o_axi_bvalid)||(i_axi_bready))
+	begin
+		if ((!err_state)&&((!o_wb_cyc)||(!i_wb_err)))
+			o_axi_bresp <= 2'b00;
+		else if ((!err_state)&&(o_wb_cyc)&&(i_wb_err))
+		begin
+			if (o_axi_bvalid)
+				o_axi_bresp <= (r_mid == next_last) ? 2'b10 : 2'b00;
+			else
+				o_axi_bresp <= (r_mid == r_last) ? 2'b10 : 2'b00;
+		end else if (err_state)
+		begin
+			if (next_last == err_loc)
+				o_axi_bresp <= 2'b10;
+			else if (o_axi_bresp[1])
+				o_axi_bresp <= 2'b11;
+		end else
+			o_axi_bresp <= 0;
+	end
+
+
+	initial err_state  = 0;
+	always @(posedge i_clk)
+	if (w_reset)
+		err_state <= 0;
+	else if (r_first == r_last)
+		err_state <= 0;
+	else if ((o_wb_cyc)&&(i_wb_err))
+		err_state <= 1'b1;
+
+	initial	o_axi_bvalid = 1'b0;
+	always @(posedge i_clk)
+	if (w_reset)
+		o_axi_bvalid <= 0;
+	else if ((o_wb_cyc)&&((i_wb_ack)||(i_wb_err)))
+		o_axi_bvalid <= 1'b1;
+	else if ((o_axi_bvalid)&&(i_axi_bready))
+	begin
+		if (err_state)
+			o_axi_bvalid <= (next_last != r_first);
+		else
+			o_axi_bvalid <= (next_last != r_mid);
+	end
+
+	// Make Verilator happy
+	// verilator lint_off UNUSED
+	wire	[9:0]	unused;
+	assign	unused = { i_axi_awcache, i_axi_awprot,
+				fifo_empty, i_axi_awaddr[AXI_LSBS-1:0] };
+	// verilator lint_on  UNUSED
+
+`ifdef	FORMAL
+	reg			f_past_valid;
+	wire			f_axi_stalled;
+	wire	[LGFIFO:0]	f_wb_nreqs, f_wb_nacks, f_wb_outstanding;
+	wire	[LGFIFO:0]	wb_fill;
+	wire	[LGFIFO:0]	f_axi_rd_outstanding,
+				f_axi_wr_outstanding,
+				f_axi_awr_outstanding;
+	wire	[LGFIFO:0]	f_mid_minus_err, f_err_minus_last,
+				f_first_minus_err;
+	wire	[LGFIFO:0]	f_fifo_fill;
+
+	initial f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+
+`ifdef	AXILWR2WBSP
+`define	ASSUME	assume
+`else
+`define	ASSUME	assert
+`endif
+
+	always @(*)
+	if (!f_past_valid)
+		`ASSUME(w_reset);
+
+	assign	f_fifo_fill  = (r_first - r_last);
+
+	always @(*)
+	if (err_state)
+	begin
+		assert(!r_awvalid || !o_axi_awready);
+		assert(!r_wvalid  || !o_axi_wready);
+
+		assert(!o_wb_cyc);
+	end
+
+	always @(*)
+	if ((fifo_empty)&&(!w_reset))
+		assert((!fifo_full)&&(r_first == r_last)&&(r_mid == r_last));
+
+	always @(*)
+	if (fifo_full)
+	begin
+		assert(!fifo_empty);
+		assert(r_first[LGFIFO-1:0] == r_last[LGFIFO-1:0]);
+		assert(r_first[LGFIFO] != r_last[LGFIFO]);
+	end
+
+	always @(*)
+		assert(f_fifo_fill <= (1<<LGFIFO));
+
+	always @(*)
+	if (fifo_full)
+	begin
+		assert(!r_awvalid || !o_axi_awready);
+		assert(!r_wvalid  || !o_axi_wready);
+	end
+
+	always @(*)
+		assert(fifo_full == (f_fifo_fill >= (1<<LGFIFO)));
+	always @(*)
+		assert(wb_pending == (wb_outstanding != 0));
+
+
+	assign	f_first    = r_first;
+	assign	f_mid      = r_mid;
+	assign	f_last     = r_last;
+	assign	f_wpending = { r_awvalid, r_wvalid };
+
+	fwb_master #(
+		.AW(AW), .DW(DW), .F_LGDEPTH(LGFIFO+1)
+		) fwb(i_clk, w_reset,
+		o_wb_cyc, o_wb_stb, 1'b1, o_wb_addr, o_wb_data, o_wb_sel,
+			i_wb_ack, i_wb_stall, {(DW){1'b0}}, i_wb_err,
+		f_wb_nreqs,f_wb_nacks, f_wb_outstanding);
+
+	always @(*)
+	if (o_wb_cyc)
+		assert(f_wb_outstanding == wb_outstanding);
+
+	always @(*)
+	if (o_wb_cyc)
+		assert(wb_outstanding <= (1<<LGFIFO));
+
+	assign	wb_fill = r_first - r_mid;
+	always @(*)
+		assert(wb_fill <= f_fifo_fill);
+	always @(*)
+	if (!w_reset)
+	begin
+		if (o_wb_stb)
+			assert(wb_outstanding+1 == wb_fill);
+		else if (o_wb_cyc)
+			assert(wb_outstanding == wb_fill);
+		else if (!err_state)
+			assert((wb_fill == 0)&&(wb_outstanding == 0));
+	end
+
+	faxil_slave #(
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.F_LGDEPTH(LGFIFO+1),
+		.F_OPT_WRITE_ONLY(1),
+		.F_AXI_MAXWAIT(0),
+		.F_AXI_MAXDELAY(0)
+		) faxil(i_clk, i_axi_reset_n,
+		//
+		// AXI write address channel signals
+		o_axi_awready, i_axi_awaddr, i_axi_awcache, i_axi_awprot, i_axi_awvalid,
+		// AXI write data channel signals
+		o_axi_wready, i_axi_wdata, i_axi_wstrb, i_axi_wvalid,
+		// AXI write response channel signals
+		o_axi_bresp, o_axi_bvalid, i_axi_bready,
+		// AXI read address channel signals
+		1'b0, i_axi_awaddr, i_axi_awcache, i_axi_awprot,
+			1'b0,
+		// AXI read data channel signals
+		o_axi_bresp, 1'b0, {(DW){1'b0}}, 1'b0,
+		f_axi_rd_outstanding, f_axi_wr_outstanding,
+		f_axi_awr_outstanding);
+
+	always @(*)
+		assert(f_axi_wr_outstanding - (r_wvalid ? 1:0)
+				== f_axi_awr_outstanding - (r_awvalid ? 1:0));
+	always @(*)
+		assert(f_axi_rd_outstanding == 0);
+	always @(*)
+		assert(f_axi_wr_outstanding - (r_wvalid ? 1:0) == f_fifo_fill);
+	always @(*)
+		assert(f_axi_awr_outstanding - (r_awvalid ? 1:0) == f_fifo_fill);
+	always @(*)
+		if (r_wvalid)  assert(f_axi_wr_outstanding > 0);
+	always @(*)
+		if (r_awvalid) assert(f_axi_awr_outstanding > 0);
+
+	assign	f_mid_minus_err  = f_mid - err_loc;
+	assign	f_err_minus_last = err_loc - f_last;
+	assign	f_first_minus_err = f_first - err_loc;
+	always @(*)
+	if (o_axi_bvalid)
+	begin
+		if (!err_state)
+			assert(!o_axi_bresp[1]);
+		else if (err_loc == f_last)
+			assert(o_axi_bresp == 2'b10);
+		else if (f_err_minus_last < (1<<LGFIFO))
+			assert(!o_axi_bresp[1]);
+		else
+			assert(o_axi_bresp[1]);
+	end
+
+	always @(*)
+	if (err_state)
+		assert(o_axi_bvalid == (r_first != r_last));
+	else
+		assert(o_axi_bvalid == (r_mid != r_last));
+
+	always @(*)
+	if (err_state)
+		assert(f_first_minus_err <= (1<<LGFIFO));
+
+	always @(*)
+	if (err_state)
+		assert(f_first_minus_err != 0);
+
+	always @(*)
+	if (err_state)
+		assert(f_mid_minus_err <= f_first_minus_err);
+
+	assign	f_axi_stalled = (fifo_full)||(err_state)
+				||((o_wb_stb)&&(i_wb_stall));
+
+	always @(*)
+	if ((r_awvalid)&&(f_axi_stalled))
+		assert(!o_axi_awready);
+	always @(*)
+	if ((r_wvalid)&&(f_axi_stalled))
+		assert(!o_axi_wready);
+
+
+	// WB covers
+	always @(*)
+		cover(o_wb_cyc && o_wb_stb && !i_wb_stall);
+	always @(*)
+		cover(o_wb_cyc && i_wb_ack);
+
+	always @(posedge i_clk)
+		cover(o_wb_cyc && $past(o_wb_cyc && o_wb_stb && !i_wb_stall));//
+
+	always @(posedge i_clk)
+		cover(o_wb_cyc && o_wb_stb && !i_wb_stall
+			&& $past(o_wb_cyc && o_wb_stb && !i_wb_stall,2)
+			&& $past(o_wb_cyc && o_wb_stb && !i_wb_stall,4)); //
+
+	always @(posedge i_clk)
+		cover(o_wb_cyc && o_wb_stb && !i_wb_stall
+			&& $past(o_wb_cyc && o_wb_stb && !i_wb_stall)
+			&& $past(o_wb_cyc && o_wb_stb && !i_wb_stall)); //
+
+	always @(posedge i_clk)
+		cover(o_wb_cyc && i_wb_ack
+			&& $past(o_wb_cyc && i_wb_ack)
+			&& $past(o_wb_cyc && i_wb_ack)); //
+
+	// AXI covers
+	always @(posedge i_clk)
+		cover(o_axi_bvalid && i_axi_bready
+			&& $past(o_axi_bvalid && i_axi_bready,1)
+			&& $past(o_axi_bvalid && i_axi_bready,2)); //
+
+`endif
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axilxbar.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilxbar.v
new file mode 100644
index 0000000..0e158b8
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axilxbar.v
@@ -0,0 +1,2207 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axilxbar.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Create a full crossbar between NM AXI-lite sources (masters),
+//		and NS AXI-lite slaves.  Every master can talk to any slave,
+//	provided it isn't already busy.
+//
+// Performance:	This core has been designed with the goal of being able to push
+//		one transaction through the interconnect, from any master to
+//	any slave, per clock cycle.  This may perhaps be its most unique
+//	feature.  While throughput is good, latency is something else.
+//
+//	The arbiter requires a clock to switch, then another clock to send data
+//	downstream.  This creates a minimum two clock latency up front.  The
+//	return path suffers another clock of latency as well, placing the
+//	minimum latency at four clocks.  The minimum write latency is at
+//	least one clock longer, since the write data must wait for the write
+//	address before proceeeding.
+//
+// Usage:	To use, you must first set NM and NS to the number of masters
+//	and the number of slaves you wish to connect to.  You then need to
+//	adjust the addresses of the slaves, found SLAVE_ADDR array.  Those
+//	bits that are relevant in SLAVE_ADDR to then also be set in SLAVE_MASK.
+//	Adjusting the data and address widths go without saying.
+//
+//	Lower numbered masters are given priority in any "fight".
+//
+//	Channel grants are given on the condition that 1) they are requested,
+//	2) no other channel has a grant, 3) all of the responses have been
+//	received from the current channel, and 4) the internal counters are
+//	not overflowing.
+//
+//	The core limits the number of outstanding transactions on any channel to
+//	1<<LGMAXBURST-1.
+//
+//	Channel grants are lost 1) after OPT_LINGER clocks of being idle, or
+//	2) when another master requests an idle (but still lingering) channel
+//	assignment, or 3) once all the responses have been returned to the
+//	current channel, and the current master is requesting another channel.
+//
+//	A special slave is allocated for the case of no valid address.
+//
+//	Since the write channel has no address information, the write data
+//	channel always be delayed by at least one clock from the write address
+//	channel.
+//
+//	If OPT_LOWPOWER is set, then unused values will be set to zero.
+//	This can also be used to help identify relevant values within any
+//	trace.
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+module	axilxbar #(
+		parameter integer C_AXI_DATA_WIDTH = 32,
+		parameter integer C_AXI_ADDR_WIDTH = 32,
+		//
+		// NM is the number of master interfaces this core supports
+		parameter	NM = 4,
+		//
+		// NS is the number of slave interfaces
+		parameter	NS = 8,
+		//
+		// AW, and DW, are short-hand abbreviations used locally.
+		localparam	AW = C_AXI_ADDR_WIDTH,
+		localparam	DW = C_AXI_DATA_WIDTH,
+		// SLAVE_ADDR is a bit vector containing AW bits for each of the
+		// slaves indicating the base address of the slave.  This
+		// goes with SLAVE_MASK below.
+		parameter	[NS*AW-1:0]	SLAVE_ADDR = {
+			3'b111,  {(AW-3){1'b0}},
+			3'b110,  {(AW-3){1'b0}},
+			3'b101,  {(AW-3){1'b0}},
+			3'b100,  {(AW-3){1'b0}},
+			3'b011,  {(AW-3){1'b0}},
+			3'b010,  {(AW-3){1'b0}},
+			4'b0001, {(AW-4){1'b0}},
+			4'b0000, {(AW-4){1'b0}} },
+		//
+		// SLAVE_MASK indicates which bits in the SLAVE_ADDR bit vector
+		// need to be checked to determine if a given address request
+		// maps to the given slave or not
+		// Verilator lint_off WIDTH
+		parameter	[NS*AW-1:0]	SLAVE_MASK =
+			(NS <= 1) ? { 4'b1111, {(AW-4){1'b0}}}
+			: { {(NS-2){ 3'b111, {(AW-3){1'b0}} }},
+				{(2){ 4'b1111, {(AW-4){1'b0}}}} },
+		// Verilator lint_on WIDTH
+		//
+		// If set, OPT_LOWPOWER will set all unused registers, both
+		// internal and external, to zero anytime their corresponding
+		// *VALID bit is clear
+		parameter [0:0]	OPT_LOWPOWER = 1,
+		//
+		// OPT_LINGER is the number of cycles to wait, following a
+		// transaction, before tearing down the bus grant.
+		parameter	OPT_LINGER = 4,
+		//
+		// LGMAXBURST is the log (base two) of the maximum number of
+		// requests that can be outstanding on any given channel at any
+		// given time.  It is used within this core to control the
+		// counters that are used to determine if a particular channel
+		// grant must stay open, or if it may be closed.
+		parameter	LGMAXBURST = 5
+	) (
+		input	wire	S_AXI_ACLK,
+		input	wire	S_AXI_ARESETN,
+		//
+		input	wire	[NM*C_AXI_ADDR_WIDTH-1:0]	S_AXI_AWADDR,
+		input	wire	[NM*3-1:0]			S_AXI_AWPROT,
+		input	wire	[NM-1:0]			S_AXI_AWVALID,
+		output	wire	[NM-1:0]			S_AXI_AWREADY,
+		//
+		input	wire	[NM*C_AXI_DATA_WIDTH-1:0]	S_AXI_WDATA,
+		input	wire	[NM*C_AXI_DATA_WIDTH/8-1:0]	S_AXI_WSTRB,
+		input	wire	[NM-1:0]			S_AXI_WVALID,
+		output	wire	[NM-1:0]			S_AXI_WREADY,
+		//
+		output	wire	[NM*2-1:0]			S_AXI_BRESP,
+		output	wire	[NM-1:0]			S_AXI_BVALID,
+		input	wire	[NM-1:0]			S_AXI_BREADY,
+		//
+		input	wire	[NM*C_AXI_ADDR_WIDTH-1:0]	S_AXI_ARADDR,
+		input	wire	[NM*3-1:0]			S_AXI_ARPROT,
+		input	wire	[NM-1:0]			S_AXI_ARVALID,
+		output	wire	[NM-1:0]			S_AXI_ARREADY,
+		//
+		output	wire	[NM*C_AXI_DATA_WIDTH-1:0]	S_AXI_RDATA,
+		output	wire	[NM*2-1:0]			S_AXI_RRESP,
+		output	wire	[NM-1:0]			S_AXI_RVALID,
+		input	wire	[NM-1:0]			S_AXI_RREADY,
+		//
+		//
+		//
+		output	wire	[NS*C_AXI_ADDR_WIDTH-1:0]	M_AXI_AWADDR,
+		output	wire	[NS*3-1:0]			M_AXI_AWPROT,
+		output	wire	[NS-1:0]			M_AXI_AWVALID,
+		input	wire	[NS-1:0]			M_AXI_AWREADY,
+		//
+		output	wire	[NS*C_AXI_DATA_WIDTH-1:0]	M_AXI_WDATA,
+		output	wire	[NS*C_AXI_DATA_WIDTH/8-1:0]	M_AXI_WSTRB,
+		output	wire	[NS-1:0]			M_AXI_WVALID,
+		input	wire	[NS-1:0]			M_AXI_WREADY,
+		//
+		input	wire	[NS*2-1:0]			M_AXI_BRESP,
+		input	wire	[NS-1:0]			M_AXI_BVALID,
+		output	wire	[NS-1:0]			M_AXI_BREADY,
+		//
+		output	wire	[NS*C_AXI_ADDR_WIDTH-1:0]	M_AXI_ARADDR,
+		output	wire	[NS*3-1:0]			M_AXI_ARPROT,
+		output	wire	[NS-1:0]			M_AXI_ARVALID,
+		input	wire	[NS-1:0]			M_AXI_ARREADY,
+		//
+		input	wire	[NS*C_AXI_DATA_WIDTH-1:0]	M_AXI_RDATA,
+		input	wire	[NS*2-1:0]			M_AXI_RRESP,
+		input	wire	[NS-1:0]			M_AXI_RVALID,
+		output	wire	[NS-1:0]			M_AXI_RREADY
+	);
+	//
+	// Local parameters, derived from those above
+	localparam	LGLINGER = (OPT_LINGER>1) ? $clog2(OPT_LINGER+1) : 1;
+	//
+	localparam	LGNM = (NM>1) ? $clog2(NM) : 1;
+	localparam	LGNS = (NS>1) ? $clog2(NS+1) : 1;
+	//
+	// In order to use indexes, and hence fully balanced mux trees, it helps
+	// to make certain that we have a power of two based lookup.  NMFULL
+	// is the number of masters in this lookup, with potentially some
+	// unused extra ones.  NSFULL is defined similarly.
+	localparam	NMFULL = (NM>1) ? (1<<LGNM) : 1;
+	localparam	NSFULL = (NS>1) ? (1<<LGNS) : 2;
+	//
+	localparam [1:0] INTERCONNECT_ERROR = 2'b11;
+	localparam [0:0]	OPT_SKID_INPUT = 0;
+	localparam [0:0]	OPT_BUFFER_DECODER = 1;
+
+	genvar	N,M;
+	integer	iN, iM;
+
+	reg	[NSFULL-1:0]	wrequest		[0:NM-1];
+	reg	[NSFULL-1:0]	rrequest		[0:NM-1];
+	reg	[NSFULL-1:0]	wrequested		[0:NM];
+	reg	[NSFULL-1:0]	rrequested		[0:NM];
+	reg	[NS:0]		wgrant			[0:NM-1];
+	reg	[NS:0]		rgrant			[0:NM-1];
+	reg	[NM-1:0]	swgrant;
+	reg	[NM-1:0]	srgrant;
+	reg	[NS-1:0]	mwgrant;
+	reg	[NS-1:0]	mrgrant;
+
+	// verilator lint_off UNUSED
+	wire	[LGMAXBURST-1:0]	w_sawpending	[0:NM-1];
+	wire	[LGMAXBURST-1:0]	w_swpending	[0:NM-1];
+	wire	[LGMAXBURST-1:0]	w_srpending	[0:NM-1];
+	// verilator lint_on  UNUSED
+	reg	[NM-1:0]		swfull;
+	reg	[NM-1:0]		srfull;
+	reg	[NM-1:0]		swempty;
+	reg	[NM-1:0]		srempty;
+	//
+	reg	[LGNS-1:0]		swindex	[0:NMFULL-1];
+	reg	[LGNS-1:0]		srindex	[0:NMFULL-1];
+	reg	[LGNM-1:0]		mwindex	[0:NSFULL-1];
+	reg	[LGNM-1:0]		mrindex	[0:NSFULL-1];
+
+	(* keep *) reg	[NM-1:0]		wdata_expected;
+
+	// The shadow buffers
+	reg	[NMFULL-1:0]	m_awvalid, m_wvalid, m_arvalid;
+	wire	[NM-1:0]	dcd_awvalid, dcd_arvalid;
+
+	wire	[C_AXI_ADDR_WIDTH-1:0]		m_awaddr	[0:NMFULL-1];
+	wire	[2:0]				m_awprot	[0:NMFULL-1];
+	wire	[C_AXI_DATA_WIDTH-1:0]		m_wdata		[0:NMFULL-1];
+	wire	[C_AXI_DATA_WIDTH/8-1:0]	m_wstrb		[0:NMFULL-1];
+
+	wire	[C_AXI_ADDR_WIDTH-1:0]		m_araddr	[0:NMFULL-1];
+	wire	[2:0]				m_arprot	[0:NMFULL-1];
+	//
+
+	wire	[NM-1:0]	skd_awvalid, skd_awstall, skd_wvalid;
+	wire	[NM-1:0]	skd_arvalid, skd_arstall;
+	wire	[AW-1:0]	skd_awaddr			[0:NM-1];
+	wire	[3-1:0]		skd_awprot			[0:NM-1];
+	wire	[AW-1:0]	skd_araddr			[0:NM-1];
+	wire	[3-1:0]		skd_arprot			[0:NM-1];
+
+
+	reg	[NSFULL-1:0]	m_axi_awvalid;
+	reg	[NSFULL-1:0]	m_axi_awready;
+	reg	[NSFULL-1:0]	m_axi_wvalid;
+	reg	[NSFULL-1:0]	m_axi_wready;
+	reg	[NSFULL-1:0]	m_axi_bvalid;
+`ifdef	FORMAL
+	reg	[NSFULL-1:0]	m_axi_bready;
+`endif
+	reg	[1:0]		m_axi_bresp	[0:NSFULL-1];
+
+	reg	[NSFULL-1:0]	m_axi_arvalid;
+	// Verilator lint_off UNUSED
+	reg	[NSFULL-1:0]	m_axi_arready;
+	// Verilator lint_on  UNUSED
+	reg	[NSFULL-1:0]	m_axi_rvalid;
+	// Verilator lint_off UNUSED
+	reg	[NSFULL-1:0]	m_axi_rready;
+	// Verilator lint_on  UNUSED
+
+	reg	[DW-1:0]	m_axi_rdata	[0:NSFULL-1];
+	reg	[1:0]		m_axi_rresp	[0:NSFULL-1];
+
+	reg	[NM-1:0]	slave_awaccepts;
+	reg	[NM-1:0]	slave_waccepts;
+	reg	[NM-1:0]	slave_raccepts;
+
+	always @(*)
+	begin
+		m_axi_awvalid = -1;
+		m_axi_awready = -1;
+		m_axi_wvalid = -1;
+		m_axi_wready = -1;
+		m_axi_bvalid = 0;
+
+		m_axi_awvalid[NS-1:0] = M_AXI_AWVALID;
+		m_axi_awready[NS-1:0] = M_AXI_AWREADY;
+		m_axi_wvalid[NS-1:0]  = M_AXI_WVALID;
+		m_axi_wready[NS-1:0]  = M_AXI_WREADY;
+		m_axi_bvalid[NS-1:0]  = M_AXI_BVALID;
+
+		for(iM=0; iM<NS; iM=iM+1)
+		begin
+			m_axi_bresp[iM] = M_AXI_BRESP[iM* 2 +:  2];
+
+			m_axi_rdata[iM] = M_AXI_RDATA[iM*DW +: DW];
+			m_axi_rresp[iM] = M_AXI_RRESP[iM* 2 +:  2];
+		end
+		for(iM=NS; iM<NSFULL; iM=iM+1)
+		begin
+			m_axi_bresp[iM] = INTERCONNECT_ERROR;
+
+			m_axi_rdata[iM] = 0;
+			m_axi_rresp[iM] = INTERCONNECT_ERROR;
+		end
+
+`ifdef	FORMAL
+		m_axi_bready = -1;
+		m_axi_bready[NS-1:0]  = M_AXI_BREADY;
+`endif
+	end
+
+	generate for(N=0; N<NM; N=N+1)
+	begin : DECODE_WRITE_REQUEST
+		wire	[NS:0]		wdecode;
+
+		skidbuffer #(.DW(AW+3), .OPT_OUTREG(OPT_SKID_INPUT))
+		awskid(S_AXI_ACLK, !S_AXI_ARESETN,
+			S_AXI_AWVALID[N], S_AXI_AWREADY[N],
+			{ S_AXI_AWADDR[N*AW +: AW], S_AXI_AWPROT[N*3 +: 3] },
+			skd_awvalid[N], !skd_awstall[N],
+				{ skd_awaddr[N], skd_awprot[N] });
+
+		addrdecode #(.AW(AW), .DW(3), .NS(NS),
+			.SLAVE_ADDR(SLAVE_ADDR),
+			.SLAVE_MASK(SLAVE_MASK),
+			.OPT_REGISTERED(OPT_BUFFER_DECODER))
+		wraddr(.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+			.i_valid(skd_awvalid[N]), .o_stall(skd_awstall[N]),
+				.i_addr(skd_awaddr[N]), .i_data(skd_awprot[N]),
+			.o_valid(dcd_awvalid[N]),
+				.i_stall(!dcd_awvalid[N]||!slave_awaccepts[N]),
+				.o_decode(wdecode), .o_addr(m_awaddr[N]),
+				.o_data(m_awprot[N]));
+
+		skidbuffer #(.DW(DW+DW/8), .OPT_OUTREG(OPT_SKID_INPUT))
+		wskid(S_AXI_ACLK, !S_AXI_ARESETN,
+			S_AXI_WVALID[N], S_AXI_WREADY[N],
+			{ S_AXI_WDATA[N*DW +: DW], S_AXI_WSTRB[N*DW/8 +: DW/8]},
+			skd_wvalid[N], (m_wvalid[N] && slave_waccepts[N]),
+					{ m_wdata[N], m_wstrb[N] });
+
+		always @(*)
+		begin
+			slave_awaccepts[N] = 1'b1;
+			if (!swgrant[N])
+				slave_awaccepts[N] = 1'b0;
+			if (swfull[N])
+				slave_awaccepts[N] = 1'b0;
+			if (!wrequest[N][swindex[N]])
+				slave_awaccepts[N] = 1'b0;
+			if (!wgrant[N][NS]&&(m_axi_awvalid[swindex[N]] && !m_axi_awready[swindex[N]]))
+				slave_awaccepts[N] = 1'b0;
+			// ERRORs are always accepted
+			//	back pressure is handled in the write side
+		end
+
+		always @(*)
+		begin
+			slave_waccepts[N] = 1'b1;
+			if (!swgrant[N])
+				slave_waccepts[N] = 1'b0;
+			if (!wdata_expected[N])
+				slave_waccepts[N] = 1'b0;
+			if (!wgrant[N][NS] &&(m_axi_wvalid[swindex[N]]
+						&& !m_axi_wready[swindex[N]]))
+				slave_waccepts[N] = 1'b0;
+			if (wgrant[N][NS]&&(S_AXI_BVALID[N]&& !S_AXI_BREADY[N]))
+				slave_waccepts[N] = 1'b0;
+		end
+
+		always @(*)
+		begin
+			m_awvalid[N]= dcd_awvalid[N] && !swfull[N];
+			m_wvalid[N] = skd_wvalid[N];
+			wrequest[N]= 0;
+			if (!swfull[N])
+				wrequest[N][NS:0] = wdecode;
+		end
+
+`ifdef	FORMAL
+		always @(*)
+		if (skd_awvalid[N])
+			assert(skd_awprot[N] == 0);
+`endif
+	end for (N=NM; N<NMFULL; N=N+1)
+	begin : UNUSED_WSKID_BUFFERS
+
+		always @(*)
+			m_awvalid[N] = 0;
+		assign	m_awaddr[N] = 0;
+		assign	m_awprot[N] = 0;
+		assign	m_wdata[N] = 0;
+		assign	m_wstrb[N] = 0;
+
+	end endgenerate
+
+	generate for(N=0; N<NM; N=N+1)
+	begin : DECODE_READ_REQUEST
+		wire	[NS:0]		rdecode;
+
+		skidbuffer #(.DW(AW+3), .OPT_OUTREG(OPT_SKID_INPUT))
+		arskid(S_AXI_ACLK, !S_AXI_ARESETN,
+			S_AXI_ARVALID[N], S_AXI_ARREADY[N],
+			{ S_AXI_ARADDR[N*AW +: AW], S_AXI_ARPROT[N*3 +: 3] },
+			skd_arvalid[N], !skd_arstall[N],
+				{ skd_araddr[N], skd_arprot[N] });
+
+		addrdecode #(.AW(AW), .DW(3), .NS(NS),
+			.SLAVE_ADDR(SLAVE_ADDR), .SLAVE_MASK(SLAVE_MASK),
+			.OPT_REGISTERED(OPT_BUFFER_DECODER))
+		rdaddr(.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+			.i_valid(skd_arvalid[N]), .o_stall(skd_arstall[N]),
+				.i_addr(skd_araddr[N]), .i_data(skd_arprot[N]),
+			.o_valid(dcd_arvalid[N]),
+				.i_stall(!m_arvalid[N] || !slave_raccepts[N]),
+				.o_decode(rdecode), .o_addr(m_araddr[N]),
+				.o_data(m_arprot[N]));
+
+
+		always @(*)
+		begin
+			m_arvalid[N] = dcd_arvalid[N] && !srfull[N];
+			rrequest[N] = 0;
+			if (!srfull[N])
+				rrequest[N][NS:0] = rdecode;
+		end
+
+		always @(*)
+		begin
+			slave_raccepts[N] = 1'b1;
+			if (!srgrant[N])
+				slave_raccepts[N] = 1'b0;
+			if (srfull[N])
+				slave_raccepts[N] = 1'b0;
+			// verilator lint_off  WIDTH
+			if (!rrequest[N][srindex[N]])
+				slave_raccepts[N] = 1'b0;
+			// verilator lint_on  WIDTH
+			if (!rgrant[N][NS])
+			begin
+				if (m_axi_arvalid[srindex[N]] && !m_axi_arready[srindex[N]])
+					slave_raccepts[N] = 1'b0;
+			end else if (S_AXI_RVALID[N] && !S_AXI_RREADY[N])
+				slave_raccepts[N] = 1'b0;
+		end
+
+
+`ifdef	FORMAL
+		always @(*)
+		if (skd_arvalid[N])
+			assert(skd_arprot[N] == 0);
+`endif
+	end for (N=NM; N<NMFULL; N=N+1)
+	begin : UNUSED_RSKID_BUFFERS
+
+		always @(*)
+			m_arvalid[N] = 0;
+		assign	m_araddr[N] = 0;
+		assign	m_arprot[N] = 0;
+	end endgenerate
+
+	always @(*)
+	begin : DECONFLICT_WRITE_REQUESTS
+
+		for(iN=1; iN<NM ; iN=iN+1)
+			wrequested[iN] = 0;
+
+		// Vivado may complain about too many bits for wrequested.
+		// This is (currrently) expected.  swindex is used to index
+		// into wrequested, and swindex has LGNS bits, where LGNS
+		// is $clog2(NS+1) rather than $clog2(NS).  The extra bits
+		// are defined to be zeros, but the point is there are defined.
+		// Therefore, no matter what swindex is, it will always
+		// reference something valid.
+		wrequested[NM] = 0;
+
+		for(iM=0; iM<NS; iM=iM+1)
+		begin
+			wrequested[0][iM] = 1'b0;
+			for(iN=1; iN<NM ; iN=iN+1)
+			begin
+				// Continue to request any channel with
+				// a grant and pending operations
+				if (wrequest[iN-1][iM] && wgrant[iN-1][iM])
+					wrequested[iN][iM] = 1;
+				if (wrequest[iN-1][iM] && (!swgrant[iN-1]||swempty[iN-1]))
+					wrequested[iN][iM] = 1;
+				// Otherwise, if it's already claimed, then
+				// it can't be claimed again
+				if (wrequested[iN-1][iM])
+					wrequested[iN][iM] = 1;
+			end
+			wrequested[NM][iM] = wrequest[NM-1][iM] || wrequested[NM-1][iM];
+		end
+
+	end
+
+	always @(*)
+	begin : DECONFLICT_READ_REQUESTS
+
+		for(iN=0; iN<NM ; iN=iN+1)
+			rrequested[iN] = 0;
+
+		// See the note above for wrequested.  This applies to
+		// rrequested as well.
+		rrequested[NM] = 0;
+
+		for(iM=0; iM<NS; iM=iM+1)
+		begin
+			rrequested[0][iM] = 0;
+			for(iN=1; iN<NM ; iN=iN+1)
+			begin
+				// Continue to request any channel with
+				// a grant and pending operations
+				if (rrequest[iN-1][iM] && rgrant[iN-1][iM])
+					rrequested[iN][iM] = 1;
+				if (rrequest[iN-1][iM] && (!srgrant[iN-1] || srempty[iN-1]))
+					rrequested[iN][iM] = 1;
+				// Otherwise, if it's already claimed, then
+				// it can't be claimed again
+				if (rrequested[iN-1][iM])
+					rrequested[iN][iM] = 1;
+			end
+			rrequested[NM][iM] = rrequest[NM-1][iM] || rrequested[NM-1][iM];
+		end
+
+	end
+
+	generate for(M=0; M<NS; M=M+1)
+	begin
+
+		always @(*)
+		begin
+			mwgrant[M] = 0;
+			for(iN=0; iN<NM; iN=iN+1)
+			if (wgrant[iN][M])
+				mwgrant[M] = 1;
+		end
+
+		always @(*)
+		begin
+			mrgrant[M] = 0;
+			for(iN=0; iN<NM; iN=iN+1)
+			if (rgrant[iN][M])
+				mrgrant[M] = 1;
+		end
+
+	end endgenerate
+
+	generate for(N=0; N<NM; N=N+1)
+	begin : ARBITRATE_WRITE_REQUESTS
+		reg			stay_on_channel;
+		reg			requested_channel_is_available;
+		reg			leave_channel;
+		reg	[LGNS-1:0]	requested_index;
+
+		always @(*)
+		begin
+			stay_on_channel = |(wrequest[N][NS:0] & wgrant[N]);
+
+			if (swgrant[N] && !swempty[N])
+				stay_on_channel = 1;
+		end
+
+		always @(*)
+		begin
+			requested_channel_is_available = 
+				|(wrequest[N][NS-1:0] & ~mwgrant
+						& ~wrequested[N][NS-1:0]);
+			if (wrequest[N][NS])
+				requested_channel_is_available = 1;
+
+			if (NM < 2)
+				requested_channel_is_available = m_awvalid[N];
+		end
+
+		reg	linger;
+		if (OPT_LINGER == 0)
+		begin
+			always @(*)
+				linger = 0;
+		end else begin : WRITE_LINGER
+
+			reg [LGLINGER-1:0]	linger_counter;
+
+			initial	linger = 0;
+			initial	linger_counter = 0;
+			always @(posedge S_AXI_ACLK)
+			if (!S_AXI_ARESETN || wgrant[N][NS])
+			begin
+				linger <= 0;
+				linger_counter <= 0;
+			end else if (!swempty[N] || S_AXI_BVALID[N])
+			begin
+				linger_counter <= OPT_LINGER;
+				linger <= 1;
+			end else if (linger_counter > 0)
+			begin
+				linger <= (linger_counter > 1);
+				linger_counter <= linger_counter - 1;
+			end else
+				linger <= 0;
+
+`ifdef	FORMAL
+			always @(*)
+				assert(linger == (linger_counter != 0));
+`endif
+		end
+
+		always @(*)
+		begin
+			leave_channel = 0;
+			if (!m_awvalid[N]
+				&& (!linger || wrequested[NM][swindex[N]]))
+				// Leave the channel after OPT_LINGER counts
+				// of the channel being idle, or when someone
+				// else asks for the channel
+				leave_channel = 1;
+			if (m_awvalid[N] && !wrequest[N][swindex[N]])
+				// Need to leave this channel to connect
+				// to any other channel
+				leave_channel = 1;
+		end
+
+
+		initial	wgrant[N]  = 0;
+		initial	swgrant[N] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+		begin
+			wgrant[N]  <= 0;
+			swgrant[N] <= 0;
+		end else if (!stay_on_channel)
+		begin
+			if (requested_channel_is_available)
+			begin
+				// Switching channels
+				swgrant[N] <= 1'b1;
+				wgrant[N]  <= wrequest[N][NS:0];
+			end else if (leave_channel)
+			begin
+				swgrant[N] <= 1'b0;
+				wgrant[N]  <= 0;
+			end
+		end
+
+		always @(*)
+		begin
+			requested_index = 0;
+			for(iM=0; iM<=NS; iM=iM+1)
+			if (wrequest[N][iM])
+				requested_index= requested_index | iM[LGNS-1:0];
+		end
+
+		// Now for swindex
+		initial	swindex[N] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!stay_on_channel && requested_channel_is_available)
+			swindex[N] <= requested_index;
+
+	end for (N=NM; N<NMFULL; N=N+1)
+	begin
+
+		always @(*)
+			swindex[N] = 0;
+
+	end endgenerate
+
+	generate for(N=0; N<NM; N=N+1)
+	begin : ARBITRATE_READ_REQUESTS
+		reg			stay_on_channel;
+		reg			requested_channel_is_available;
+		reg			leave_channel;
+		reg	[LGNS-1:0]	requested_index;
+
+
+		always @(*)
+		begin
+			stay_on_channel = |(rrequest[N][NS:0] & rgrant[N]);
+
+			if (srgrant[N] && !srempty[N])
+				stay_on_channel = 1;
+		end
+
+		always @(*)
+		begin
+			requested_channel_is_available = 
+				|(rrequest[N][NS-1:0] & ~mrgrant
+						& ~rrequested[N][NS-1:0]);
+			if (rrequest[N][NS])
+				requested_channel_is_available = 1;
+
+			if (NM < 2)
+				requested_channel_is_available = m_arvalid[N];
+		end
+
+		reg	linger;
+		if (OPT_LINGER == 0)
+		begin
+			always @(*)
+				linger = 0;
+		end else begin : READ_LINGER
+
+			reg [LGLINGER-1:0]	linger_counter;
+
+			initial	linger = 0;
+			initial	linger_counter = 0;
+			always @(posedge S_AXI_ACLK)
+			if (!S_AXI_ARESETN || rgrant[N][NS])
+			begin
+				linger <= 0;
+				linger_counter <= 0;
+			end else if (!srempty[N] || S_AXI_RVALID[N])
+			begin
+				linger_counter <= OPT_LINGER;
+				linger <= 1;
+			end else if (linger_counter > 0)
+			begin
+				linger <= (linger_counter > 1);
+				linger_counter <= linger_counter - 1;
+			end else
+				linger <= 0;
+
+`ifdef	FORMAL
+			always @(*)
+				assert(linger == (linger_counter != 0));
+`endif
+		end
+
+		always @(*)
+		begin
+			leave_channel = 0;
+			if (!m_arvalid[N]
+				&& (!linger || rrequested[NM][srindex[N]]))
+				// Leave the channel after OPT_LINGER counts
+				// of the channel being idle, or when someone
+				// else asks for the channel
+				leave_channel = 1;
+			if (m_arvalid[N] && !rrequest[N][srindex[N]])
+				// Need to leave this channel to connect
+				// to any other channel
+				leave_channel = 1;
+		end
+
+
+		initial	rgrant[N]  = 0;
+		initial	srgrant[N] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+		begin
+			rgrant[N]  <= 0;
+			srgrant[N] <= 0;
+		end else if (!stay_on_channel)
+		begin
+			if (requested_channel_is_available)
+			begin
+				// Switching channels
+				srgrant[N] <= 1'b1;
+				rgrant[N] <= rrequest[N][NS:0];
+			end else if (leave_channel)
+			begin
+				srgrant[N] <= 1'b0;
+				rgrant[N]  <= 0;
+			end
+		end
+
+
+		always @(*)
+		begin
+			requested_index = 0;
+			for(iM=0; iM<=NS; iM=iM+1)
+			if (rrequest[N][iM])
+				requested_index = requested_index|iM[LGNS-1:0];
+		end
+
+		// Now for srindex
+		initial	srindex[N] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!stay_on_channel && requested_channel_is_available)
+			srindex[N] <= requested_index;
+
+
+	end for (N=NM; N<NMFULL; N=N+1)
+	begin
+
+		always @(*)
+			srindex[N] = 0;
+
+	end endgenerate
+
+`ifdef	FORMAL
+	generate for (N=0; N<NM; N=N+1)
+	begin
+		always @(*)
+		if (dcd_awvalid[N])
+			assert(m_awprot[N] == 0);
+
+		always @(*)
+		if (dcd_arvalid[N])
+			assert(m_arprot[N] == 0);
+
+	end endgenerate
+`endif
+
+	// Calculate mwindex
+	generate for (M=0; M<NS; M=M+1)
+	begin : SLAVE_WRITE_INDEX
+
+		if (NM <= 1)
+		begin
+
+			always @(*)
+				mwindex[M] = 0;
+
+		end else begin : MULTIPLE_MASTERS
+
+			reg [LGNM-1:0]	reswindex;
+
+			always @(*)
+			begin
+				reswindex = 0;
+			for(iN=0; iN<NM; iN=iN+1)
+			if ((!swgrant[iN] || swempty[iN])
+				&&(wrequest[iN][M] && !wrequested[iN][M]))
+					reswindex = reswindex | iN[LGNM-1:0];
+			end
+
+			always @(posedge S_AXI_ACLK)
+			if (!mwgrant[M])
+				mwindex[M] <= reswindex;
+		end
+
+	end for (M=NS; M<NSFULL; M=M+1)
+	begin
+
+		always @(*)
+			mwindex[M] = 0;
+
+	end endgenerate
+
+	// Calculate mrindex
+	generate for (M=0; M<NS; M=M+1)
+	begin : SLAVE_READ_INDEX
+
+		if (NM <= 1)
+		begin
+
+			always @(*)
+				mrindex[M] = 0;
+
+		end else begin : MULTIPLE_MASTERS
+
+			reg [LGNM-1:0]	resrindex;
+
+			always @(*)
+			begin
+				resrindex = 0;
+			for(iN=0; iN<NM; iN=iN+1)
+			if ((!srgrant[iN] || srempty[iN])
+				&&(rrequest[iN][M] && !rrequested[iN][M]))
+					resrindex = resrindex | iN[LGNM-1:0];
+			end
+
+			always @(posedge S_AXI_ACLK)
+			if (!mrgrant[M])
+				mrindex[M] <= resrindex;
+		end
+
+	end for (M=NS; M<NSFULL; M=M+1)
+	begin
+
+		always @(*)
+			mrindex[M] = 0;
+
+	end endgenerate
+
+
+	// Assign outputs to the various slaves
+	generate for(M=0; M<NS; M=M+1)
+	begin : WRITE_SLAVE_OUTPUTS
+
+		reg			axi_awvalid;
+		reg	[AW-1:0]	axi_awaddr;
+		reg	[2:0]		axi_awprot;
+
+		reg			axi_wvalid;
+		reg	[DW-1:0]	axi_wdata;
+		reg	[DW/8-1:0]	axi_wstrb;
+		//
+		reg			axi_bready;
+
+		reg	sawstall, swstall, mbstall;
+		always @(*)
+			sawstall= (M_AXI_AWVALID[M]&& !M_AXI_AWREADY[M]);
+		always @(*)
+			swstall = (M_AXI_WVALID[M] && !M_AXI_WREADY[M]);
+		always @(*)
+			mbstall = (S_AXI_BVALID[mwindex[M]] && !S_AXI_BREADY[mwindex[M]]);
+
+		initial	axi_awvalid = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN || !mwgrant[M])
+			axi_awvalid <= 0;
+		else if (!sawstall)
+		begin
+			axi_awvalid <= m_awvalid[mwindex[M]]
+				&&(slave_awaccepts[mwindex[M]]);
+		end
+
+		initial	axi_awaddr  = 0;
+		initial	axi_awprot  = 0;
+		always @(posedge S_AXI_ACLK)
+		if (OPT_LOWPOWER && !S_AXI_ARESETN)
+		begin
+			axi_awaddr  <= 0;
+			axi_awprot  <= 0;
+		end else if (OPT_LOWPOWER && !mwgrant[M])
+		begin
+			axi_awaddr  <= 0;
+			axi_awprot  <= 0;
+		end else if (!sawstall)
+		begin
+			if (!OPT_LOWPOWER||(m_awvalid[mwindex[M]]&&slave_awaccepts[mwindex[M]]))
+			begin
+				axi_awaddr  <= m_awaddr[mwindex[M]];
+				axi_awprot  <= m_awprot[mwindex[M]];
+			end else begin
+				axi_awaddr  <= 0;
+				axi_awprot  <= 0;
+			end
+		end
+
+		initial	axi_wvalid = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN || !mwgrant[M])
+			axi_wvalid <= 0;
+		else if (!swstall)
+		begin
+			axi_wvalid <= (m_wvalid[mwindex[M]])
+					&&(slave_waccepts[mwindex[M]]);
+		end
+
+		initial axi_wdata  = 0;
+		initial axi_wstrb  = 0;
+		always @(posedge S_AXI_ACLK)
+		if (OPT_LOWPOWER && !S_AXI_ARESETN)
+		begin
+			axi_wdata  <= 0;
+			axi_wstrb  <= 0;
+		end else if (OPT_LOWPOWER && !mwgrant[M])
+		begin
+			axi_wdata  <= 0;
+			axi_wstrb  <= 0;
+		end else if (!swstall)
+		begin
+			if (!OPT_LOWPOWER || (m_wvalid[mwindex[M]]&&slave_waccepts[mwindex[M]]))
+			begin
+				axi_wdata  <= m_wdata[mwindex[M]];
+				axi_wstrb  <= m_wstrb[mwindex[M]];
+			end else begin
+				axi_wdata  <= 0;
+				axi_wstrb  <= 0;
+			end
+		end
+
+		//
+		initial	axi_bready = 1;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN || !mwgrant[M])
+			axi_bready <= 1;
+		else if (!mbstall)
+			axi_bready <= 1;
+		else if (M_AXI_BVALID[M]) // && mbstall
+			axi_bready <= 0;
+
+		//
+		assign	M_AXI_AWVALID[M]         = axi_awvalid;
+		assign	M_AXI_AWADDR[M*AW +: AW] = axi_awaddr;
+		assign	M_AXI_AWPROT[M*3 +: 3]   = axi_awprot;
+		//
+		//
+		assign	M_AXI_WVALID[M]             = axi_wvalid;
+		assign	M_AXI_WDATA[M*DW +: DW]     = axi_wdata;
+		assign	M_AXI_WSTRB[M*DW/8 +: DW/8] = axi_wstrb;
+		//
+		//
+		assign	M_AXI_BREADY[M]             = axi_bready;
+		//
+`ifdef	FORMAL
+		if (OPT_LOWPOWER)
+		begin
+			always @(*)
+			if (!axi_awvalid)
+			begin
+				assert(axi_awaddr == 0);
+				assert(axi_awprot == 0);
+			end
+
+			always @(*)
+			if (!axi_wvalid)
+			begin
+				assert(axi_wdata == 0);
+				assert(axi_wstrb == 0);
+			end
+		end
+`endif
+	end endgenerate
+
+
+	generate for(M=0; M<NS; M=M+1)
+	begin : READ_SLAVE_OUTPUTS
+
+		reg				axi_arvalid;
+		reg	[C_AXI_ADDR_WIDTH-1:0]	axi_araddr;
+		reg	[2:0]			axi_arprot;
+		//
+		reg				axi_rready;
+
+		reg	arstall, srstall;
+		always @(*)
+			arstall= (M_AXI_ARVALID[M]&& !M_AXI_ARREADY[M]);
+		always @(*)
+			srstall = (S_AXI_RVALID[mrindex[M]]
+						&& !S_AXI_RREADY[mrindex[M]]);
+
+		initial	axi_arvalid = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN || !mrgrant[M])
+			axi_arvalid <= 0;
+		else if (!arstall)
+		begin
+			axi_arvalid <= m_arvalid[mrindex[M]] && slave_raccepts[mrindex[M]];
+		end
+
+		initial	axi_araddr  = 0;
+		initial	axi_arprot  = 0;
+		always @(posedge S_AXI_ACLK)
+		if (OPT_LOWPOWER && !S_AXI_ARESETN)
+		begin
+			axi_araddr  <= 0;
+			axi_arprot  <= 0;
+		end else if (OPT_LOWPOWER && !mrgrant[M])
+		begin
+			axi_araddr  <= 0;
+			axi_arprot  <= 0;
+		end else if (!arstall)
+		begin
+			if (!OPT_LOWPOWER || (m_arvalid[mrindex[M]] && slave_raccepts[mrindex[M]]))
+			begin
+				if (NM == 1)
+				begin
+					axi_araddr  <= m_araddr[0];
+					axi_arprot  <= m_arprot[0];
+				end else begin
+					axi_araddr  <= m_araddr[mrindex[M]];
+					axi_arprot  <= m_arprot[mrindex[M]];
+				end
+			end else begin
+				axi_araddr  <= 0;
+				axi_arprot  <= 0;
+			end
+		end
+
+		initial	axi_rready = 1;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN || !mrgrant[M])
+			axi_rready <= 1;
+		else if (!srstall)
+			axi_rready <= 1;
+		else if (M_AXI_RVALID[M] && M_AXI_RREADY[M]) // && srstall
+			axi_rready <= 0;
+
+		//
+		assign	M_AXI_ARVALID[M]         = axi_arvalid;
+		assign	M_AXI_ARADDR[M*AW +: AW] = axi_araddr;
+		assign	M_AXI_ARPROT[M*3 +: 3]   = axi_arprot;
+		//
+		assign	M_AXI_RREADY[M]          = axi_rready;
+		//
+`ifdef	FORMAL
+		if (OPT_LOWPOWER)
+		begin
+			always @(*)
+			if (!axi_arvalid)
+			begin
+				assert(axi_araddr == 0);
+				assert(axi_arprot == 0);
+			end
+		end
+`endif
+	end endgenerate
+
+	reg		r_bvalid	[0:NM-1];
+	reg	[1:0]	r_bresp		[0:NM-1];
+
+	// Return values
+	generate for (N=0; N<NM; N=N+1)
+	begin : WRITE_RETURN_CHANNEL
+
+		reg		axi_bvalid;
+		reg	[1:0]	axi_bresp;
+		reg		i_axi_bvalid;
+		reg	[1:0]	i_axi_bresp;
+		reg		mbstall;
+
+		always @(*)
+		if (wgrant[N][NS])
+			i_axi_bvalid = m_wvalid[N] && slave_waccepts[N];
+		else
+			i_axi_bvalid = m_axi_bvalid[swindex[N]];
+
+		always @(*)
+			i_axi_bresp = m_axi_bresp[swindex[N]];
+
+		always @(*)
+			mbstall = S_AXI_BVALID[N] && !S_AXI_BREADY[N];
+
+		initial	r_bvalid[N] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			r_bvalid[N] <= 0;
+		else if (mbstall && !r_bvalid[N] && !wgrant[N][NS])
+			r_bvalid[N] <= swgrant[N] && i_axi_bvalid;
+		else if (!mbstall)
+			r_bvalid[N] <= 1'b0;
+
+		initial	r_bresp[N] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (OPT_LOWPOWER && !S_AXI_ARESETN)
+			r_bresp[N] <= 0;
+		else if (OPT_LOWPOWER && (!swgrant[N] || S_AXI_BREADY[N]))
+			r_bresp[N] <= 0;
+		else if (!r_bvalid[N])
+		begin
+			if (!OPT_LOWPOWER ||(i_axi_bvalid && !wgrant[N][NS] && mbstall))
+			begin
+				r_bresp[N] <= i_axi_bresp;
+			end else
+				r_bresp[N] <= 0;
+		end
+
+		initial	axi_bvalid = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			axi_bvalid <= 0;
+		else if (!mbstall)
+			axi_bvalid <= swgrant[N] && (r_bvalid[N] || i_axi_bvalid);
+
+		initial	axi_bresp = 0;
+		always @(posedge S_AXI_ACLK)
+		if (OPT_LOWPOWER && !S_AXI_ARESETN)
+			axi_bresp <= 0;
+		else if (OPT_LOWPOWER && !swgrant[N])
+			axi_bresp <= 0;
+		else if (!mbstall)
+		begin
+			if (r_bvalid[N])
+				axi_bresp <= r_bresp[N];
+			else if (!OPT_LOWPOWER || i_axi_bvalid)
+				axi_bresp <= i_axi_bresp;
+			else
+				axi_bresp <= 0;
+
+			if (wgrant[N][NS] && (!OPT_LOWPOWER || i_axi_bvalid))
+				axi_bresp <= INTERCONNECT_ERROR;
+		end
+
+		//
+		assign	S_AXI_BVALID[N]       = axi_bvalid;
+		assign	S_AXI_BRESP[N*2 +: 2] = axi_bresp;
+`ifdef	FORMAL
+		always @(*)
+		if (r_bvalid[N])
+			assert(r_bresp[N] != 2'b01);
+		always @(*)
+		if (swgrant[N])
+			assert(m_axi_bready[swindex[N]] == !r_bvalid[N]);
+		else
+			assert(!r_bvalid[N]);
+		always @(*)
+		if (OPT_LOWPOWER && !r_bvalid[N])
+			assert(r_bresp[N]  == 0);
+
+		always @(*)
+		if (OPT_LOWPOWER && !axi_bvalid)
+			assert(axi_bresp  == 0);
+`endif
+	end endgenerate
+
+	always @(*)
+	begin
+		m_axi_arvalid = 0;
+		m_axi_arready = 0;
+		m_axi_rvalid = 0;
+		m_axi_rready = 0;
+
+		m_axi_arvalid[NS-1:0] = M_AXI_ARVALID;
+		m_axi_arready[NS-1:0] = M_AXI_ARREADY;
+		m_axi_rvalid[NS-1:0]  = M_AXI_RVALID;
+		m_axi_rready[NS-1:0]  = M_AXI_RREADY;
+	end
+
+	reg			r_rvalid	[0:NM-1];
+	reg	[1:0]		r_rresp		[0:NM-1];
+	reg	[DW-1:0]	r_rdata		[0:NM-1];
+	// Return values
+	generate for (N=0; N<NM; N=N+1)
+	begin : READ_RETURN_CHANNEL
+
+		reg			axi_rvalid;
+		reg	[1:0]		axi_rresp;
+		reg	[DW-1:0]	axi_rdata;
+		reg			srstall;
+		reg			i_axi_rvalid;
+
+		always @(*)
+		if (rgrant[N][NS])
+			i_axi_rvalid = m_arvalid[N] && slave_raccepts[N];
+		else
+			i_axi_rvalid = m_axi_rvalid[srindex[N]];
+
+		always @(*)
+			srstall = S_AXI_RVALID[N] && !S_AXI_RREADY[N];
+
+		initial	r_rvalid[N] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			r_rvalid[N] <= 0;
+		else if (srstall && !r_rvalid[N])
+			r_rvalid[N] <= srgrant[N] && !rgrant[N][NS]&&i_axi_rvalid;
+		else if (!srstall)
+			r_rvalid[N] <= 0;
+
+		initial	r_rresp[N] = 0;
+		initial	r_rdata[N] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (OPT_LOWPOWER && !S_AXI_ARESETN)
+		begin
+			r_rresp[N] <= 0;
+			r_rdata[N] <= 0;
+		end else if (OPT_LOWPOWER && (!srgrant[N] || S_AXI_RREADY[N]))
+		begin
+			r_rresp[N] <= 0;
+			r_rdata[N] <= 0;
+		end else if (!r_rvalid[N])
+		begin
+			if (!OPT_LOWPOWER || (i_axi_rvalid && !rgrant[N][NS] && srstall))
+			begin
+				if (NS == 1)
+				begin
+					r_rresp[N] <= m_axi_rresp[0];
+					r_rdata[N] <= m_axi_rdata[0];
+				end else begin
+					r_rresp[N] <= m_axi_rresp[srindex[N]];
+					r_rdata[N] <= m_axi_rdata[srindex[N]];
+				end
+			end else begin
+				r_rresp[N] <= 0;
+				r_rdata[N] <= 0;
+			end
+		end
+
+		initial	axi_rvalid = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			axi_rvalid <= 0;
+		else if (!srstall)
+			axi_rvalid <= srgrant[N] && (r_rvalid[N] || i_axi_rvalid);
+
+		initial	axi_rresp = 0;
+		initial	axi_rdata = 0;
+		always @(posedge S_AXI_ACLK)
+		if (OPT_LOWPOWER && !S_AXI_ARESETN)
+		begin
+			axi_rresp <= 0;
+			axi_rdata <= 0;
+		end else if (OPT_LOWPOWER && !srgrant[N])
+		begin
+			axi_rresp <= 0;
+			axi_rdata <= 0;
+		end else if (!srstall)
+		begin
+			if (r_rvalid[N])
+			begin
+				axi_rresp <= r_rresp[N];
+				axi_rdata <= r_rdata[N];
+			end else if (!OPT_LOWPOWER || i_axi_rvalid)
+			begin
+				if (NS == 1)
+				begin
+					axi_rresp <= m_axi_rresp[0];
+					axi_rdata <= m_axi_rdata[0];
+				end else begin
+					axi_rresp <= m_axi_rresp[srindex[N]];
+					axi_rdata <= m_axi_rdata[srindex[N]];
+				end
+
+				if (rgrant[N][NS])
+					axi_rresp <= INTERCONNECT_ERROR;
+			end else begin
+				axi_rresp <= 0;
+				axi_rdata <= 0;
+			end
+		end
+
+		assign	S_AXI_RVALID[N]        = axi_rvalid;
+		assign	S_AXI_RRESP[N*2  +: 2] = axi_rresp;
+		assign	S_AXI_RDATA[N*DW +: DW]= axi_rdata;
+`ifdef	FORMAL
+		always @(*)
+		if (r_rvalid[N])
+			assert(r_rresp[N] != 2'b01);
+		always @(*)
+		if (srgrant[N] && !rgrant[N][NS])
+			assert(m_axi_rready[srindex[N]] == !r_rvalid[N]);
+		else
+			assert(!r_rvalid[N]);
+		always @(*)
+		if (OPT_LOWPOWER && !r_rvalid[N])
+		begin
+			assert(r_rresp[N] == 0);
+			assert(r_rdata[N] == 0);
+		end
+
+		always @(*)
+		if (OPT_LOWPOWER && !axi_rvalid)
+		begin
+			assert(axi_rresp == 0);
+			assert(axi_rdata == 0);
+		end
+`endif
+	end endgenerate
+
+	// Count pending transactions
+	generate for (N=0; N<NM; N=N+1)
+	begin : COUNT_PENDING
+
+		reg	[LGMAXBURST-1:0]	wpending, awpending, rpending,
+						missing_wdata;
+		//reg				rempty, awempty; // wempty;
+		(* keep *) reg	r_wdata_expected;
+
+		initial	awpending    = 0;
+		initial	swempty[N]   = 1;
+		initial	swfull[N]    = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+		begin
+			awpending     <= 0;
+			swempty[N]    <= 1;
+			swfull[N]     <= 0;
+		end else case ({(m_awvalid[N] && slave_awaccepts[N]),
+				(S_AXI_BVALID[N] && S_AXI_BREADY[N])})
+		2'b01: begin
+			awpending     <= awpending - 1;
+			swempty[N]    <= (awpending <= 1);
+			swfull[N]     <= 0;
+			end
+		2'b10: begin
+			awpending <= awpending + 1;
+			swempty[N] <= 0;
+			swfull[N]     <= &awpending[LGMAXBURST-1:1];
+			end
+		default: begin end
+		endcase
+
+		initial	wpending = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			wpending <= 0;
+		else case ({(m_wvalid[N] && slave_waccepts[N]),
+				(S_AXI_BVALID[N] && S_AXI_BREADY[N])})
+		2'b01: wpending <= wpending - 1;
+		2'b10: wpending <= wpending + 1;
+		default: begin end
+		endcase
+
+		initial	missing_wdata = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			missing_wdata <= 0;
+		else begin
+			missing_wdata <= missing_wdata
+				+((m_awvalid[N] && slave_awaccepts[N])? 1:0)
+				-((m_wvalid[N] && slave_waccepts[N])? 1:0);
+		end
+
+		initial	r_wdata_expected = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			r_wdata_expected <= 0;
+		else case({ m_awvalid[N] && slave_awaccepts[N],
+				m_wvalid[N] && slave_waccepts[N] })
+		2'b10: r_wdata_expected <= 1;
+		2'b01: r_wdata_expected <= (missing_wdata > 1);
+		default: begin end
+		endcase
+
+
+		initial	rpending     = 0;
+		initial	srempty[N]   = 1;
+		initial	srfull[N]    = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+		begin
+			rpending  <= 0;
+			srempty[N]<= 1;
+			srfull[N] <= 0;
+		end else case ({(m_arvalid[N] && slave_raccepts[N]),
+				(S_AXI_RVALID[N] && S_AXI_RREADY[N])})
+		2'b01: begin
+			rpending      <= rpending - 1;
+			srempty[N]    <= (rpending == 1);
+			srfull[N]     <= 0;
+			end
+		2'b10: begin
+			rpending      <= rpending + 1;
+			srfull[N]     <= &rpending[LGMAXBURST-1:1];
+			srempty[N]    <= 0;
+			end
+		default: begin end
+		endcase
+
+		assign	w_sawpending[N] = awpending;
+		assign	w_swpending[N]  = wpending;
+		assign	w_srpending[N]  = rpending;
+
+		always @(*)
+			wdata_expected[N] = r_wdata_expected;
+
+`ifdef	FORMAL
+	reg	[LGMAXBURST-1:0]	f_missing_wdata;
+
+	always @(*)
+		assert(missing_wdata == awpending - wpending);
+	always @(*)
+		assert(r_wdata_expected == (missing_wdata > 0));
+`endif
+	end endgenerate
+
+	initial begin
+		if (NM == 0) begin
+                        $display("At least one master must be defined");
+                        $stop;
+                end
+
+		if (NS == 0) begin
+                        $display("At least one slave must be defined");
+                        $stop;
+                end
+        end
+
+`ifdef	FORMAL
+	localparam	F_LGDEPTH = LGMAXBURST+1;
+	wire	[F_LGDEPTH-1:0]	fm_rd_outstanding	[0:NM-1];
+	wire	[F_LGDEPTH-1:0]	fm_wr_outstanding	[0:NM-1];
+	wire	[F_LGDEPTH-1:0]	fm_awr_outstanding	[0:NM-1];
+
+	wire	[F_LGDEPTH-1:0]	fs_rd_outstanding	[0:NS-1];
+	wire	[F_LGDEPTH-1:0]	fs_wr_outstanding	[0:NS-1];
+	wire	[F_LGDEPTH-1:0]	fs_awr_outstanding	[0:NS-1];
+
+	initial	assert(NS >= 1);
+	initial	assert(NM >= 1);
+
+`ifdef	VERIFIC
+	reg	f_past_valid;
+
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+
+`ifdef	VERIFIC
+`define	INITIAL_CHECK	assume
+`else
+`define	INITIAL_CHECK	assert
+`endif // VERIFIC
+	always @(*)
+	if (!f_past_valid)
+	begin
+		`INITIAL_CHECK(!S_AXI_ARESETN);
+		`INITIAL_CHECK(S_AXI_BVALID == 0);
+		`INITIAL_CHECK(S_AXI_RVALID == 0);
+		`INITIAL_CHECK(swgrant == 0);
+		`INITIAL_CHECK(srgrant == 0);
+		`INITIAL_CHECK(swfull == 0);
+		`INITIAL_CHECK(srfull == 0);
+		`INITIAL_CHECK(&swempty);
+		`INITIAL_CHECK(&srempty);
+		for(iN=0; iN<NM; iN=iN+1)
+		begin
+			`INITIAL_CHECK(wgrant[iN] == 0);
+			assume(swindex[iN] == 0);
+
+			`INITIAL_CHECK(rgrant[iN] == 0);
+			assume(srindex[iN] == 0);
+
+			`INITIAL_CHECK(r_bvalid[iN] == 0);
+			`INITIAL_CHECK(r_rvalid[iN] == 0);
+			//
+			`INITIAL_CHECK(r_bresp[iN]  == 0);
+			//
+			`INITIAL_CHECK(r_rresp[iN]  == 0);
+			`INITIAL_CHECK(r_rdata[iN]  == 0);
+		end
+
+		`INITIAL_CHECK(M_AXI_AWVALID == 0);
+		`INITIAL_CHECK(M_AXI_WVALID == 0);
+		`INITIAL_CHECK(M_AXI_RVALID == 0);
+	end
+`endif
+
+	generate for(N=0; N<NM; N=N+1)
+	begin : CHECK_MASTER_GRANTS
+
+		// Write grants
+		always @(*)
+		for(iM=0; iM<=NS; iM=iM+1)
+		begin
+			if (wgrant[N][iM])
+			begin
+				assert((wgrant[N] ^ (1<<iM))==0);
+				assert(swgrant[N]);
+				assert(swindex[N] == iM);
+				if (iM < NS)
+				begin
+					assert(mwgrant[iM]);
+					assert(mwindex[iM] == N);
+				end
+			end
+		end
+
+		always @(*)
+		if (swgrant[N])
+			assert(wgrant[N] != 0);
+
+		always @(*)
+		if (wrequest[N][NS])
+			assert(wrequest[N][NS-1:0] == 0);
+
+
+		////////////////////////////////////////////////////////////////
+		//
+		// Read grant checking
+		//
+		always @(*)
+		for(iM=0; iM<=NS; iM=iM+1)
+		begin
+			if (rgrant[N][iM])
+			begin
+				assert((rgrant[N] ^ (1<<iM))==0);
+				assert(srgrant[N]);
+				assert(srindex[N] == iM);
+				if (iM < NS)
+				begin
+					assert(mrgrant[iM]);
+					assert(mrindex[iM] == N);
+				end
+			end
+		end
+
+		always @(*)
+		if (srgrant[N])
+			assert(rgrant[N] != 0);
+
+		always @(*)
+		if (rrequest[N][NS])
+			assert(rrequest[N][NS-1:0] == 0);
+
+	end endgenerate
+
+	generate for(N=0; N<NM; N=N+1)
+	begin : CHECK_MASTERS
+
+		faxil_slave #(
+			.C_AXI_DATA_WIDTH(DW),
+			.C_AXI_ADDR_WIDTH(AW),
+			.F_OPT_HAS_CACHE(1'b0),
+			.F_OPT_ASSUME_RESET(1'b1),
+			.F_AXI_MAXWAIT(0),
+			.F_AXI_MAXDELAY(0),
+			.F_LGDEPTH(F_LGDEPTH))
+		  mstri(.i_clk(S_AXI_ACLK),
+			.i_axi_reset_n(S_AXI_ARESETN),
+			//
+			.i_axi_awready(S_AXI_AWREADY[N]),
+			.i_axi_awaddr(S_AXI_AWADDR[N*AW +: AW]),
+			.i_axi_awcache(0),
+			.i_axi_awprot(S_AXI_AWPROT[N*3 +: 3]),
+			.i_axi_awvalid(S_AXI_AWVALID[N]),
+			//
+			.i_axi_wready(S_AXI_WREADY[N]),
+			.i_axi_wdata( S_AXI_WDATA[N*DW +: DW]),
+			.i_axi_wstrb( S_AXI_WSTRB[N*DW/8 +: DW/8]),
+			.i_axi_wvalid(S_AXI_WVALID[N]),
+			//
+			.i_axi_bresp( S_AXI_BRESP[N*2 +: 2]),
+			.i_axi_bvalid(S_AXI_BVALID[N]),
+			.i_axi_bready(S_AXI_BREADY[N]),
+			//
+			.i_axi_arready(S_AXI_ARREADY[N]),
+			.i_axi_araddr( S_AXI_ARADDR[N*AW +: AW]),
+			.i_axi_arcache(4'b0),
+			.i_axi_arprot( S_AXI_ARPROT[N*3 +: 3]),
+			.i_axi_arvalid(S_AXI_ARVALID[N]),
+			//
+			//
+			.i_axi_rresp( S_AXI_RRESP[N*2 +: 2]),
+			.i_axi_rvalid(S_AXI_RVALID[N]),
+			.i_axi_rdata( S_AXI_RDATA[N*DW +: DW]),
+			.i_axi_rready(S_AXI_RREADY[N]),
+			//
+			.f_axi_rd_outstanding( fm_rd_outstanding[N]),
+			.f_axi_wr_outstanding( fm_wr_outstanding[N]),
+			.f_axi_awr_outstanding(fm_awr_outstanding[N]));
+
+		//
+		// Check write counters
+		//
+		always @(*)
+		if (S_AXI_ARESETN)
+		assert(fm_awr_outstanding[N] == { 1'b0, w_sawpending[N] }
+				+((OPT_BUFFER_DECODER & dcd_awvalid[N]) ? 1:0)
+				+ (S_AXI_AWREADY[N] ? 0:1));
+
+		always @(*)
+		if (S_AXI_ARESETN)
+		assert(fm_wr_outstanding[N] == { 1'b0, w_swpending[N] }
+				+ (S_AXI_WREADY[N] ? 0:1));
+
+		always @(*)
+		if (S_AXI_ARESETN)
+			assert(fm_awr_outstanding[N] >=
+				(S_AXI_AWREADY[N] ? 0:1)
+				+((OPT_BUFFER_DECODER & dcd_awvalid[N]) ? 1:0)
+				+ (S_AXI_BVALID[N]  ? 1:0));
+
+		always @(*)
+		if (S_AXI_ARESETN)
+			assert(fm_wr_outstanding[N] >=
+				(S_AXI_WREADY[N] ? 0:1)
+				+ (S_AXI_BVALID[N]? 1:0));
+
+		always @(*)
+		if (S_AXI_ARESETN)
+		assert(fm_wr_outstanding[N]-(S_AXI_WREADY[N] ? 0:1)
+			<= fm_awr_outstanding[N]-(S_AXI_AWREADY[N] ? 0:1));
+
+		always @(*)
+		if (S_AXI_ARESETN && wgrant[N][NS])
+			assert(fm_wr_outstanding[N] == (S_AXI_WREADY[N] ? 0:1)
+				+ (S_AXI_BVALID[N] ? 1:0));
+
+		always @(*)
+		if (S_AXI_ARESETN && !swgrant[N])
+		begin
+			assert(!S_AXI_BVALID[N]);
+
+			assert(fm_awr_outstanding[N]==(S_AXI_AWREADY[N] ? 0:1)
+				+((OPT_BUFFER_DECODER & dcd_awvalid[N]) ? 1:0));
+			assert(fm_wr_outstanding[N] == (S_AXI_WREADY[N] ? 0:1));
+			assert(w_sawpending[N] == 0);
+			assert(w_swpending[N] == 0);
+		end
+
+
+		//
+		// Check read counters
+		//
+		always @(*)
+		if (S_AXI_ARESETN)
+			assert(fm_rd_outstanding[N] >=
+				(S_AXI_ARREADY[N] ? 0:1)
+				+(S_AXI_RVALID[N] ? 1:0));
+
+		always @(*)
+		if (S_AXI_ARESETN && (!srgrant[N] || rgrant[N][NS]))
+			assert(fm_rd_outstanding[N] ==
+				(S_AXI_ARREADY[N] ? 0:1)
+				+((OPT_BUFFER_DECODER & dcd_arvalid[N]) ? 1:0)
+				+(S_AXI_RVALID[N] ? 1:0));
+
+		always @(*)
+		if (S_AXI_ARESETN)
+			assert(fm_rd_outstanding[N] == { 1'b0, w_srpending[N] }
+				+((OPT_BUFFER_DECODER & dcd_arvalid[N]) ? 1:0)
+				+ (S_AXI_ARREADY[N] ? 0:1));
+
+		always @(*)
+		if (S_AXI_ARESETN && rgrant[N][NS])
+			assert(fm_rd_outstanding[N] == (S_AXI_ARREADY[N] ? 0:1)
+				+((OPT_BUFFER_DECODER & dcd_arvalid[N]) ? 1:0)
+				+(S_AXI_RVALID[N] ? 1:0));
+
+		always @(*)
+		if (S_AXI_ARESETN && !srgrant[N])
+		begin
+			assert(!S_AXI_RVALID[N]);
+			assert(fm_rd_outstanding[N]== (S_AXI_ARREADY[N] ? 0:1)
+				+((OPT_BUFFER_DECODER && dcd_arvalid[N])? 1:0));
+			assert(w_srpending[N] == 0);
+		end
+
+		//
+		// Check full/empty flags
+		//
+		localparam	[LGMAXBURST-1:0] NEAR_THRESHOLD = -2;
+
+		always @(*)
+		begin
+			assert(swfull[N] == &w_sawpending[N]);
+			assert(swempty[N] == (w_sawpending[N] == 0));
+		end
+
+		always @(*)
+		begin
+			assert(srfull[N] == &w_srpending[N]);
+			assert(srempty[N] == (w_srpending[N] == 0));
+		end
+
+
+	end endgenerate
+
+	generate for(M=0; M<NS; M=M+1)
+	begin : CHECK_SLAVES
+
+		faxil_master #(
+			.C_AXI_DATA_WIDTH(DW),
+			.C_AXI_ADDR_WIDTH(AW),
+			.F_OPT_HAS_CACHE(1'b0),
+			.F_OPT_ASSUME_RESET(1'b1),
+			.F_AXI_MAXRSTALL(0),
+			.F_LGDEPTH(F_LGDEPTH))
+		  slvi(.i_clk(S_AXI_ACLK),
+			.i_axi_reset_n(S_AXI_ARESETN),
+			//
+			.i_axi_awready(M_AXI_AWREADY[M]),
+			.i_axi_awaddr(M_AXI_AWADDR[M*AW +: AW]),
+			.i_axi_awcache(0),
+			.i_axi_awprot(M_AXI_AWPROT[M*3 +: 3]),
+			.i_axi_awvalid(M_AXI_AWVALID[M]),
+			//
+			.i_axi_wready(M_AXI_WREADY[M]),
+			.i_axi_wdata( M_AXI_WDATA[M*DW +: DW]),
+			.i_axi_wstrb( M_AXI_WSTRB[M*DW/8 +: DW/8]),
+			.i_axi_wvalid(M_AXI_WVALID[M]),
+			//
+			.i_axi_bresp( M_AXI_BRESP[M*2 +: 2]),
+			.i_axi_bvalid(M_AXI_BVALID[M]),
+			.i_axi_bready(M_AXI_BREADY[M]),
+			//
+			.i_axi_arready(M_AXI_ARREADY[M]),
+			.i_axi_araddr( M_AXI_ARADDR[M*AW +: AW]),
+			.i_axi_arcache(4'b0),
+			.i_axi_arprot( M_AXI_ARPROT[M*3 +: 3]),
+			.i_axi_arvalid(M_AXI_ARVALID[M]),
+			//
+			//
+			.i_axi_rresp( M_AXI_RRESP[M*2 +: 2]),
+			.i_axi_rvalid(M_AXI_RVALID[M]),
+			.i_axi_rdata( M_AXI_RDATA[M*DW +: DW]),
+			.i_axi_rready(M_AXI_RREADY[M]),
+			//
+			.f_axi_rd_outstanding( fs_rd_outstanding[M]),
+			.f_axi_wr_outstanding( fs_wr_outstanding[M]),
+			.f_axi_awr_outstanding(fs_awr_outstanding[M]));
+
+		always @(*)
+		assert(fs_wr_outstanding[M] + (M_AXI_WVALID[M] ? 1:0)
+			<= fs_awr_outstanding[M] + (M_AXI_AWVALID[M]? 1:0));
+
+		always @(*)
+		if (!mwgrant[M])
+		begin
+			assert(fs_awr_outstanding[M] == 0);
+			assert(fs_wr_outstanding[M] == 0);
+		end
+
+		always @(*)
+		if (!mrgrant[M])
+			assert(fs_rd_outstanding[M] == 0);
+
+		always @(*)
+			assert(fs_awr_outstanding[M] < { 1'b1, {(F_LGDEPTH-1){1'b0}}});
+		always @(*)
+			assert(fs_wr_outstanding[M] < { 1'b1, {(F_LGDEPTH-1){1'b0}}});
+		always @(*)
+			assert(fs_rd_outstanding[M] < { 1'b1, {(F_LGDEPTH-1){1'b0}}});
+
+		always @(*)
+		if (M_AXI_AWVALID[M])
+			assert(((M_AXI_AWADDR[M*AW +: AW]
+				^ SLAVE_ADDR[M*AW +: AW])
+				& SLAVE_MASK[M*AW +: AW]) == 0);
+
+		always @(*)
+		if (M_AXI_ARVALID[M])
+			assert(((M_AXI_ARADDR[M*AW +: AW]
+				^ SLAVE_ADDR[M*AW +: AW])
+				& SLAVE_MASK[M*AW +: AW]) == 0);
+
+	end endgenerate
+
+	generate for(N=0; N<NM; N=N+1)
+	begin : CORRELATE_OUTSTANDING
+
+		always @(*)
+		if (S_AXI_ARESETN && (swgrant[N] && (swindex[N] < NS)))
+		begin
+			assert((fm_awr_outstanding[N]
+				- (S_AXI_AWREADY[N] ? 0:1)
+				-((OPT_BUFFER_DECODER && dcd_awvalid[N]) ? 1:0)
+				- (S_AXI_BVALID[N]  ? 1:0))
+				== (fs_awr_outstanding[swindex[N]]
+					+ (m_axi_awvalid[swindex[N]] ? 1:0)
+					+ (m_axi_bready[swindex[N]] ? 0:1)));
+
+			assert((fm_wr_outstanding[N]
+				- (S_AXI_WREADY[N] ? 0:1)
+				- (S_AXI_BVALID[N] ? 1:0))
+				== (fs_wr_outstanding[swindex[N]]
+					+ (m_axi_wvalid[swindex[N]] ? 1:0)
+					+ (m_axi_bready[swindex[N]] ? 0:1)));
+
+		end else if (S_AXI_ARESETN && (!swgrant[N] || (swindex[N]==NS)))
+		begin
+			if (!swgrant[N])
+				assert(fm_awr_outstanding[N] ==
+					(S_AXI_AWREADY[N] ? 0:1)
+					+((OPT_BUFFER_DECODER && dcd_awvalid[N]) ? 1:0)
+					+(S_AXI_BVALID[N]  ? 1:0));
+			else
+				assert(fm_awr_outstanding[N] >=
+					(S_AXI_AWREADY[N] ? 0:1)
+					+((OPT_BUFFER_DECODER && dcd_awvalid[N]) ? 1:0)
+					+(S_AXI_BVALID[N]  ? 1:0));
+
+			assert(fm_wr_outstanding[N]  ==
+					(S_AXI_WREADY[N]  ? 0:1)
+					+(S_AXI_BVALID[N]  ? 1:0));
+		end
+
+		always @(*)
+		if (srgrant[N] && (srindex[N] < NS))
+		begin
+			assert((fm_rd_outstanding[N]//17
+				- (S_AXI_ARREADY[N] ? 0:1)//1
+				-((OPT_BUFFER_DECODER && dcd_arvalid[N]) ? 1:0)
+				- (S_AXI_RVALID[N] ? 1:0))//0
+				== (fs_rd_outstanding[srindex[N]]//16
+					+ (m_axi_arvalid[srindex[N]] ? 1:0)//0
+					+ (m_axi_rready[srindex[N]] ? 0:1)));//0
+		end
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// Can every master reach every slave?
+	// Can things transition without dropping the request line(s)?
+	generate for(N=0; N<NM; N=N+1)
+	begin : COVER_CONNECTIVITY_FROM_MASTER
+		reg [3:0]	w_returns, r_returns;
+		reg		err_wr_return, err_rd_return;
+		reg [NS-1:0]	w_every, r_every;
+		reg		was_wevery, was_revery, whsreturn, rhsreturn;
+
+		// w_returns is a speed check: Can we return one write
+		// acknowledgement per clock cycle?
+		initial	w_returns = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			w_returns = 0;
+		else begin
+			w_returns <= { w_returns[2:0], 1'b0 };
+			if (S_AXI_BVALID[N] && S_AXI_BREADY[N] && !wgrant[N][NS])
+				w_returns[0] <= 1'b1;
+		end
+
+		initial	whsreturn = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			whsreturn <= 0;
+		else
+			whsreturn <= whsreturn || (&w_returns);
+
+		// w_every is a connectivity test: Can we get a return from
+		// every slave?
+		initial	w_every = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			w_every <= 0;
+		else if (!S_AXI_AWVALID[N])
+			w_every <= 0;
+		else begin
+			if (S_AXI_BVALID[N] && S_AXI_BREADY[N] && !wgrant[N][NS])
+				w_every[swindex[N]] <= 1'b1;
+		end
+
+		always @(posedge S_AXI_ACLK)
+		if (S_AXI_BVALID[N])
+			assert($stable(swindex[N]));
+
+		initial	was_wevery = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			was_wevery <= 0;
+		else
+			was_wevery <= was_wevery || (&w_every);
+
+		// err_wr_return is a test to make certain we can return a
+		// bus error on the write channel.
+		initial	err_wr_return = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			err_wr_return = 0;
+		else if (wgrant[N][NS] && S_AXI_BVALID[N]
+				&& (S_AXI_BRESP[2*N+:2]==INTERCONNECT_ERROR))
+			err_wr_return = 1;
+
+`ifndef	VERILATOR
+		always @(*)
+			cover(!swgrant[N] && whsreturn);
+		always @(*)
+			cover(!swgrant[N] && was_wevery);
+
+		always @(*)
+			cover(S_AXI_ARESETN && wrequest[N][NS]);
+		always @(*)
+			cover(S_AXI_ARESETN && wrequest[N][NS] && slave_awaccepts[N]);
+		always @(*)
+			cover(err_wr_return);
+		always @(*)
+			cover(!swgrant[N] && err_wr_return);
+`endif
+
+		always @(*)
+		if (S_AXI_BVALID[N])
+			assert(swgrant[N]);
+
+		// r_returns is a speed check: Can we return one read
+		// acknowledgment per clock cycle?
+		initial	r_returns = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			r_returns = 0;
+		else begin
+			r_returns <= { r_returns[2:0], 1'b0 };
+			if (S_AXI_RVALID[N] && S_AXI_RREADY[N])
+				r_returns[0] <= 1'b1;
+		end
+
+		initial	rhsreturn = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			rhsreturn <= 0;
+		else
+			rhsreturn <= rhsreturn || (&r_returns);
+
+
+		// r_every is a connectivity test: Can we get a read return from
+		// every slave?
+		initial	r_every = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			r_every = 0;
+		else if (!S_AXI_ARVALID[N])
+			r_every = 0;
+		else begin
+			if (S_AXI_RVALID[N] && S_AXI_RREADY[N])
+				r_every[srindex[N]] <= 1'b1;
+		end
+
+		// was_revery is a return to idle check following the
+		// connectivity test.  Since the connectivity test is cleared
+		// if there's ever a drop in the valid line, we need a separate
+		// wire to check that this master can return to idle again.
+		initial	was_revery = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			was_revery <= 0;
+		else
+			was_revery <= was_revery || (&r_every);
+
+		always @(posedge S_AXI_ACLK)
+		if (S_AXI_RVALID[N])
+			assert($stable(srindex[N]));
+
+		initial	err_rd_return = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			err_rd_return = 0;
+		else if (rgrant[N][NS] && S_AXI_RVALID[N]
+				&& (S_AXI_RRESP[2*N+:2]==INTERCONNECT_ERROR))
+			err_rd_return = 1;
+
+`ifndef	VERILATOR
+		always @(*)
+			cover(!srgrant[N] && rhsreturn);	// @26
+		always @(*)
+			cover(!srgrant[N] && was_revery);	// @26
+
+		always @(*)
+			cover(S_AXI_ARVALID[N] && rrequest[N][NS]);
+		always @(*)
+			cover(rgrant[N][NS]);
+		always @(*)
+			cover(err_rd_return);
+		always @(*)
+			cover(!srgrant[N] && err_rd_return); //@!
+`endif
+
+		always @(*)
+		if (S_AXI_BVALID[N] && wgrant[N][NS])
+			assert(S_AXI_BRESP[2*N+:2]==INTERCONNECT_ERROR);
+		always @(*)
+		if (S_AXI_RVALID[N] && rgrant[N][NS])
+			assert(S_AXI_RRESP[2*N+:2]==INTERCONNECT_ERROR);
+	end endgenerate
+
+	reg	multi_write_hit, multi_read_hit;
+
+	initial	multi_write_hit = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		multi_write_hit <= 0;
+	else if (fm_awr_outstanding[0] > 2 && !wgrant[0][NS])
+		multi_write_hit <= 1;
+
+	initial	multi_read_hit = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		multi_read_hit <= 0;
+	else if (fm_rd_outstanding[0] > 2 && !rgrant[0][NS])
+		multi_read_hit <= 1;
+
+	always @(*)
+		cover(multi_write_hit);
+
+	always @(*)
+		cover(multi_read_hit);
+
+	always @(*)
+		cover(S_AXI_ARESETN && multi_write_hit & mwgrant == 0 && M_AXI_BVALID == 0);
+
+	always @(*)
+		cover(S_AXI_ARESETN && multi_read_hit & mrgrant == 0 && M_AXI_RVALID == 0);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Negation check
+	//
+	// Pick a particular value.  Assume the value doesn't show up on the
+	// input.  Prove it doesn't show up on the output.  This will check for
+	// ...
+	// 1. Stuck bits on the output channel
+	// 2. Cross-talk between channels
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	(* anyconst *)	reg	[LGNM-1:0]	f_const_source;
+	(* anyconst *)	reg	[AW-1:0]	f_const_addr;
+	(* anyconst *)	reg	[AW-1:0]	f_const_addr_n;
+	(* anyconst *)	reg	[DW-1:0]	f_const_data_n;
+	(* anyconst *)	reg	[DW/8-1:0]	f_const_strb_n;
+	(* anyconst *)	reg	[3-1:0]		f_const_prot_n;
+	(* anyconst *)	reg	[2-1:0]		f_const_resp_n;
+			reg	[LGNS-1:0]	f_const_slave;
+
+	always @(*)
+		assume(f_const_source < NM);
+	always @(*)
+	begin
+		f_const_slave = NS;
+		for(iM=0; iM<NS; iM=iM+1)
+		begin
+			if (((f_const_addr ^ SLAVE_ADDR[iM*AW+:AW])
+					&SLAVE_MASK[iM*AW+:AW])==0)
+				f_const_slave = iM;
+		end
+
+		assume(f_const_slave < NS);
+	end
+
+	reg	[AW-1:0]	f_awaddr;
+	reg	[AW-1:0]	f_araddr;
+	always @(*)
+		f_awaddr = S_AXI_AWADDR[f_const_source * AW +: AW];
+	always @(*)
+		f_araddr = S_AXI_ARADDR[f_const_source * AW +: AW];
+
+	// The assumption check: assume our negated values are not found on
+	// the inputs
+	always @(*)
+	begin
+		if (S_AXI_AWVALID[f_const_source])
+		begin
+			assume(f_awaddr != f_const_addr_n);
+			assume(S_AXI_AWPROT[f_const_source*3+:3] != f_const_prot_n);
+		end
+		if (m_wvalid)
+		begin
+			assume(m_wdata[f_const_source] != f_const_data_n);
+			assume(m_wstrb[f_const_source] != f_const_strb_n);
+		end
+		if (S_AXI_ARVALID[f_const_source])
+		begin
+			assume(f_araddr != f_const_addr_n);
+			assume(S_AXI_ARPROT[f_const_source*3+:3] != f_const_prot_n);
+		end
+
+		if (M_AXI_BVALID[f_const_slave] && wgrant[f_const_source][f_const_slave])
+		begin
+			assume(m_axi_bresp[f_const_slave] != f_const_resp_n);
+		end
+
+		if (M_AXI_RVALID[f_const_slave] && rgrant[f_const_source][f_const_slave])
+		begin
+			assume(m_axi_rdata[f_const_slave] != f_const_data_n);
+			assume(m_axi_rresp[f_const_slave] != f_const_resp_n);
+		end
+	end
+
+	// Proof check: Prove these values are not found on our outputs
+	always @(*)
+	begin
+		if (skd_awvalid[f_const_source])
+		begin
+			assert(skd_awaddr[f_const_source] != f_const_addr_n);
+			assert(skd_awprot[f_const_source] != f_const_prot_n);
+		end
+		if (dcd_awvalid[f_const_source])
+		begin
+			assert(m_awaddr[f_const_source] != f_const_addr_n);
+			assert(m_awprot[f_const_source] != f_const_prot_n);
+		end
+		if (M_AXI_AWVALID[f_const_slave] && wgrant[f_const_source][f_const_slave])
+		begin
+			assert(M_AXI_AWADDR[f_const_slave*AW+:AW] != f_const_addr_n);
+			assert(M_AXI_AWPROT[f_const_slave*3+:3] != f_const_prot_n);
+		end
+		if (M_AXI_WVALID[f_const_slave] && wgrant[f_const_source][f_const_slave])
+		begin
+			assert(M_AXI_WDATA[f_const_slave*DW+:DW] != f_const_data_n);
+			assert(M_AXI_WSTRB[f_const_slave*(DW/8)+:(DW/8)] != f_const_strb_n);
+		end
+		if (skd_arvalid[f_const_source])
+		begin
+			assert(skd_araddr[f_const_source] != f_const_addr_n);
+			assert(skd_arprot[f_const_source] != f_const_prot_n);
+		end
+		if (dcd_arvalid[f_const_source])
+		begin
+			assert(m_araddr[f_const_source] != f_const_addr_n);
+			assert(m_arprot[f_const_source] != f_const_prot_n);
+		end
+		if (M_AXI_ARVALID[f_const_slave] && rgrant[f_const_source][f_const_slave])
+		begin
+			assert(M_AXI_ARADDR[f_const_slave*AW+:AW] != f_const_addr_n);
+			assert(M_AXI_ARPROT[f_const_slave*3+:3] != f_const_prot_n);
+		end
+		//
+		if (r_bvalid[f_const_source] && wgrant[f_const_source][f_const_slave])
+			assert(r_bresp[f_const_source] != f_const_resp_n);
+		if (S_AXI_BVALID[f_const_source] && wgrant[f_const_source][f_const_slave])
+			assert(S_AXI_BRESP[f_const_source*2+:2] != f_const_resp_n);
+		if (r_rvalid[f_const_source] && rgrant[f_const_source][f_const_slave])
+		begin
+			assert(r_rresp[f_const_source] != f_const_resp_n);
+			assert(r_rdata[f_const_source] != f_const_data_n);
+		end
+		if (S_AXI_RVALID[f_const_source] && rgrant[f_const_source][f_const_slave])
+		begin
+			assert(S_AXI_RRESP[f_const_source*2+:2]!=f_const_resp_n);
+			assert(S_AXI_RDATA[f_const_source*DW+:DW]!=f_const_data_n);
+		end
+	end
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// (Careless) constraining assumptions
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate for(N=0; N<NM; N=N+1)
+	begin
+
+	end endgenerate
+
+`endif
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axim2wbsp.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axim2wbsp.v
new file mode 100644
index 0000000..cf518d5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axim2wbsp.v
@@ -0,0 +1,283 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axim2wbsp.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	So ... this converter works in the other direction from
+//		wbm2axisp.  This converter takes AXI commands, and organizes
+//	them into pipelined wishbone commands.
+//
+//	This particular core treats AXI as two separate buses: one for writes,
+//	and the other for reads.  This particular core combines the two channels
+//	into one.  The designer should be aware that the two AXI buses turned
+//	Wishbone buses can be kept separate as separate inputs to a WB crosssbar
+//	for better performance in some circumstances.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2016-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module axim2wbsp #(
+	parameter  C_AXI_ID_WIDTH	= 2, // The AXI id width used for R&W
+                                             // This is an int between 1-16
+	parameter  C_AXI_DATA_WIDTH	= 32,// Width of the AXI R&W data
+	parameter  C_AXI_ADDR_WIDTH	= 28,	// AXI Address width
+	localparam AXI_LSBS		= $clog2(C_AXI_DATA_WIDTH)-3,
+	localparam DW			= C_AXI_DATA_WIDTH,
+	localparam AW			= C_AXI_ADDR_WIDTH - AXI_LSBS,
+	parameter  LGFIFO		= 5,
+	parameter [0:0]	OPT_READONLY	= 1'b0,
+	parameter [0:0]	OPT_WRITEONLY	= 1'b0
+	) (
+	//
+	input	wire			S_AXI_ACLK,	// System clock
+	input	wire			S_AXI_ARESETN,
+
+	// AXI write address channel signals
+	input	wire			S_AXI_AWVALID,	// Write address valid
+	output	wire			S_AXI_AWREADY, // Slave is ready to rcv
+	input	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_AWID,	// Write ID
+	input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_AWADDR,	// Write address
+	input	wire	[7:0]		S_AXI_AWLEN,	// Write Burst Length
+	input	wire	[2:0]		S_AXI_AWSIZE,	// Write Burst size
+	input	wire	[1:0]		S_AXI_AWBURST,	// Write Burst type
+	input	wire	[0:0]		S_AXI_AWLOCK,	// Write lock type
+	input	wire	[3:0]		S_AXI_AWCACHE,	// Write Cache type
+	input	wire	[2:0]		S_AXI_AWPROT,	// Write Protection type
+	input	wire	[3:0]		S_AXI_AWQOS,	// Write Quality of Svc
+	//
+	// AXI write data channel signals
+	input	wire			S_AXI_WVALID,	// Write valid
+	output	wire			S_AXI_WREADY,  // Write data ready
+	input	wire [C_AXI_DATA_WIDTH-1:0]   S_AXI_WDATA,	// Write data
+	input	wire [C_AXI_DATA_WIDTH/8-1:0] S_AXI_WSTRB,	// Write strobes
+	input	wire			S_AXI_WLAST, // Last write transaction
+	//
+	// AXI write response channel signals
+	output	wire 			S_AXI_BVALID,  // Write reponse valid
+	input	wire			S_AXI_BREADY,  // Response ready
+	output	wire [C_AXI_ID_WIDTH-1:0] S_AXI_BID,	// Response ID
+	output	wire [1:0]		S_AXI_BRESP,	// Write response
+	//
+	// AXI read address channel signals
+	input	wire			S_AXI_ARVALID,	// Read address valid
+	output	wire			S_AXI_ARREADY,	// Read address ready
+	input	wire [C_AXI_ID_WIDTH-1:0]   S_AXI_ARID,	// Read ID
+	input	wire [C_AXI_ADDR_WIDTH-1:0] S_AXI_ARADDR,	// Read address
+	input	wire	[7:0]		S_AXI_ARLEN,	// Read Burst Length
+	input	wire	[2:0]		S_AXI_ARSIZE,	// Read Burst size
+	input	wire	[1:0]		S_AXI_ARBURST,	// Read Burst type
+	input	wire	[0:0]		S_AXI_ARLOCK,	// Read lock type
+	input	wire	[3:0]		S_AXI_ARCACHE,	// Read Cache type
+	input	wire	[2:0]		S_AXI_ARPROT,	// Read Protection type
+	input	wire	[3:0]		S_AXI_ARQOS,	// Read Quality of Svc
+	//
+	// AXI read data channel signals
+	output	wire			S_AXI_RVALID,  // Read reponse valid
+	input	wire			S_AXI_RREADY,  // Read Response ready
+	output	wire [C_AXI_ID_WIDTH-1:0]   S_AXI_RID,     // Response ID
+	output	wire [C_AXI_DATA_WIDTH-1:0] S_AXI_RDATA,    // Read data
+	output	wire			S_AXI_RLAST,    // Read last
+	output	wire [1:0]		S_AXI_RRESP,   // Read response
+
+	// We'll share the clock and the reset
+	output	wire				o_reset,
+	output	wire				o_wb_cyc,
+	output	wire				o_wb_stb,
+	output	wire				o_wb_we,
+	output	wire [(AW-1):0]			o_wb_addr,
+	output	wire [(C_AXI_DATA_WIDTH-1):0]	o_wb_data,
+	output	wire [(C_AXI_DATA_WIDTH/8-1):0]	o_wb_sel,
+	input	wire				i_wb_stall,
+	input	wire				i_wb_ack,
+	input	wire [(C_AXI_DATA_WIDTH-1):0]	i_wb_data,
+	input	wire				i_wb_err
+	);
+	//
+	//
+	//
+
+
+	wire	[(AW-1):0]			w_wb_addr, r_wb_addr;
+	wire	[(C_AXI_DATA_WIDTH-1):0]	w_wb_data;
+	wire	[(C_AXI_DATA_WIDTH/8-1):0]	w_wb_sel;
+	wire	r_wb_err, r_wb_cyc, r_wb_stb, r_wb_stall, r_wb_ack;
+	wire	w_wb_err, w_wb_cyc, w_wb_stb, w_wb_stall, w_wb_ack;
+	wire	r_wb_we, w_wb_we;
+
+	assign	r_wb_we = 1'b0;
+	assign	w_wb_we = 1'b1;
+
+	generate if (!OPT_READONLY)
+	begin : AXI_WR
+	aximwr2wbsp #(
+		.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.LGFIFO(LGFIFO))
+		axi_write_decoder(
+			.S_AXI_ACLK(S_AXI_ACLK), .S_AXI_ARESETN(S_AXI_ARESETN),
+			//
+			.S_AXI_AWVALID(S_AXI_AWVALID),
+			.S_AXI_AWREADY(S_AXI_AWREADY),
+			.S_AXI_AWID(   S_AXI_AWID),
+			.S_AXI_AWADDR( S_AXI_AWADDR),
+			.S_AXI_AWLEN(  S_AXI_AWLEN),
+			.S_AXI_AWSIZE( S_AXI_AWSIZE),
+			.S_AXI_AWBURST(S_AXI_AWBURST),
+			.S_AXI_AWLOCK( S_AXI_AWLOCK),
+			.S_AXI_AWCACHE(S_AXI_AWCACHE),
+			.S_AXI_AWPROT( S_AXI_AWPROT),
+			.S_AXI_AWQOS(  S_AXI_AWQOS),
+			//
+			.S_AXI_WVALID( S_AXI_WVALID),
+			.S_AXI_WREADY( S_AXI_WREADY),
+			.S_AXI_WDATA(  S_AXI_WDATA),
+			.S_AXI_WSTRB(  S_AXI_WSTRB),
+			.S_AXI_WLAST(  S_AXI_WLAST),
+			//
+			.S_AXI_BVALID(S_AXI_BVALID),
+			.S_AXI_BREADY(S_AXI_BREADY),
+			.S_AXI_BID(   S_AXI_BID),
+			.S_AXI_BRESP( S_AXI_BRESP),
+			//
+			.o_wb_cyc(  w_wb_cyc),
+			.o_wb_stb(  w_wb_stb),
+			.o_wb_addr( w_wb_addr),
+			.o_wb_data( w_wb_data),
+			.o_wb_sel(  w_wb_sel),
+			.i_wb_ack(  w_wb_ack),
+			.i_wb_stall(w_wb_stall),
+			.i_wb_err(  w_wb_err)
+		);
+	end else begin
+		assign	w_wb_cyc  = 0;
+		assign	w_wb_stb  = 0;
+		assign	w_wb_addr = 0;
+		assign	w_wb_data = 0;
+		assign	w_wb_sel  = 0;
+		assign	S_AXI_AWREADY = 0;
+		assign	S_AXI_WREADY  = 0;
+		assign	S_AXI_BVALID  = 0;
+		assign	S_AXI_BRESP   = 2'b11;
+		assign	S_AXI_BID     = 0;
+	end endgenerate
+
+	generate if (!OPT_WRITEONLY)
+	begin : AXI_RD
+
+	aximrd2wbsp #(
+		.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.LGFIFO(LGFIFO))
+	axi_read_decoder(
+		.S_AXI_ACLK(S_AXI_ACLK), .S_AXI_ARESETN(S_AXI_ARESETN),
+		//
+		.S_AXI_ARVALID(S_AXI_ARVALID),
+		.S_AXI_ARREADY(S_AXI_ARREADY),
+		.S_AXI_ARID(   S_AXI_ARID),
+		.S_AXI_ARADDR( S_AXI_ARADDR),
+		.S_AXI_ARLEN(  S_AXI_ARLEN),
+		.S_AXI_ARSIZE( S_AXI_ARSIZE),
+		.S_AXI_ARBURST(S_AXI_ARBURST),
+		.S_AXI_ARLOCK( S_AXI_ARLOCK),
+		.S_AXI_ARCACHE(S_AXI_ARCACHE),
+		.S_AXI_ARPROT( S_AXI_ARPROT),
+		.S_AXI_ARQOS(  S_AXI_ARQOS),
+		//
+		.S_AXI_RVALID(S_AXI_RVALID),
+		.S_AXI_RREADY(S_AXI_RREADY),
+		.S_AXI_RID(   S_AXI_RID),
+		.S_AXI_RDATA( S_AXI_RDATA),
+		.S_AXI_RLAST( S_AXI_RLAST),
+		.S_AXI_RRESP( S_AXI_RRESP),
+		//
+		.o_wb_cyc(  r_wb_cyc),
+		.o_wb_stb(  r_wb_stb),
+		.o_wb_addr( r_wb_addr),
+		.i_wb_ack(  r_wb_ack),
+		.i_wb_stall(r_wb_stall),
+		.i_wb_data( i_wb_data),
+		.i_wb_err(  r_wb_err)
+		);
+	end else begin
+		assign	r_wb_cyc  = 0;
+		assign	r_wb_stb  = 0;
+		assign	r_wb_addr = 0;
+		//
+		assign S_AXI_ARREADY = 0;
+		assign S_AXI_RVALID  = 0;
+		assign S_AXI_RID     = 0;
+		assign S_AXI_RDATA   = 0;
+		assign S_AXI_RLAST   = 0;
+		assign S_AXI_RRESP   = 0;
+	end endgenerate
+
+	generate if (OPT_READONLY)
+	begin : ARB_RD
+		assign	o_wb_cyc  = r_wb_cyc;
+		assign	o_wb_stb  = r_wb_stb;
+		assign	o_wb_we   = r_wb_we;
+		assign	o_wb_addr = r_wb_addr;
+		assign	o_wb_data = 0;
+		assign	o_wb_sel  = 0;
+		assign	r_wb_ack  = i_wb_ack;
+		assign	r_wb_stall= i_wb_stall;
+		assign	r_wb_ack  = i_wb_ack;
+		assign	r_wb_err  = i_wb_err;
+
+	end else if (OPT_WRITEONLY)
+	begin : ARB_WR
+		assign	o_wb_cyc  = w_wb_cyc;
+		assign	o_wb_stb  = w_wb_stb;
+		assign	o_wb_we   = w_wb_we;
+		assign	o_wb_addr = w_wb_addr;
+		assign	o_wb_data = w_wb_data;
+		assign	o_wb_sel  = w_wb_sel;
+		assign	w_wb_ack  = i_wb_ack;
+		assign	w_wb_stall= i_wb_stall;
+		assign	w_wb_ack  = i_wb_ack;
+		assign	w_wb_err  = i_wb_err;
+
+	end else begin : ARB_WB
+		wbarbiter	#(.DW(DW), .AW(AW))
+		readorwrite(S_AXI_ACLK, o_reset,
+			r_wb_cyc, r_wb_stb, r_wb_we, r_wb_addr, w_wb_data, w_wb_sel,
+				r_wb_ack, r_wb_stall, r_wb_err,
+			w_wb_cyc, w_wb_stb, w_wb_we, w_wb_addr, w_wb_data, w_wb_sel,
+				w_wb_ack, w_wb_stall, w_wb_err,
+			o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, o_wb_sel,
+				i_wb_ack, i_wb_stall, i_wb_err
+			);
+	end endgenerate
+
+	assign	o_reset = (S_AXI_ARESETN == 1'b0);
+
+`ifdef	FORMAL
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/aximm2s.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/aximm2s.v
new file mode 100644
index 0000000..4aacd78
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/aximm2s.v
@@ -0,0 +1,1936 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	aximm2s
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Converts an AXI (full) memory port to an AXI-stream
+//		interface.
+// // {{{
+//	While I am aware that other vendors sell similar components, if you
+//	look under the hood you'll find no relation to anything but my own
+//	work here.
+//
+// Registers:
+//
+//  0:	CMD_CONTROL
+//		Controls the transaction via either starting or aborting an
+//		ongoing transaction, provides feedback regarding the current
+//		status.
+//
+//	[31]	r_busy
+//		True if the core is in the middle of a transaction
+//
+//	[30]	r_err
+//		True if the core has detected an error, a bus error
+//		while the FIFO is reading.
+//
+//		Writing a '1' to this bit while the core is idle will clear it.
+//		New transfers will not start until this bit is cleared.
+//
+//	[29]	r_complete
+//		True if the transaction has completed, whether normally or
+//		abnormally (error or abort).
+//
+//		Any write to the CMD_CONTROL register will clear this flag.
+//
+//	[28]	r_continuous
+//		Normally the FIFO gets cleared and reset between operations.
+//		However, if you set r_continuous, the core will then expect
+//		a second operation to take place following the first one.
+//		In this case, the operation will complete but the FIFO won't
+//		get cleared.  During this time, the FIFO will not fill further.
+//
+//		Any write to the CMD_CONTROL register while the core is not
+//		busy will adjust this bit.
+//
+//	[27]	!r_increment
+//
+//		If clear, the core reads from subsequent and incrementing
+//		addresses.  If set, the core reads from the same address
+//		throughout a transaction.
+//
+//		Writes to CMD_CONTROL while the core is idle will adjust this
+//		bit.
+//
+//	[20:16]	LGFIFO
+//		These are read-only bits, returning the size of the FIFO.
+//
+//	ABORT
+//		If the core is busy, and ABORT_KEY (currently set to 8'h6d
+//		below) is written to the top 8-bits of this register,
+//		the current transfer will be aborted.  Any pending reads
+//		will be completed, but nothing more will be written to the
+//		stream.
+//
+//		Alternatively, the core will enter into an abort state
+//		following any returned bus error indications.
+//
+//  4:	(Unused and reserved)
+//
+//  8-c:	CMD_ADDRLO, CMD_ADDR_HI
+//	[C_AXI_ADDR_WIDTH-1:($clog2(C_AXI_DATA_WIDTH)-3)]
+//		If idle, the address the core will read from when it starts.
+//		If busy, the address the core is currently reading from.
+//		Upon completion, the address either returns to the starting
+//		address (if r_continuous is clear), or otherwise becomes the
+//		address where the core left off.  In the case of an abort or an
+//		error, this will be (near) the address that was last read.
+//
+//		Why "near"?  Because this address records the reads that have
+//		been issued while no error is pending.  If a bus error return
+//		comes back, there may have been several more reads issued before
+//		that error address.
+//
+//  10-14:	(Unused and reserved)
+//
+//  18-1c:  CMD_LENLO, CMD_LENHI
+//	[LGLEN-1:0]
+//		The size of the transfer in bytes.  Only accepts aligned
+//		addresses, therefore bits [($clog2(C_AXI_DATA_WIDTH)-3):0]
+//		will always be forced to zero.  To find out what size bus
+//		this core is conencted to, or the maximum transfer length,
+//		write a -1 to this value and read the returning result.
+//		Only the active bits will be set.
+//
+//		While the core is busy, reads from this address will return
+//		the number of items still to be read from the bus.
+//
+//		I hope to eventually add support for unaligned bursts.  Such
+//		support is not currently part of this core.
+//
+// }}}
+//
+// Status:
+// {{{
+//	1. The core passes both cover checks and formal property (assertion)
+//		based checks.  It has not (yet) been tested in real hardware.
+//
+//	2. I'd like to support unaligned addresses and lengths.  This will
+//		require aligning the data coming out of the FIFO as well.
+//		As written, the core doesn't yet support these.
+//
+// }}}
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+//
+`default_nettype none
+//
+module	aximm2s #(
+		// {{{
+		parameter	C_AXI_ADDR_WIDTH = 32,
+		parameter	C_AXI_DATA_WIDTH = 32,
+		parameter	C_AXI_ID_WIDTH = 1,
+		//
+		// We support five 32-bit AXI-lite registers, requiring 5-bits
+		// of AXI-lite addressing
+		localparam	C_AXIL_ADDR_WIDTH = 5,
+		localparam	C_AXIL_DATA_WIDTH = 32,
+		//
+		// The bottom ADDRLSB bits of any AXI address are subword bits
+		localparam	ADDRLSB = $clog2(C_AXI_DATA_WIDTH)-3,
+		localparam	AXILLSB = $clog2(C_AXIL_DATA_WIDTH)-3,
+		//
+		// OPT_UNALIGNED: Allow unaligned accesses, address requests
+		// and sizes which may or may not match the underlying data
+		// width.  If set, the core will quietly align these requests.
+		parameter [0:0]	OPT_UNALIGNED = 1'b0,
+		//
+		// OPT_TKEEP [Future]: If set, will also add TKEEP signals to
+		// the outgoing slave interface.  This is necessary if ever you
+		// wish to output partial stream words, such as might happen if
+		// the length were ever something other than a full number of
+		// words.  (Not yet implemented)
+		// parameter [0:0]	OPT_TKEEP = 1'b0,
+		//
+		// OPT_TLAST: If enabled, will embed TLAST=1 at the end of every
+		// commanded burst.  If  disabled, TLAST will be set to a
+		// constant 1'b1.
+		parameter [0:0]	OPT_TLAST = 1'b0,
+		//
+		// ABORT_KEY is the value that, when written to the top 8-bits
+		// of the control word, will abort any ongoing operation.
+		parameter [7:0]	ABORT_KEY = 8'h6d,
+		//
+		// The size of the FIFO
+		parameter	LGFIFO = 9,
+		//
+		// Maximum number of bytes that can ever be transferred, in
+		// log-base 2
+		parameter	LGLEN  = 20,
+		//
+		// AXI_ID is the ID we will use for all of our AXI transactions
+		parameter	AXI_ID = 0
+		// }}}
+	) (
+		// {{{
+		input	wire					S_AXI_ACLK,
+		input	wire					S_AXI_ARESETN,
+		//
+		// The stream interface
+		// {{{
+		output	wire					M_AXIS_TVALID,
+		input	wire					M_AXIS_TREADY,
+		output	wire	[C_AXI_DATA_WIDTH-1:0]		M_AXIS_TDATA,
+		output	wire					M_AXIS_TLAST,
+		// }}}
+		//
+		// The control interface
+		// {{{
+		input	wire					S_AXIL_AWVALID,
+		output	wire					S_AXIL_AWREADY,
+		input	wire	[C_AXIL_ADDR_WIDTH-1:0]		S_AXIL_AWADDR,
+		input	wire	[2:0]				S_AXIL_AWPROT,
+		//
+		input	wire					S_AXIL_WVALID,
+		output	wire					S_AXIL_WREADY,
+		input	wire	[C_AXIL_DATA_WIDTH-1:0]		S_AXIL_WDATA,
+		input	wire	[C_AXIL_DATA_WIDTH/8-1:0]	S_AXIL_WSTRB,
+		//
+		output	wire					S_AXIL_BVALID,
+		input	wire					S_AXIL_BREADY,
+		output	wire	[1:0]				S_AXIL_BRESP,
+		//
+		input	wire					S_AXIL_ARVALID,
+		output	wire					S_AXIL_ARREADY,
+		input	wire	[C_AXIL_ADDR_WIDTH-1:0]		S_AXIL_ARADDR,
+		input	wire	[2:0]				S_AXIL_ARPROT,
+		//
+		output	wire					S_AXIL_RVALID,
+		input	wire					S_AXIL_RREADY,
+		output	wire	[C_AXIL_DATA_WIDTH-1:0]		S_AXIL_RDATA,
+		output	wire	[1:0]				S_AXIL_RRESP,
+		// }}}
+		//
+
+		//
+		// The AXI (full) read interface
+		// {{{
+		output	wire				M_AXI_ARVALID,
+		input	wire				M_AXI_ARREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_ARID,
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_ARADDR,
+		output	wire	[7:0]			M_AXI_ARLEN,
+		output	wire	[2:0]			M_AXI_ARSIZE,
+		output	wire	[1:0]			M_AXI_ARBURST,
+		output	wire				M_AXI_ARLOCK,
+		output	wire	[3:0]			M_AXI_ARCACHE,
+		output	wire	[2:0]			M_AXI_ARPROT,
+		output	wire	[3:0]			M_AXI_ARQOS,
+		//
+		input	wire				M_AXI_RVALID,
+		output	wire				M_AXI_RREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_RDATA,
+		input	wire				M_AXI_RLAST,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_RID,
+		input	wire	[1:0]			M_AXI_RRESP,
+		// }}}
+		//
+		//
+		// Create an output signal to indicate that we've finished
+		output	reg				o_int
+		// }}}
+	);
+	// Local parameter declarations
+	// {{{
+	localparam [2:0]	CMD_CONTROL   = 3'b000,
+				CMD_UNUSED_1  = 3'b001,
+				CMD_ADDRLO    = 3'b010,
+				CMD_ADDRHI    = 3'b011,
+				CMD_UNUSED_2  = 3'b100,
+				CMD_UNUSED_3  = 3'b101,
+				CMD_LENLO     = 3'b110,
+				CMD_LENHI     = 3'b111;
+	localparam		CBIT_BUSY	= 31,
+				CBIT_ERR	= 30,
+				CBIT_COMPLETE	= 29,
+				CBIT_CONTINUOUS	= 28,
+				CBIT_INCREMENT	= 27;
+	localparam	LGMAXBURST=(LGFIFO > 8) ? 8 : LGFIFO-1;
+	localparam	LGMAX_FIXED_BURST = 4,
+			MAX_FIXED_BURST = 16;
+	localparam	LGLENW  = LGLEN  - ($clog2(C_AXI_DATA_WIDTH)-3),
+			LGLENWA = LGLENW + (OPT_UNALIGNED ? 1:0);
+	localparam	LGFIFOB = LGFIFO + ($clog2(C_AXI_DATA_WIDTH)-3);
+	localparam [ADDRLSB-1:0] LSBZEROS = 0;
+	// }}}
+
+	wire	i_clk   =  S_AXI_ACLK;
+	wire	i_reset = !S_AXI_ARESETN;
+
+	// Signal declarations
+	// {{{
+	reg	r_busy, r_err, r_complete, r_continuous, r_increment,
+		cmd_abort, zero_length,
+		w_cmd_start, w_complete, w_cmd_abort;
+	// reg	cmd_start;
+	reg				axi_abort_pending;
+
+	reg	[LGLENWA-1:0]		ar_requests_remaining,
+					ar_bursts_outstanding;
+	reg	[LGMAXBURST:0]		r_max_burst;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	axi_raddr;
+
+	reg	[C_AXI_ADDR_WIDTH-1:0]	cmd_addr;
+	reg	[LGLENW-1:0]		cmd_length_w;
+	reg	[LGLENWA-1:0]		cmd_length_aligned_w;
+	reg				unaligned_cmd_addr;
+
+	// FIFO signals
+	wire				reset_fifo, write_to_fifo,
+					read_from_fifo;
+	wire	[C_AXI_DATA_WIDTH-1:0]	write_data;
+	wire	[LGFIFO:0]		fifo_fill;
+	wire				fifo_full, fifo_empty;
+
+	wire				awskd_valid, axil_write_ready;
+	wire	[C_AXIL_ADDR_WIDTH-AXILLSB-1:0]	awskd_addr;
+	//
+	wire				wskd_valid;
+	wire	[C_AXIL_DATA_WIDTH-1:0]	wskd_data;
+	wire [C_AXIL_DATA_WIDTH/8-1:0]	wskd_strb;
+	reg				axil_bvalid;
+	//
+	wire				arskd_valid, axil_read_ready;
+	wire	[C_AXIL_ADDR_WIDTH-AXILLSB-1:0]	arskd_addr;
+	reg	[C_AXIL_DATA_WIDTH-1:0]	axil_read_data;
+	reg				axil_read_valid;
+	reg	[C_AXIL_DATA_WIDTH-1:0]	w_status_word;
+	reg	[2*C_AXIL_DATA_WIDTH-1:0]	wide_address, wide_length,
+					new_wideaddr, new_widelen;
+	wire	[C_AXIL_DATA_WIDTH-1:0]	new_cmdaddrlo, new_cmdaddrhi,
+					new_lengthlo, new_lengthhi;
+
+
+
+	reg				axi_arvalid;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	axi_araddr;
+	reg	[7:0]			axi_arlen;
+	reg	[1:0]			axi_arburst;
+
+	// Speed up checking for zeros
+	reg				ar_none_remaining,
+					ar_none_outstanding,
+					phantom_start, start_burst;
+	reg				partial_burst_requested;
+	reg	[LGMAXBURST-1:0]	addralign;
+	reg	[LGFIFO:0]		rd_uncommitted;
+	reg				w_increment;
+	reg	[LGMAXBURST:0]		initial_burstlen;
+	reg	[LGLENWA-1:0]		rd_reads_remaining;
+	reg				rd_none_remaining,
+					rd_last_remaining;
+
+	wire				realign_last_valid;
+/*
+					wr_none_pending, r_none_remaining;
+
+	reg				w_phantom_start, phantom_start;
+	reg	[LGFIFO:0]	next_fill;
+*/
+
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite signaling
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// This is mostly the skidbuffer logic, and handling of the VALID
+	// and READY signals for the AXI-lite control logic in the next
+	// section.
+	// {{{
+
+	//
+	// Write signaling
+	//
+	// {{{
+
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_ADDR_WIDTH-AXILLSB))
+	axilawskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_AWVALID), .o_ready(S_AXIL_AWREADY),
+		.i_data(S_AXIL_AWADDR[C_AXIL_ADDR_WIDTH-1:AXILLSB]),
+		.o_valid(awskd_valid), .i_ready(axil_write_ready),
+		.o_data(awskd_addr));
+
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_DATA_WIDTH+C_AXIL_DATA_WIDTH/8))
+	axilwskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_WVALID), .o_ready(S_AXIL_WREADY),
+		.i_data({ S_AXIL_WDATA, S_AXIL_WSTRB }),
+		.o_valid(wskd_valid), .i_ready(axil_write_ready),
+		.o_data({ wskd_data, wskd_strb }));
+
+	assign	axil_write_ready = awskd_valid && wskd_valid
+			&& (!S_AXIL_BVALID || S_AXIL_BREADY);
+
+	initial	axil_bvalid = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		axil_bvalid <= 0;
+	else if (axil_write_ready)
+		axil_bvalid <= 1;
+	else if (S_AXIL_BREADY)
+		axil_bvalid <= 0;
+
+	assign	S_AXIL_BVALID = axil_bvalid;
+	assign	S_AXIL_BRESP = 2'b00;
+	// }}}
+
+	//
+	// Read signaling
+	//
+	// {{{
+
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_ADDR_WIDTH-AXILLSB))
+	axilarskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_ARVALID), .o_ready(S_AXIL_ARREADY),
+		.i_data(S_AXIL_ARADDR[C_AXIL_ADDR_WIDTH-1:AXILLSB]),
+		.o_valid(arskd_valid), .i_ready(axil_read_ready),
+		.o_data(arskd_addr));
+
+	assign	axil_read_ready = arskd_valid
+				&& (!axil_read_valid || S_AXIL_RREADY);
+
+	initial	axil_read_valid = 1'b0;
+	always @(posedge i_clk)
+	if (i_reset)
+		axil_read_valid <= 1'b0;
+	else if (axil_read_ready)
+		axil_read_valid <= 1'b1;
+	else if (S_AXIL_RREADY)
+		axil_read_valid <= 1'b0;
+
+	assign	S_AXIL_RVALID = axil_read_valid;
+	assign	S_AXIL_RDATA  = axil_read_data;
+	assign	S_AXIL_RRESP = 2'b00;
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite controlled logic
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	//
+	// Abort transaction
+	//
+	always @(*)
+	begin
+		w_cmd_abort = 0;
+		w_cmd_abort = (axil_write_ready && awskd_addr == CMD_CONTROL)
+			&& (wskd_strb[3] && wskd_data[31:24] == ABORT_KEY);
+		if (!r_busy)
+			w_cmd_abort = 0;
+	end
+
+	initial	cmd_abort = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		cmd_abort <= 0;
+	else
+		cmd_abort <= (cmd_abort && r_busy)||w_cmd_abort;
+
+	//
+	// Start command
+	//
+	always @(*)
+	if (r_busy)
+		w_cmd_start = 0;
+	else begin
+		w_cmd_start = 0;
+		if ((axil_write_ready && awskd_addr == CMD_CONTROL)
+			&& (wskd_strb[3] && wskd_data[CBIT_BUSY]))
+			w_cmd_start = 1;
+		if (r_err && !wskd_data[CBIT_ERR])
+			w_cmd_start = 0;
+		if (zero_length)
+			w_cmd_start = 0;
+		if (OPT_UNALIGNED && unaligned_cmd_addr
+				&& wskd_data[CBIT_INCREMENT])
+			w_cmd_start = 0;
+	end
+
+	//
+	// Calculate busy or complete flags
+	//
+	initial	r_busy     = 0;
+	initial	r_complete = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		r_busy     <= 0;
+		r_complete <= 0;
+	end else if (!r_busy)
+	begin
+		if (w_cmd_start)
+			r_busy <= 1'b1;
+		if (axil_write_ready && awskd_addr == CMD_CONTROL)
+			// Any write to the control register will clear the
+			// completion flag
+			r_complete <= 1'b0;
+	end else if (r_busy)
+	begin
+		if (w_complete)
+		begin
+			r_complete <= 1;
+			r_busy <= 1'b0;
+		end
+	end
+
+	//
+	// Interrupts
+	//
+	initial	o_int = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		o_int <= 0;
+	else
+		o_int <= (r_busy && w_complete);
+
+	//
+	// Error conditions
+	//
+	always @(posedge i_clk)
+	if (i_reset)
+		r_err <= 0;
+	else if (!r_busy)
+	begin
+		if (axil_write_ready && awskd_addr == CMD_CONTROL)
+		begin
+			if (!w_cmd_abort)
+				r_err <= r_err && (!wskd_strb[3] || !wskd_data[CBIT_ERR]);
+			// On any request to start a transfer with an unaligned
+			// address, that's not incrementing--declare an
+			// immediate error
+			if (wskd_strb[3] && wskd_data[CBIT_BUSY]
+				&& wskd_data[CBIT_INCREMENT]
+				&& (OPT_UNALIGNED && unaligned_cmd_addr))
+				r_err <= 1'b1;
+		end
+	end else // if (r_busy)
+	begin
+		if (M_AXI_RVALID && M_AXI_RREADY && M_AXI_RRESP[1])
+			r_err <= 1'b1;
+	end
+
+	initial	r_continuous = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		r_continuous <= 0;
+	else begin
+		if (!r_busy && axil_write_ready && awskd_addr == CMD_CONTROL
+			&& !w_cmd_abort)
+			r_continuous <= wskd_strb[3] && wskd_data[CBIT_CONTINUOUS];
+	end
+
+	always @(*)
+	begin
+		wide_address = 0;
+		wide_address[C_AXI_ADDR_WIDTH-1:0] = cmd_addr;
+		if (!OPT_UNALIGNED)
+			wide_address[ADDRLSB-1:0] = 0;
+
+		wide_length  = 0;
+		wide_length[ADDRLSB +: LGLENW] = cmd_length_w;
+	end
+
+	assign	new_cmdaddrlo = apply_wstrb(
+			wide_address[C_AXIL_DATA_WIDTH-1:0],
+			wskd_data, wskd_strb);
+
+	assign	new_cmdaddrhi = apply_wstrb(
+			wide_address[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH],
+			wskd_data, wskd_strb);
+
+	assign	new_lengthlo = apply_wstrb(
+			wide_length[C_AXIL_DATA_WIDTH-1:0],
+			wskd_data, wskd_strb);
+
+	assign	new_lengthhi = apply_wstrb(
+			wide_length[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH],
+			wskd_data, wskd_strb);
+
+	always @(*)
+	begin
+		new_wideaddr = wide_address;
+
+		if (awskd_addr == CMD_ADDRLO)
+			new_wideaddr[C_AXIL_DATA_WIDTH-1:0] = new_cmdaddrlo;
+		if (awskd_addr == CMD_ADDRHI)
+			new_wideaddr[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH] = new_cmdaddrhi;
+		if (!OPT_UNALIGNED)
+			new_wideaddr[ADDRLSB-1:0] = 0;
+		new_wideaddr[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH] = 0;
+
+
+		new_widelen = wide_length;
+		if (awskd_addr == CMD_LENLO)
+			new_widelen[C_AXIL_DATA_WIDTH-1:0] = new_lengthlo;
+		if (awskd_addr == CMD_LENHI)
+			new_widelen[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH] = new_lengthhi;
+		new_widelen[ADDRLSB-1:0] = 0;
+		new_widelen[2*C_AXIL_DATA_WIDTH-1:ADDRLSB+LGLENW] = 0;
+	end
+
+
+	initial	r_increment   = 1'b1;
+	initial	cmd_addr      = 0;
+	initial	cmd_length_w  = 0;	// Counts in bytes
+	initial	zero_length   = 1;
+	initial	cmd_length_aligned_w = 0;
+	initial	unaligned_cmd_addr = 1'b0;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		r_increment <= 1'b1;
+		cmd_addr      <= 0;
+		cmd_length_w  <= 0;
+		cmd_length_aligned_w  <= 0;
+		zero_length   <= 1;
+		unaligned_cmd_addr <= 1'b0;
+	end else if (axil_write_ready && !r_busy)
+	begin
+		case(awskd_addr)
+		CMD_CONTROL:
+			r_increment <= !wskd_data[CBIT_INCREMENT];
+		CMD_ADDRLO: begin
+			cmd_addr <= new_wideaddr[C_AXI_ADDR_WIDTH-1:0];
+			unaligned_cmd_addr <= |new_wideaddr[ADDRLSB-1:0];
+			if (!OPT_UNALIGNED)
+				unaligned_cmd_addr <= 1'b0;
+			else
+				cmd_length_aligned_w <= cmd_length_w
+					+ (|new_wideaddr[ADDRLSB-1:0] ? 1:0);
+			// ERR: What if !r_increment?  In that case, we can't
+			//   support unaligned addressing
+			end
+		CMD_ADDRHI: if (C_AXI_ADDR_WIDTH > C_AXIL_DATA_WIDTH)
+			begin
+			cmd_addr <= new_wideaddr[C_AXI_ADDR_WIDTH-1:0];
+			end
+		CMD_LENLO: begin
+			cmd_length_w <= new_widelen[ADDRLSB +: LGLENW];
+			zero_length <= (new_widelen[ADDRLSB +: LGLENW] == 0);
+			cmd_length_aligned_w <= new_widelen[ADDRLSB +: LGLENW]
+				+ (unaligned_cmd_addr ? 1:0);
+			end
+		CMD_LENHI: begin
+			cmd_length_w <= new_widelen[ADDRLSB +: LGLENW];
+			zero_length <= (new_widelen[ADDRLSB +: LGLENW] == 0);
+			cmd_length_aligned_w <= new_widelen[ADDRLSB +: LGLENW]
+				+ (unaligned_cmd_addr ? 1:0);
+			end
+		default: begin end
+		endcase
+	end else if(r_busy && r_continuous && !axi_abort_pending && r_increment)
+		cmd_addr <= axi_raddr
+			+ ((M_AXI_RVALID && !M_AXI_RRESP[1]
+				&& (!unaligned_cmd_addr || realign_last_valid))
+				? (1<<ADDRLSB) : 0);
+
+	always @(*)
+	begin
+		w_status_word = 0;
+		w_status_word[CBIT_BUSY]	= r_busy;
+		w_status_word[CBIT_ERR]		= r_err;
+		w_status_word[CBIT_COMPLETE]	= r_complete;
+		w_status_word[CBIT_CONTINUOUS]	= r_continuous;
+		w_status_word[CBIT_INCREMENT]	= !r_increment;
+		w_status_word[20:16] = LGFIFO;
+	end
+
+	always @(posedge i_clk)
+	if (!axil_read_valid || S_AXIL_RREADY)
+	begin
+		axil_read_data <= 0;
+		case(arskd_addr)
+		CMD_CONTROL:	axil_read_data <= w_status_word;
+		CMD_ADDRLO:	axil_read_data <= wide_address[C_AXIL_DATA_WIDTH-1:0];
+		CMD_ADDRHI:	axil_read_data <= wide_address[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+		CMD_LENLO:	axil_read_data <= wide_length[C_AXIL_DATA_WIDTH-1:0];
+		CMD_LENHI:	axil_read_data <= wide_length[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+		default		axil_read_data <= 0;
+		endcase
+	end
+
+	function [C_AXIL_DATA_WIDTH-1:0]	apply_wstrb;
+		input	[C_AXIL_DATA_WIDTH-1:0]		prior_data;
+		input	[C_AXIL_DATA_WIDTH-1:0]		new_data;
+		input	[C_AXIL_DATA_WIDTH/8-1:0]	wstrb;
+
+		integer	k;
+		for(k=0; k<C_AXIL_DATA_WIDTH/8; k=k+1)
+		begin
+			apply_wstrb[k*8 +: 8]
+				= wstrb[k] ? new_data[k*8 +: 8] : prior_data[k*8 +: 8];
+		end
+	endfunction
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The data FIFO section
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	assign	reset_fifo = i_reset || (!r_busy && (!r_continuous || r_err));
+
+	// Realign the data (if OPT_UNALIGN) before sending it to the FIFO
+	// {{{
+	// This allows us to handle unaligned addresses.
+	generate if (OPT_UNALIGNED)
+	begin : REALIGN_DATA
+
+		reg				r_write_to_fifo;
+		reg	[C_AXI_DATA_WIDTH-1:0]	last_data,
+						r_write_data;
+		reg	[ADDRLSB-1:0]		corollary_shift;
+		reg				last_valid;
+		reg	[ADDRLSB-1:0]		realignment;
+
+		always @(*)
+			realignment = cmd_addr[ADDRLSB-1:0];
+
+		initial	last_data = 0;
+		always @(posedge S_AXI_ACLK)
+		if (reset_fifo || !unaligned_cmd_addr)
+			last_data <= 0;
+		else if (M_AXI_RVALID && M_AXI_RREADY)
+			last_data <= M_AXI_RDATA >> (realignment * 8);
+
+		initial	last_valid = 1'b0;
+		always @(posedge S_AXI_ACLK)
+		if (reset_fifo)
+			last_valid <= 0;
+		else if (M_AXI_RVALID && M_AXI_RREADY)
+			last_valid <= 1'b1;
+		else if (!r_busy)
+			last_valid <= 1'b0;
+
+		assign	realign_last_valid = last_valid;
+
+		always @(*)
+			corollary_shift = -realignment*8;
+
+		always @(posedge S_AXI_ACLK)
+		if (M_AXI_RVALID && M_AXI_RREADY)
+			r_write_data <= (M_AXI_RDATA << corollary_shift)
+					| last_data;
+		else if (!fifo_full)
+			r_write_data <= last_data;
+
+		initial	r_write_to_fifo = 1'b0;
+		always @(posedge S_AXI_ACLK)
+		if (reset_fifo)
+			r_write_to_fifo <= 1'b0;
+		else if (M_AXI_RVALID && M_AXI_RREADY)
+			r_write_to_fifo <= last_valid || !unaligned_cmd_addr;
+		else if (!fifo_full)
+			r_write_to_fifo <= 1'b0;
+
+		assign	write_to_fifo = r_write_to_fifo;
+		assign	write_data = r_write_data;
+
+	end else begin : ALIGNED_DATA
+
+		assign	write_to_fifo  = M_AXI_RVALID && M_AXI_RREADY;
+		assign	write_data = M_AXI_RDATA;
+		assign	realign_last_valid = 0;
+
+	end endgenerate
+	// }}}
+
+	assign	read_from_fifo = M_AXIS_TVALID && M_AXIS_TREADY;
+	assign	M_AXIS_TVALID  = !fifo_empty;
+
+	// Write the results to the FIFO
+	// {{{
+	generate if (OPT_TLAST)
+	begin : FIFO_W_TLAST
+		// FIFO section--used if we have to add a TLAST signal to the
+		// data stream
+		// {{{
+		reg	pre_tlast;
+		wire	tlast;
+
+		// tlast will be set on the last data word of any commanded
+		// burst.
+
+		// Appropriately, pre_tlast = (something) && M_AXI_RVALID
+		//			&& M_AXI_RREADY && M_AXI_RLAST
+		// We can simplify this greatly, since any time M_AXI_RVALID is
+		// true, we also know that M_AXI_RREADY will be true.  This
+		// allows us to get rid of the RREADY condition.  Next, we can
+		// simplify the RVALID condition since we'll never write to the
+		// FIFO if RVALID isn't also true.  Finally, we can get rid of
+		// M_AXI_RLAST since this is captured by rd_last_remaining.
+		always @(*)
+			pre_tlast = rd_last_remaining;
+
+		if (OPT_UNALIGNED)
+		begin
+			reg	r_tlast;
+
+			// REALIGN delays the data by one clock period.  We'll
+			// also need to delay the last as well.
+			// Note that no one cares what tlast is if write_to_fifo
+			// is zero, allowing us to massively simplify this.
+			always @(posedge i_clk)
+				r_tlast <= pre_tlast;
+
+			assign	tlast = r_tlast;
+
+		end else begin
+
+			assign	tlast = pre_tlast;
+		end
+
+
+		sfifo #(.BW(C_AXI_DATA_WIDTH+1), .LGFLEN(LGFIFO))
+		sfifo(i_clk, reset_fifo,
+			write_to_fifo, { tlast, write_data }, fifo_full, fifo_fill,
+			read_from_fifo, { M_AXIS_TLAST, M_AXIS_TDATA }, fifo_empty);
+		// }}}
+	end else begin : NO_TLAST_FIFO
+
+		// FIFO section, where TLAST is held at 1'b1
+		// {{{
+		sfifo #(.BW(C_AXI_DATA_WIDTH), .LGFLEN(LGFIFO))
+		sfifo(i_clk, reset_fifo,
+			write_to_fifo, write_data, fifo_full, fifo_fill,
+			read_from_fifo, M_AXIS_TDATA, fifo_empty);
+
+		assign	M_AXIS_TLAST = 1'b1;
+		// }}}
+	end endgenerate
+	// }}}
+
+
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The incoming AXI (full) protocol section
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// {{{
+
+	// Some counters to keep track of our state
+	// {{{
+
+
+	// Count the number of word writes left to be requested, starting
+	// with the overall command length and then reduced by M_AWLEN on
+	// each address write
+	// {{{
+	initial	ar_none_remaining = 1;
+	initial	ar_requests_remaining = 0;
+	always @(posedge i_clk)
+	if (!r_busy)
+	begin
+		ar_requests_remaining <= cmd_length_aligned_w;
+		ar_none_remaining     <= zero_length;
+	end else if (cmd_abort || axi_abort_pending)
+	begin
+		ar_requests_remaining <= 0;
+		ar_none_remaining <= 1;
+	end else if (phantom_start)
+	begin
+		// Verilator lint_off WIDTH
+		ar_requests_remaining
+			<= ar_requests_remaining - (M_AXI_ARLEN + 1);
+		ar_none_remaining <= (ar_requests_remaining == (M_AXI_ARLEN+1));
+		// Verilator lint_on WIDTH
+	end
+	// }}}
+
+	// Calculate the maximum possible burst length, ignoring 4kB boundaries
+	// {{{
+	always @(*)
+		addralign = 1+(~cmd_addr[ADDRLSB +: LGMAXBURST]);
+	always @(*)
+		w_increment = !wskd_data[CBIT_INCREMENT];
+
+	always @(*)
+	begin
+		initial_burstlen = (1<<LGMAXBURST);
+		if (!w_increment)
+		begin
+			if (LGMAXBURST <= LGMAX_FIXED_BURST)
+				initial_burstlen = (1<<LGMAXBURST);
+			else
+				initial_burstlen = MAX_FIXED_BURST;
+			if (cmd_length_aligned_w < { {(LGLENWA-LGMAXBURST-1){1'b0}},
+						initial_burstlen })
+				initial_burstlen = cmd_length_aligned_w[LGMAXBURST:0];
+		end else if (cmd_length_aligned_w >= (1<<LGMAXBURST))
+		begin
+			if (|cmd_addr[ADDRLSB +: LGMAXBURST])
+				initial_burstlen = { 1'b0, addralign };
+		end else begin
+			initial_burstlen = cmd_length_aligned_w[LGMAXBURST:0];
+			if ((|cmd_addr[ADDRLSB +: LGMAXBURST])
+				&&({{(LGLENW-LGMAXBURST){1'b0}}, addralign } < cmd_length_aligned_w))
+				initial_burstlen = { 1'b0, addralign };
+		end
+	end
+
+	initial	r_max_burst = 0;
+	always @(posedge i_clk)
+	if (!r_busy)
+	begin
+		// Force us to align ourself early
+		//   That way we don't need to check for
+		//   alignment (again) later
+		r_max_burst <= initial_burstlen;
+	end else if (phantom_start)
+	begin
+		// Verilator lint_off WIDTH
+		if (r_increment || LGMAXBURST <= LGMAX_FIXED_BURST)
+		begin : LIMIT_BY_LGMAXBURST
+			if (ar_requests_remaining < (1<<LGMAXBURST) + (M_AXI_ARLEN+1))
+				r_max_burst <= ar_requests_remaining[8:0] - (M_AXI_ARLEN+1);
+			else
+				r_max_burst <= (1<<LGMAXBURST);
+		end else begin : LIMIT_BY_SIXTEEN
+			if (ar_requests_remaining < MAX_FIXED_BURST + (M_AXI_ARLEN+1))
+				r_max_burst <= ar_requests_remaining[8:0] - (M_AXI_ARLEN+1);
+			else
+				r_max_burst <= MAX_FIXED_BURST;
+		end
+		// Verilator lint_on WIDTH
+	end
+	// }}}
+
+	// Count the number of bursts outstanding--these are the number of
+	// ARVALIDs that have been accepted, but for which the RVALID && RLAST
+	// has not (yet) been returned.
+	// {{{
+	initial	ar_none_outstanding   = 1;
+	initial	ar_bursts_outstanding = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		ar_bursts_outstanding <= 0;
+		ar_none_outstanding <= 1;
+	end else case ({ phantom_start,
+				M_AXI_RVALID && M_AXI_RREADY && M_AXI_RLAST })
+	2'b01:	begin
+			ar_bursts_outstanding <=  ar_bursts_outstanding - 1;
+			ar_none_outstanding   <= (ar_bursts_outstanding == 1);
+		end
+	2'b10:	begin
+		ar_bursts_outstanding <= ar_bursts_outstanding + 1;
+		ar_none_outstanding <= 0;
+		end
+	default: begin end
+	endcase
+	// }}}
+
+	// Are we there yet?
+	// {{{
+	initial	rd_reads_remaining = 0;
+	initial	rd_none_remaining = 1;
+	initial	rd_last_remaining = 0;
+	always @(posedge  i_clk)
+	if (!r_busy)
+	begin
+		rd_reads_remaining <= cmd_length_aligned_w;
+		rd_last_remaining  <= (cmd_length_aligned_w == 1);
+		rd_none_remaining  <= (cmd_length_aligned_w == 0);
+	end else if (M_AXI_RVALID && M_AXI_RREADY)
+	begin
+		rd_reads_remaining <= rd_reads_remaining - 1;
+		rd_last_remaining  <= (rd_reads_remaining == 2);
+		rd_none_remaining  <= (rd_reads_remaining == 1);
+	end
+
+	always @(*)
+	if (!r_busy)
+		w_complete = 0;
+	else if (axi_abort_pending && ar_none_outstanding && !M_AXI_ARVALID)
+		w_complete = 1;
+	else if (r_continuous)
+		w_complete = (rd_none_remaining)||((rd_last_remaining) && M_AXI_RVALID && M_AXI_RREADY);
+	else // if !r_continuous
+		w_complete = (rd_none_remaining && fifo_empty);
+
+	// }}}
+
+	// Are we stopping early?  Aborting something ongoing?
+	// {{{
+	initial	axi_abort_pending = 0;
+	always @(posedge i_clk)
+	if (i_reset || !r_busy)
+		axi_abort_pending <= 0;
+	else begin
+		if (M_AXI_RVALID && M_AXI_RREADY && M_AXI_RRESP[1])
+			axi_abort_pending <= 1;
+		if (cmd_abort)
+			axi_abort_pending <= 1;
+	end
+	// }}}
+
+	// Count the number of uncommited spaces in the FIFO
+	// {{{
+	generate if (OPT_UNALIGNED)
+	begin
+		initial	partial_burst_requested <= 1'b1;
+		always @(posedge i_clk)
+		if (!r_busy)
+			partial_burst_requested <= !unaligned_cmd_addr;
+		else if (phantom_start)
+			partial_burst_requested <= 1'b1;
+	end else begin
+
+		always @(*)
+			partial_burst_requested = 1'b1;
+	end endgenerate
+
+	initial	rd_uncommitted = (1<<LGFIFO);
+	always @(posedge i_clk)
+	if (reset_fifo)
+	begin
+		rd_uncommitted <= (1<<LGFIFO);
+	end else case ({ phantom_start,
+			M_AXIS_TVALID && M_AXIS_TREADY })
+	2'b00: begin end
+	2'b01: begin
+		rd_uncommitted <= rd_uncommitted + 1;
+		end
+	2'b10: begin
+		// Verilator lint_off WIDTH
+		rd_uncommitted <= rd_uncommitted - (M_AXI_ARLEN + 1)
+			+ (partial_burst_requested ? 0 :1);
+		end
+	2'b11: begin
+		rd_uncommitted <= rd_uncommitted - (M_AXI_ARLEN)
+			+ (partial_burst_requested ? 0 :1);
+		// Verilator lint_on WIDTH
+		end
+	endcase
+	// }}}
+
+	// So that we can monitor where we are at, and perhaps restart it
+	// later, keep track of the current address used by the R-channel
+	// {{{
+
+	initial	axi_raddr = 0;
+	always @(posedge i_clk)
+	begin
+		if (!r_busy)
+			axi_raddr <= cmd_addr;
+		else if (axi_abort_pending || !r_increment)
+			// Stop incrementing tthe address following an abort
+			axi_raddr <= axi_raddr;
+		else begin
+			if (M_AXI_RVALID && M_AXI_RREADY && !M_AXI_RRESP[1]
+				&& (!unaligned_cmd_addr || realign_last_valid))
+				axi_raddr <= axi_raddr + (1<<ADDRLSB);
+		end
+
+		if (!OPT_UNALIGNED)
+			axi_raddr[ADDRLSB-1:0] <= 0;
+	end
+
+	// }}}
+
+	//
+	// }}}
+
+	always @(*)
+	begin
+		start_burst = !ar_none_remaining;
+		if (rd_uncommitted< {{(LGFIFO-LGMAXBURST){1'b0}}, r_max_burst})
+			start_burst = 0;
+		if (phantom_start)
+			// Insist on a minimum of one clock between burst
+			// starts, so we can get our lengths right
+			start_burst = 0;
+		if (M_AXI_ARVALID && !M_AXI_ARREADY)
+			start_burst = 0;
+		if (!r_busy || cmd_abort || axi_abort_pending)
+			start_burst  = 0;
+	end
+
+	initial	phantom_start = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		phantom_start <= 0;
+	else
+		phantom_start <= start_burst;
+	// }}}
+
+
+	// Calculate ARLEN and ARADDR for the next ARVALID
+	// {{{
+	initial	axi_araddr = 0;
+	always @(posedge i_clk)
+	if (!M_AXI_ARVALID || M_AXI_ARREADY)
+	begin
+		if (!r_busy)
+			axi_araddr <= cmd_addr;
+		else if (M_AXI_ARVALID && r_increment)
+		begin
+			// Verilator lint_off WIDTH
+			axi_araddr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+				<= axi_araddr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+					+ (M_AXI_ARLEN + 1);
+			// Verilator lint_on  WIDTH
+			axi_araddr[ADDRLSB-1:0] <= 0;
+		end
+		axi_arlen  <= r_max_burst[7:0] - 8'd1;
+
+		if (!OPT_UNALIGNED)
+			axi_araddr[ADDRLSB-1:0] <= 0;
+	end
+	// }}}
+
+	// ARVALID
+	// {{{
+	initial	axi_arvalid = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		axi_arvalid <= 0;
+	else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+		axi_arvalid <= start_burst;
+	// }}}
+
+	always @(posedge i_clk)
+	if (!r_busy)
+		axi_arburst <= (w_increment) ? 2'b01 : 2'b00;
+
+	// Set the constant M_AXI_* signals
+	// {{{
+	assign	M_AXI_ARVALID= axi_arvalid;
+	assign	M_AXI_ARID   = AXI_ID;
+	assign	M_AXI_ARADDR = axi_araddr;
+	assign	M_AXI_ARLEN  = axi_arlen;
+	// Verilator lint_off WIDTH
+	assign	M_AXI_ARSIZE = $clog2(C_AXI_DATA_WIDTH)-3;
+	// Verilator lint_on  WIDTH
+	assign	M_AXI_ARBURST= axi_arburst;
+	assign	M_AXI_ARLOCK = 0;
+	assign	M_AXI_ARCACHE= 4'b0011;
+	assign	M_AXI_ARPROT = 0;
+	assign	M_AXI_ARQOS  = 0;
+
+	assign	M_AXI_RREADY = 1;
+
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, S_AXIL_AWPROT, S_AXIL_ARPROT, M_AXI_RID,
+			M_AXI_RRESP[0], fifo_full, wskd_strb[2:0], fifo_fill,
+			ar_none_outstanding, S_AXIL_AWADDR[AXILLSB-1:0],
+			S_AXIL_ARADDR[AXILLSB-1:0],
+			new_wideaddr[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH],
+			new_widelen[2*C_AXIL_DATA_WIDTH-1:LGLEN],
+			new_widelen[AXILLSB-1:0]
+			 };
+	// Verilator lint_on  UNUSED
+	// }}}
+`ifdef	FORMAL
+	//
+	// The formal properties for this unit are maintained elsewhere.
+	// This core does, however, pass a full prove (w/ induction) for all
+	// bus properties.
+	//
+	// ...
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Properties of the AXI-stream data interface
+	// {{{
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// (These are captured by the FIFO within)
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The AXI-lite control interface
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	faxil_slave #(
+		// {{{
+		.C_AXI_DATA_WIDTH(C_AXIL_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXIL_ADDR_WIDTH),
+		//
+		// ...
+		// }}}
+	) faxil(
+		// {{{
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXIL_AWVALID),
+		.i_axi_awready(S_AXIL_AWREADY),
+		.i_axi_awaddr( S_AXIL_AWADDR),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot( S_AXIL_AWPROT),
+		//
+		.i_axi_wvalid(S_AXIL_WVALID),
+		.i_axi_wready(S_AXIL_WREADY),
+		.i_axi_wdata( S_AXIL_WDATA),
+		.i_axi_wstrb( S_AXIL_WSTRB),
+		//
+		.i_axi_bvalid(S_AXIL_BVALID),
+		.i_axi_bready(S_AXIL_BREADY),
+		.i_axi_bresp( S_AXIL_BRESP),
+		//
+		.i_axi_arvalid(S_AXIL_ARVALID),
+		.i_axi_arready(S_AXIL_ARREADY),
+		.i_axi_araddr( S_AXIL_ARADDR),
+		.i_axi_arcache(4'h0),
+		.i_axi_arprot( S_AXIL_ARPROT),
+		//
+		.i_axi_rvalid(S_AXIL_RVALID),
+		.i_axi_rready(S_AXIL_RREADY),
+		.i_axi_rdata( S_AXIL_RDATA),
+		.i_axi_rresp( S_AXIL_RRESP));
+		//
+		// ...
+		// }}}
+		);
+
+	//
+	// ...
+	//
+
+	always @(posedge i_clk)
+	if (f_past_valid && $past(S_AXI_ARESETN))
+	begin
+		if ($past(r_busy)||$past(w_cmd_start))
+		begin
+			assert($stable(cmd_length_b));
+			assert($stable(cmd_length_w));
+			assert($stable(cmd_length_aligned_w));
+		end
+		if ($past(r_busy))
+		begin
+			assert($stable(r_increment));
+			assert($stable(r_continuous));
+		end
+		if ($past(r_busy) && $past(r_busy,2))
+			assert($stable(fv_start_addr));
+	end
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The AXI master memory interface
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	//
+	// ...
+	//
+
+	faxi_master #(
+		// {{{
+		.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		//
+		.OPT_EXCLUSIVE(1'b0),
+		.OPT_NARROW_BURST(1'b0),
+		//
+		// ...
+		// }}}
+	) faxi(
+		// {{{
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(1'b0),
+		.i_axi_awready(1'b0),
+		.i_axi_awid(   AXI_ID),
+		.i_axi_awaddr( 0),
+		.i_axi_awlen(  0),
+		.i_axi_awsize( 0),
+		.i_axi_awburst(0),
+		.i_axi_awlock( 0),
+		.i_axi_awcache(0),
+		.i_axi_awprot( 0),
+		.i_axi_awqos(  0),
+		//
+		.i_axi_wvalid(0),
+		.i_axi_wready(0),
+		.i_axi_wdata( 0),
+		.i_axi_wstrb( 0),
+		.i_axi_wlast( 0),
+		//
+		.i_axi_bvalid(1'b0),
+		.i_axi_bready(1'b0),
+		.i_axi_bid(   AXI_ID),
+		.i_axi_bresp( 2'b00),
+		//
+		.i_axi_arvalid(M_AXI_ARVALID),
+		.i_axi_arready(M_AXI_ARREADY),
+		.i_axi_arid(   M_AXI_ARID),
+		.i_axi_araddr( M_AXI_ARADDR),
+		.i_axi_arlen(  M_AXI_ARLEN),
+		.i_axi_arsize( M_AXI_ARSIZE),
+		.i_axi_arburst(M_AXI_ARBURST),
+		.i_axi_arlock( M_AXI_ARLOCK),
+		.i_axi_arcache(M_AXI_ARCACHE),
+		.i_axi_arprot( M_AXI_ARPROT),
+		.i_axi_arqos(  M_AXI_ARQOS),
+		//
+		.i_axi_rvalid(M_AXI_RVALID),
+		.i_axi_rready(M_AXI_RREADY),
+		.i_axi_rdata( M_AXI_RDATA),
+		.i_axi_rlast( M_AXI_RLAST),
+		.i_axi_rresp( M_AXI_RRESP));
+		//
+		// ...
+		//
+		// }}}
+	);
+
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (r_busy)
+		assert(axi_arburst == (r_increment ? 2'b01 : 2'b00));
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (r_busy)
+	begin
+		//
+		// ...
+		//
+	end else begin
+		//
+		// ...
+		//
+
+		assert(rd_uncommitted
+			+ ((OPT_UNALIGNED && write_to_fifo) ? 1:0)
+			+ fifo_fill == (1<<LGFIFO));
+		if (!r_continuous)
+			assert(fifo_fill == 0 || reset_fifo);
+	end
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (r_busy)
+	begin
+		if (!OPT_UNALIGNED)
+			assert(M_AXI_ARADDR[ADDRLSB-1:0] == 0);
+		else
+			assert((M_AXI_ARADDR[ADDRLSB-1:0] == 0)
+				||(M_AXI_ARADDR == fv_start_addr));
+	end
+
+	always @(*)
+	if (!OPT_UNALIGNED || (r_busy && !r_increment))
+	begin
+		assert(cmd_addr[ADDRLSB-1:0] == 0);
+		assert(fv_start_addr[ADDRLSB-1:0] == 0);
+		assert(axi_araddr[ADDRLSB-1:0] == 0);
+		assert(axi_raddr[ADDRLSB-1:0] == 0);
+	end
+
+	//
+	// f_last_addr is the (aligned) address one following the last valid
+	// address read.  Once all reading is done, all (aligned) address
+	// pointers should point there.
+	always @(*)
+	begin
+		f_last_addr = { fv_start_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB],
+				{(ADDRLSB){1'b0}} };
+
+		if (r_increment)
+			f_last_addr = f_last_addr + cmd_length_b;
+		if (unaligned_cmd_addr)	// Only true if r_increment as well
+			f_last_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+				= f_last_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]+1;
+
+		f_last_addr[ADDRLSB-1:0] = 0;
+
+		f_next_start = fv_start_addr;
+		if (r_increment)
+			f_next_start = f_next_start + cmd_length_b;
+		if (!OPT_UNALIGNED)
+			assert(f_next_start == f_last_addr);
+	end
+
+
+	//
+	// ...
+	//
+
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Other formal properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	//
+	// Define some helper metrics
+	//
+	initial	fv_start_addr = 0;
+	always @(posedge i_clk)
+	if (!r_busy)
+		fv_start_addr <= cmd_addr;
+
+	always @(*)
+	begin
+		// Metrics defining M_AXI_ARADDR
+		f_araddr_is_aligned = (M_AXI_ARADDR[ADDRLSB+LGMAXBURST-1:0]==0);
+		f_araddr_is_initial = (M_AXI_ARADDR == fv_start_addr);
+		f_araddr_is_final   = (M_AXI_ARADDR == f_last_addr);
+
+		//
+		// Metrics to check ARADDR, assuming it had been accepted
+		//
+
+		//
+		// ...
+		//
+	end
+
+	//
+	// fv_ar_requests_remaining ... shadows ar_requests_remaining
+	//
+	// Since ar_requests_remaining drops to zero suddenly on any
+	// axi_abort_pending, we need another counter that we can use
+	// which doesn't have this feature, but which can also be used
+	// to check assertions and intermediate logic against until the
+	// abort takes effect.
+	initial	fv_ar_requests_remaining = 0;
+	always @(posedge i_clk)
+	if (!r_busy)
+	begin
+		fv_ar_requests_remaining <= cmd_length_aligned_w;
+	end else if (phantom_start)
+	begin
+		// Verilator lint_off WIDTH
+		fv_ar_requests_remaining
+			<= fv_ar_requests_remaining - (M_AXI_ARLEN + 1);
+		// Verilator lint_on WIDTH
+	end
+
+	always @(*)
+	if (r_busy)
+	begin
+		if (!axi_abort_pending)
+			assert(fv_ar_requests_remaining == ar_requests_remaining);
+		else
+			assert((ar_requests_remaining == 0)
+				||(fv_ar_requests_remaining
+					== ar_requests_remaining));
+	end
+
+	always @(*)
+	if(r_busy)
+	begin
+		assert(fv_ar_requests_remaining <= cmd_length_aligned_w);
+		//
+		// ...
+		//
+	end
+
+	//
+	// fv_axi_raddr ... shadows axi_raddr
+	//
+	// The low order bits will match the low order bits of the initial
+	// cmd_addr
+	//
+	initial	fv_axi_raddr = 0;
+	always @(posedge i_clk)
+	if (!r_busy)
+		fv_axi_raddr <= cmd_addr;
+	else if (!r_increment)
+		fv_axi_raddr <= fv_start_addr;
+	else begin
+		if (M_AXI_RVALID && M_AXI_RREADY
+				&& (!unaligned_cmd_addr || realign_last_valid))
+			fv_axi_raddr <= fv_axi_raddr + (1<<ADDRLSB);
+		if (!OPT_UNALIGNED)
+			fv_axi_raddr[ADDRLSB-1:0] <= 0;
+	end
+
+	// Constrain start <= axi_raddr <= fv_axi_raddr <= f_last_addr
+	//	in spite of any address wrapping
+	always @(*)
+	if (r_busy)
+	begin
+		assert(axi_raddr[ADDRLSB-1:0] == cmd_addr[ADDRLSB-1:0]);
+		assert(axi_abort_pending || fv_axi_raddr == axi_raddr);
+		if (!r_increment)
+		begin
+			assert(fv_axi_raddr == fv_start_addr);
+			assert(axi_raddr == fv_start_addr);
+		end if (!axi_abort_pending)
+		begin
+			if (fv_start_addr <= f_last_addr)
+			begin
+				// Natural order: start < f_raddr < last
+				assert(fv_axi_raddr <= f_last_addr);
+				assert(fv_axi_raddr >= fv_start_addr);
+			end else begin
+				// Reverse order
+				//	Either: last < start <= f_raddr
+				//	    or: f_raddr < last < start
+				assert((fv_axi_raddr >= fv_start_addr)
+					||(fv_axi_raddr <= f_last_addr));
+			end
+
+			if (fv_start_addr <= fv_axi_raddr)
+			begin
+				// Natural order: start < rad < f_rad < last
+				//   or even: last < start < rad < f_rad
+				assert(axi_raddr <= fv_axi_raddr);
+				assert(fv_start_addr <= axi_raddr);
+			end else if (fv_axi_raddr <= f_last_addr)
+			begin
+				// Reverse order: f_raddr < last < start
+				//   so either: last < start < raddr
+				//          or: raddr < f_raddr < last < start
+				//
+				assert((axi_raddr >= fv_start_addr)
+					|| (axi_raddr <= fv_axi_raddr));
+			end
+		end
+	end
+
+	always @(*)
+	if (!r_busy)
+	begin
+		assert(!M_AXI_ARVALID);
+		assert(!M_AXI_RVALID);
+		//
+		// ...
+		//
+	end
+
+	always @(*)
+		assert(zero_length == (cmd_length_w == 0));
+
+	always @(*)
+	if (phantom_start)
+		assert(rd_uncommitted >= (M_AXI_ARLEN + 1));
+
+	always @(*)
+	if (zero_length)
+		assert(!r_busy);
+	always @(*)
+	if (r_busy)
+		assert(ar_none_remaining   == (ar_requests_remaining == 0));
+	always @(*)
+		assert(ar_none_outstanding == (ar_bursts_outstanding == 0));
+	always @(*)
+		assert(rd_none_remaining   == (rd_reads_remaining == 0));
+	always @(*)
+		assert(rd_last_remaining   == (rd_reads_remaining == 1));
+
+	always @(*)
+	if (r_complete)
+		assert(!r_busy);
+
+	//
+	// ...
+	//
+
+	//
+	// fifo_availability is a measure of (1<<LGFIFO) minus the current
+	// fifo fill.  This does not include what's in the pre-FIFO
+	// logic when OPT_UNALIGNED is true.
+	always @(*)
+		f_fifo_availability = rd_uncommitted;
+
+	always @(*)
+		assert(f_fifo_committed <= (1<<LGFIFO));
+
+	always @(*)
+		assert(f_fifo_availability <= (1<<LGFIFO));
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (!reset_fifo)
+		assert(f_fifo_committed + f_fifo_availability + fifo_fill
+			== (1<<LGFIFO));
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (r_busy)
+		assert(r_max_burst <= (1<<LGMAXBURST));
+
+	always @(*)
+	if (r_busy)
+		assert((r_max_burst > 0) || (ar_requests_remaining == 0));
+
+
+	always @(*)
+	if (phantom_start)
+		assert(M_AXI_ARVALID);
+
+	always @(posedge i_clk)
+	if (phantom_start)
+	begin
+		assert(r_max_burst > 0);
+		assert(M_AXI_ARLEN == $past(r_max_burst)-1);
+	end
+
+	always @(*)
+	if (r_busy)
+		assert(initial_burstlen > 0);
+
+
+	//
+	// Address checking
+	//
+
+	// Check cmd_addr
+	always @(*)
+	if (r_busy)
+	begin
+		if (r_increment && r_continuous)
+			assert(cmd_addr == axi_raddr);
+		else
+			assert(cmd_addr == fv_start_addr);
+	end
+
+	// Check M_AXI_ARADDR
+	//
+	// ...
+	//
+
+	//
+	// Check M_AXI_ARLEN
+	//
+	// ...
+	//
+
+	//
+	// Constrain the r_maxburst
+	//
+	// ...
+	//
+
+	always @(*)
+	if (r_busy)
+	begin
+		assert(r_max_burst <= (1<<LGMAXBURST));
+		//
+		// ...
+		//
+	end
+
+	//
+	// Constrain the length
+	//
+	// ...
+	//
+
+	always @(posedge i_clk)
+	if (phantom_start)
+	begin
+		assert(axi_arlen == $past(r_max_burst[7:0]) - 8'd1);
+		if (!r_increment)
+			assert(M_AXI_ARADDR == fv_start_addr);
+	end
+
+	// Constrain rd_reads_remaining
+	//
+	// ...
+	//
+	always @(*)
+	if (r_busy)
+	begin
+		assert(rd_reads_remaining <= cmd_length_w);
+		//
+		// ...
+		//
+		assert(ar_bursts_outstanding <= rd_reads_remaining);
+		//
+		// ...
+		//
+	end
+
+	//
+	// Constrain the number of requests remaining
+	//
+	// ...
+	//
+
+	//
+	// Make sure our aw_bursts_outstanding counter never overflows
+	// (Given that the counter is as long as the length register, it cannot)
+	//
+	always @(*)
+	begin
+		if (&ar_bursts_outstanding[LGLENWA-1:1])
+			assert(!M_AXI_ARVALID);
+		//
+		// ...
+		//
+	end
+
+	// }}}
+
+	//
+	// Match axi_raddr to the faxi_ values
+	//
+	// ...
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Contract checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	// 1. All data values must get read and placed into the FIFO, with
+	//	none skipped
+	//	Captured in logic above(?)
+	//
+	// 2. No addresses skipped.  Check the write address against the 
+	//	write address we are expecting
+	//
+	// ...
+	//
+
+	// 3. If we aren't incrementing addresses, then our current address
+	//	should always be the axi address
+	//
+	// ...
+
+	//
+	// 4. Whenever we go from busy to idle, we should raise o_int for one
+	// (and only one) cycle
+	always @(posedge i_clk)
+	if (!f_past_valid || $past(!S_AXI_ARESETN))
+		assert(!o_int);
+	else
+		assert(o_int == $fell(r_busy));
+
+	//
+	// ...
+	//
+
+
+	// 5. Pick an incoming data value.  Choose whether or not to restrict
+	// incoming data not to be that value.  If the incoming data is so restricted
+	// then assert that the stream output will contain that value.
+	(* anyconst *)	reg	f_restrict_data;
+	(* anyconst *)	reg	[C_AXI_DATA_WIDTH-1:0]	f_restricted;
+
+	always @(*)
+	if (f_restrict_data && M_AXI_RVALID
+			&& (!OPT_UNALIGNED || !unaligned_cmd_addr))
+		assume(M_AXI_RDATA != f_restricted);
+
+	always @(*)
+	if (f_restrict_data && M_AXIS_TVALID
+			&& (!OPT_UNALIGNED || !unaligned_cmd_addr))
+		assert(M_AXIS_TDATA != f_restricted);
+
+	//
+	// ...
+	//
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	reg		cvr_aborted, cvr_buserr;
+	reg	[2:0]	cvr_continued;
+
+	initial	{ cvr_aborted, cvr_buserr } = 0;
+	always @(posedge i_clk)
+	if (i_reset || !r_busy)
+		{ cvr_aborted, cvr_buserr } <= 0;
+	else if (r_busy && !axi_abort_pending)
+	begin
+		if (cmd_abort && ar_requests_remaining > 0)
+			cvr_aborted <= 1;
+		if (M_AXI_RVALID && M_AXI_RRESP[1] && M_AXI_RLAST)
+			cvr_buserr <= 1;
+	end
+
+	initial	cvr_continued = 0;
+	always @(posedge i_clk)
+	if (i_reset || r_err || cmd_abort)
+		cvr_continued <= 0;
+	else begin
+		// Cover a continued transaction across two separate bursts
+		if (r_busy && r_continuous)
+			cvr_continued[0] <= 1;
+		if (!r_busy && cvr_continued[0])
+			cvr_continued[1] <= 1;
+		if (r_busy && cvr_continued[1])
+			cvr_continued[2] <= 1;
+	end
+
+	always @(posedge i_clk)
+	if (f_past_valid && !$past(i_reset) && !i_reset && $fell(r_busy))
+	begin
+		cover( r_err && cvr_aborted);
+		cover( r_err && cvr_buserr);
+		cover(!r_err);
+		if (!r_err && !axi_abort_pending && !cvr_aborted && !cvr_buserr)
+		begin
+			cover(cmd_length_w > 5);
+			cover(cmd_length_w > 8);
+			//
+			// ...
+			//
+			cover(&cvr_continued);
+			cover(&cvr_continued && (cmd_length_w > 2));
+			cover(&cvr_continued && (cmd_length_w > 5));
+		end
+	end
+
+	always @(*)
+	if (!i_reset)
+		cover(!r_err && fifo_fill > 8 && !r_busy);
+
+	always @(*)
+		cover(r_busy);
+
+	always @(*)
+		cover(start_burst);
+
+	always @(*)
+		cover(M_AXI_ARVALID && M_AXI_ARREADY);
+
+	always @(*)
+		cover(M_AXI_RVALID);
+
+	always @(*)
+		cover(M_AXI_RVALID & M_AXI_RLAST);
+	always @(*)
+	if (r_busy)
+	begin
+		cover(!ar_none_remaining);
+		if(!ar_none_remaining)
+		begin
+			cover(1);
+			cover(rd_uncommitted>= {{(LGFIFO-LGMAXBURST){1'b0}}, r_max_burst});
+			if(rd_uncommitted>= {{(LGFIFO-LGMAXBURST){1'b0}}, r_max_burst})
+			begin
+				cover(!phantom_start);
+				cover(phantom_start);
+			end
+		end
+	end
+
+	//
+	// Unaligned cover properties
+	generate if (OPT_TLAST)
+	begin
+		reg	[3:0]	cvr_lastcount;
+		always @(posedge i_clk)
+		if (i_reset || (r_busy && cmd_length_w <= 2))
+			cvr_lastcount <= 0;
+		else if (M_AXIS_TVALID && M_AXIS_TREADY && M_AXIS_TLAST
+				&& !cvr_lastcount[3])
+			cvr_lastcount <= cvr_lastcount + 1;
+
+		always @(*)
+			cover(M_AXIS_TVALID && M_AXIS_TREADY && M_AXIS_TLAST);
+
+		always @(posedge i_clk)
+			cover(o_int && cvr_lastcount > 2);
+
+	end endgenerate
+
+	generate if (OPT_UNALIGNED)
+	begin
+		//
+		// ...
+		//
+		always @(posedge i_clk)
+		if (f_past_valid && !$past(i_reset) && !i_reset &&$fell(r_busy))
+		begin
+			cover(r_err);
+			cover(!r_err);
+			cover(axi_abort_pending);
+			cover(!axi_abort_pending);
+			cover(cvr_aborted);
+			cover(!cvr_aborted);
+			cover(cvr_buserr);
+			cover(!cvr_buserr);
+			cover(!cvr_buserr && !axi_abort_pending);
+			cover(!cvr_buserr && !axi_abort_pending
+				&& (cmd_length_w > 2));
+			cover(!r_err && !cvr_aborted && !cvr_buserr
+				&& !axi_abort_pending
+				&& (cmd_length_w > 2));
+		end
+	end endgenerate
+
+
+	// }}}
+	// }}}
+`endif
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/aximrd2wbsp.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/aximrd2wbsp.v
new file mode 100644
index 0000000..a42e80f
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/aximrd2wbsp.v
@@ -0,0 +1,603 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	aximrd2wbsp.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Bridge an AXI read channel pair to a single wishbone read
+//		channel.
+//
+// Rules:
+// 	1. Any read channel error *must* be returned to the correct
+//		read channel ID.  In other words, we can't pipeline between IDs
+//	2. A FIFO must be used on getting a WB return, to make certain that
+//		the AXI return channel is able to stall with no loss
+//	3. No request can be accepted unless there is room in the return
+//		channel for it
+//
+// Status:	Passes a formal bounded model check at 15 steps.  Should be
+//		ready for a hardware check.
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module	aximrd2wbsp #(
+	parameter C_AXI_ID_WIDTH	= 6, // The AXI id width used for R&W
+                                             // This is an int between 1-16
+	parameter C_AXI_DATA_WIDTH	= 32,// Width of the AXI R&W data
+	parameter C_AXI_ADDR_WIDTH	= 28,	// AXI Address width
+	parameter AW			= 26,	// AXI Address width
+	parameter LGFIFO                =  3,
+	parameter [0:0] OPT_SWAP_ENDIANNESS = 0
+	// parameter	WBMODE		= "B4PIPELINE"
+		// Could also be "BLOCK"
+	) (
+	input	wire			S_AXI_ACLK,	// Bus clock
+	input	wire			S_AXI_ARESETN,	// Bus reset
+
+// AXI read address channel signals
+	input	wire			S_AXI_ARVALID,	// Read address valid
+	output	wire			S_AXI_ARREADY,	// Read address ready
+	input wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_ARID,	// Read ID
+	input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_ARADDR,	// Read address
+	input	wire	[7:0]		S_AXI_ARLEN,	// Read Burst Length
+	input	wire	[2:0]		S_AXI_ARSIZE,	// Read Burst size
+	input	wire	[1:0]		S_AXI_ARBURST,	// Read Burst type
+	input	wire	[0:0]		S_AXI_ARLOCK,	// Read lock type
+	input	wire	[3:0]		S_AXI_ARCACHE,	// Read Cache type
+	input	wire	[2:0]		S_AXI_ARPROT,	// Read Protection type
+	input	wire	[3:0]		S_AXI_ARQOS,	// Read Protection type
+  
+// AXI read data channel signals   
+	output	reg			S_AXI_RVALID,  // Read reponse valid
+	input	wire			S_AXI_RREADY,  // Read Response ready
+	output	wire [C_AXI_ID_WIDTH-1:0] S_AXI_RID,     // Response ID
+	output	wire [C_AXI_DATA_WIDTH-1:0] S_AXI_RDATA,    // Read data
+	output	wire 			S_AXI_RLAST,    // Read last
+	output	reg [1:0]		S_AXI_RRESP,   // Read response
+
+	// We'll share the clock and the reset
+	output	reg				o_wb_cyc,
+	output	reg				o_wb_stb,
+	output	reg [(AW-1):0]			o_wb_addr,
+	input	wire				i_wb_stall,
+	input	wire				i_wb_ack,
+	input	wire [(C_AXI_DATA_WIDTH-1):0]	i_wb_data,
+	input	wire				i_wb_err
+	);
+
+	localparam	DW = C_AXI_DATA_WIDTH;
+
+	wire	w_reset;
+	assign	w_reset = (S_AXI_ARESETN == 1'b0);
+
+
+	wire	lastid_fifo_full, lastid_fifo_empty,
+		resp_fifo_full, resp_fifo_empty;
+	wire	[LGFIFO:0]	lastid_fifo_fill, resp_fifo_fill;
+
+
+	reg				last_stb, last_ack, err_state;
+	reg	[C_AXI_ID_WIDTH-1:0]	axi_id;
+	reg	[7:0]			stblen;
+
+	wire				skid_arvalid;
+	wire	[C_AXI_ID_WIDTH-1:0]	skid_arid;//    r_id;
+	wire	[C_AXI_ADDR_WIDTH-1:0]	skid_araddr;//  r_addr;
+	wire	[7:0]			skid_arlen;//   r_len;
+	wire	[2:0]			skid_arsize;//  r_size;
+	wire	[1:0]			skid_arburst;// r_burst;
+	reg				fifo_nearfull;
+	wire				accept_request;
+
+	reg	[1:0]	axi_burst;
+	reg	[2:0]	axi_size;
+	reg	[7:0]	axi_len;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	axi_addr;
+	wire	[C_AXI_ADDR_WIDTH-1:0]	next_addr;
+	wire	response_err;
+	wire	lastid_fifo_wr;
+	reg	midissue, wb_empty;
+	reg	[LGFIFO+7:0]	acks_expected;
+
+	skidbuffer #(
+		.OPT_OUTREG(0),
+		.DW(C_AXI_ID_WIDTH + C_AXI_ADDR_WIDTH + 8 + 3 + 2)
+	) axirqbuf(S_AXI_ACLK, !S_AXI_ARESETN,
+		S_AXI_ARVALID, S_AXI_ARREADY,
+			{ S_AXI_ARID, S_AXI_ARADDR, S_AXI_ARLEN,
+			  S_AXI_ARSIZE, S_AXI_ARBURST },
+		skid_arvalid, accept_request,
+			{ skid_arid, skid_araddr, skid_arlen,
+			  skid_arsize, skid_arburst });
+
+	assign	accept_request = (!err_state)
+			&&((!o_wb_cyc)||(!i_wb_err))
+			// &&(!lastid_fifo_full)
+			&&(!midissue
+				||(o_wb_stb && last_stb && !i_wb_stall))
+			&&(skid_arvalid)
+			// One ID at a time, lest we return a bus error
+			// to the wrong AXI master
+			&&(wb_empty ||(skid_arid == axi_id));
+
+
+	initial o_wb_cyc        = 0;
+	initial o_wb_stb        = 0;
+	initial stblen          = 0;
+	initial last_stb        = 0;
+	always @(posedge S_AXI_ACLK)
+	if (w_reset)
+	begin
+		o_wb_stb <= 1'b0;
+		o_wb_cyc <= 1'b0;
+	end else if (err_state || (o_wb_cyc && i_wb_err))
+	begin
+		o_wb_cyc <= 1'b0;
+		o_wb_stb <= 1'b0;
+	end else if ((!o_wb_stb)||(!i_wb_stall))
+	begin
+		if (accept_request)
+		begin
+			// Process the new request
+			o_wb_cyc <= 1'b1;
+			if (lastid_fifo_full && (!S_AXI_RVALID||!S_AXI_RREADY))
+				o_wb_stb <= 1'b0;
+			else if (fifo_nearfull && midissue
+				&& (!S_AXI_RVALID||!S_AXI_RREADY))
+				o_wb_stb <= 1'b0;
+			else
+				o_wb_stb <= 1'b1;
+		end else if (!o_wb_stb && midissue)
+		begin
+			// Restart a transfer once the FIFO clears
+			if (S_AXI_RVALID)
+				o_wb_stb <= S_AXI_RREADY;
+		// end else if ((o_wb_cyc)&&(i_wb_err)||(err_state))
+		end else if (o_wb_stb && !last_stb)
+		begin
+			if (fifo_nearfull
+				&& (!S_AXI_RVALID||!S_AXI_RREADY))
+				o_wb_stb <= 1'b0;
+		end else if (!o_wb_stb || last_stb)
+		begin
+			// End the request
+			o_wb_stb <= 1'b0;
+
+			// Check for the last acknowledgment
+			if ((i_wb_ack)&&(last_ack))
+				o_wb_cyc <= 1'b0;
+			if (i_wb_err)
+				o_wb_cyc <= 1'b0;
+		end
+	end
+
+	initial	stblen   = 0;
+	initial	last_stb = 0;
+	initial	midissue = 0;
+	always @(posedge S_AXI_ACLK)
+	if (w_reset)
+	begin
+		stblen   <= 0;
+		last_stb <= 0;
+		midissue <= 0;
+	end else if (accept_request)
+	begin
+		stblen   <= skid_arlen;
+		last_stb <= (skid_arlen == 0);
+		midissue <= 1'b1;
+	end else if (lastid_fifo_wr)
+	begin
+		if (stblen > 0)
+			stblen <= stblen - 1;
+		last_stb <= (stblen == 1);
+		midissue <= (stblen > 0);
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (accept_request)
+	begin
+		axi_id    <= skid_arid;
+		axi_burst <= skid_arburst;
+		axi_size  <= skid_arsize;
+		axi_len   <= skid_arlen;
+	end
+
+	axi_addr #(.AW(C_AXI_ADDR_WIDTH), .DW(C_AXI_DATA_WIDTH))
+	next_read_addr(axi_addr, axi_size, axi_burst, axi_len, next_addr);
+
+	always @(posedge S_AXI_ACLK)
+	if (accept_request)
+		axi_addr <= skid_araddr;
+	else if (!i_wb_stall)
+		axi_addr <= next_addr;
+
+	always @(*)
+		o_wb_addr = axi_addr[(C_AXI_ADDR_WIDTH-1):C_AXI_ADDR_WIDTH-AW];
+
+	assign	lastid_fifo_wr = (o_wb_stb && (i_wb_err || !i_wb_stall))
+			||(err_state && midissue && !lastid_fifo_full);
+
+	sfifo #(.BW(C_AXI_ID_WIDTH+1), .LGFLEN(LGFIFO))
+	lastid_fifo(S_AXI_ACLK, w_reset,
+		lastid_fifo_wr,
+		{ axi_id, last_stb },
+		lastid_fifo_full, lastid_fifo_fill,
+		S_AXI_RVALID && S_AXI_RREADY,
+		{ S_AXI_RID, S_AXI_RLAST },
+		lastid_fifo_empty);
+
+	reg	[C_AXI_DATA_WIDTH-1:0]	read_data;
+
+	generate if (OPT_SWAP_ENDIANNESS)
+	begin : SWAP_ENDIANNESS
+		integer	ik;
+
+		// AXI is little endian.  WB can be either.  Most of my WB
+		// work is big-endian.
+		//
+		// This will convert byte ordering between the two
+		always @(*)
+		for(ik=0; ik<C_AXI_DATA_WIDTH/8; ik=ik+1)
+			read_data[ik*8 +: 8]
+				= i_wb_data[(C_AXI_DATA_WIDTH-(ik+1)*8) +: 8];
+
+	end else begin : KEEP_ENDIANNESS
+
+		always @(*)
+			read_data = i_wb_data;
+
+	end endgenerate
+
+	sfifo #(.BW(C_AXI_DATA_WIDTH+1), .LGFLEN(LGFIFO))
+	resp_fifo(S_AXI_ACLK, w_reset,
+		o_wb_cyc && (i_wb_ack || i_wb_err), { read_data, i_wb_err },
+		resp_fifo_full, resp_fifo_fill,
+		S_AXI_RVALID && S_AXI_RREADY,
+		{ S_AXI_RDATA, response_err },
+		resp_fifo_empty);
+
+	// Count the number of acknowledgements we are still expecting.  This
+	// is to support the last_ack calculation in the next process
+	initial	acks_expected = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || err_state)
+		acks_expected <= 0;
+	else case({ accept_request, o_wb_cyc && i_wb_ack })
+	2'b01:	acks_expected <= acks_expected -1;
+	2'b10:	acks_expected <= acks_expected+({{(LGFIFO){1'b0}},skid_arlen} + 1);
+	2'b11:	acks_expected <= acks_expected+{{(LGFIFO){1'b0}},skid_arlen};
+	default: begin end
+	endcase
+
+	// last_ack should be true if the next acknowledgment will end the bus
+	// cycle
+	initial	last_ack = 1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || err_state)
+		last_ack <= 1;
+	else case({ accept_request, i_wb_ack })
+	2'b01:	last_ack <= (acks_expected <= 2);
+	2'b10:	last_ack <= (acks_expected == 0)&&(skid_arlen == 0);
+	2'b11:	last_ack <= (acks_expected < 2)&&(skid_arlen < 2)
+				&&(!acks_expected[0]||!skid_arlen[0]);
+	default: begin end
+	endcase
+
+	initial	fifo_nearfull = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		fifo_nearfull <= 1'b0;
+	else case({ lastid_fifo_wr, S_AXI_RVALID && S_AXI_RREADY })
+	2'b10: fifo_nearfull <= (lastid_fifo_fill >= (1<<LGFIFO)-2);
+	2'b01: fifo_nearfull <= lastid_fifo_full;
+	default: begin end
+	endcase
+
+	initial	wb_empty = 1'b1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !o_wb_cyc)
+		wb_empty <= 1'b1;
+	else case({ lastid_fifo_wr, (i_wb_ack || i_wb_err) })
+	2'b10: wb_empty <= 1'b0;
+	2'b01: wb_empty <= (lastid_fifo_fill == resp_fifo_fill + 1);
+	default: begin end
+	endcase
+
+	always @(*)
+	begin
+		S_AXI_RRESP[0] = 1'b0;
+		S_AXI_RRESP[1] = response_err || (resp_fifo_empty && err_state);
+
+
+		S_AXI_RVALID = !resp_fifo_empty
+			|| (err_state && !lastid_fifo_empty);
+	end
+
+	initial	err_state = 0;
+	always @(posedge S_AXI_ACLK)
+	if (w_reset)
+		err_state <= 1'b0;
+	else if ((o_wb_cyc)&&(i_wb_err))
+		err_state <= 1'b1;
+	else if (lastid_fifo_empty && !midissue)
+		err_state <= 1'b0;
+
+
+	// Make Verilator happy
+	// verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, S_AXI_ARLOCK, S_AXI_ARCACHE,
+			S_AXI_ARPROT, S_AXI_ARQOS, resp_fifo_full };
+	// verilator lint_on  UNUSED
+
+`ifdef	FORMAL
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The following are a subset of the properties used to verify this
+	// core.
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	f_past_valid;
+	initial f_past_valid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1'b1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Assumptions
+	//
+	//
+	always @(*)
+	if (!f_past_valid)
+		assume(w_reset);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Ad-hoc assertions
+	//
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Error state
+	//
+	//
+	always @(*)
+	if (err_state)
+		assert(!o_wb_stb && !o_wb_cyc);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Bus properties
+	//
+	//
+
+	localparam	F_LGDEPTH = (LGFIFO>8) ? LGFIFO+1 : 10, F_LGRDFIFO = 72; // 9*F_LGFIFO;
+	//
+	// ...
+	//
+	wire	[(F_LGDEPTH-1):0]
+			fwb_nreqs, fwb_nacks, fwb_outstanding;
+
+	fwb_master #(.AW(AW), .DW(C_AXI_DATA_WIDTH), .F_MAX_STALL(2),
+		.F_MAX_ACK_DELAY(3), .F_LGDEPTH(F_LGDEPTH),
+		.F_OPT_DISCONTINUOUS(1))
+		fwb(S_AXI_ACLK, w_reset,
+			o_wb_cyc, o_wb_stb, 1'b0, o_wb_addr, {(DW){1'b0}}, 4'hf,
+			i_wb_ack, i_wb_stall, i_wb_data, i_wb_err,
+			fwb_nreqs, fwb_nacks, fwb_outstanding);
+
+	always @(*)
+	if (err_state)
+		assert(fwb_outstanding == 0);
+
+
+	faxi_slave	#(.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+			.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+			.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+			.F_LGDEPTH(F_LGDEPTH),
+			.F_AXI_MAXSTALL(0),
+			.F_AXI_MAXDELAY(0))
+		faxi(.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+			.i_axi_awready(1'b0),
+			.i_axi_awaddr(0),
+			.i_axi_awlen(8'h0),
+			.i_axi_awsize(3'h0),
+			.i_axi_awburst(2'h0),
+			.i_axi_awlock(1'b0),
+			.i_axi_awcache(4'h0),
+			.i_axi_awprot(3'h0),
+			.i_axi_awqos(4'h0),
+			.i_axi_awvalid(1'b0),
+			//
+			.i_axi_wready(1'b0),
+			.i_axi_wdata(0),
+			.i_axi_wstrb(0),
+			.i_axi_wlast(0),
+			.i_axi_wvalid(1'b0),
+			//
+			.i_axi_bid(0),
+			.i_axi_bresp(0),
+			.i_axi_bvalid(1'b0),
+			.i_axi_bready(1'b0),
+			//
+			.i_axi_arready(S_AXI_ARREADY),
+			.i_axi_arid(S_AXI_ARID),
+			.i_axi_araddr(S_AXI_ARADDR),
+			.i_axi_arlen(S_AXI_ARLEN),
+			.i_axi_arsize(S_AXI_ARSIZE),
+			.i_axi_arburst(S_AXI_ARBURST),
+			.i_axi_arlock(S_AXI_ARLOCK),
+			.i_axi_arcache(S_AXI_ARCACHE),
+			.i_axi_arprot(S_AXI_ARPROT),
+			.i_axi_arqos(S_AXI_ARQOS),
+			.i_axi_arvalid(S_AXI_ARVALID),
+			//
+			.i_axi_rresp(S_AXI_RRESP),
+			.i_axi_rid(S_AXI_RID),
+			.i_axi_rvalid(S_AXI_RVALID),
+			.i_axi_rdata(S_AXI_RDATA),
+			.i_axi_rlast(S_AXI_RLAST),
+			.i_axi_rready(S_AXI_RREADY)
+			//
+			// ...
+			//
+			);
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (!resp_fifo_empty && response_err)
+		assert(resp_fifo_fill == 1);
+
+	always @(*)
+		assert(midissue == ((stblen > 0)||(last_stb)));
+
+	always @(*)
+	if (last_stb && !err_state)
+		assert(o_wb_stb || lastid_fifo_full);
+
+	always @(*)
+	if (last_stb)
+		assert(stblen == 0);
+
+	always @(*)
+	if (lastid_fifo_full)
+	begin
+		assert(!o_wb_stb);
+		assert(!lastid_fifo_wr);
+	end
+
+	always @(*)
+	if (!err_state)
+	begin
+		if (midissue && !last_stb)
+			assert(!last_ack);
+
+		assert(lastid_fifo_fill - resp_fifo_fill
+			== fwb_outstanding);
+
+		if (fwb_outstanding > 1)
+			assert(!last_ack);
+		else if (fwb_outstanding == 1)
+			assert(midissue || last_ack);
+		else if (o_wb_cyc) // && (fwb_outstanding ==0)
+			assert(last_ack == last_stb);
+
+		if (midissue)
+			assert(o_wb_cyc);
+	end
+
+	always @(*)
+	if (o_wb_cyc)
+		assert(wb_empty == (lastid_fifo_fill == resp_fifo_fill));
+
+	always @(*)
+	if ((fwb_nacks == fwb_nreqs)&&(!midissue))
+		assert(!o_wb_cyc);
+
+	always @(*)
+		assert(fwb_outstanding <= (1<<LGFIFO));
+
+	always @(*)
+		assert(fifo_nearfull == (lastid_fifo_fill >= (1<<LGFIFO)-1));
+
+	always @(*)
+	if (o_wb_stb)
+		assert(last_ack == (last_stb&& wb_empty));//&&(!i_wb_stall);
+	else if (o_wb_cyc && !midissue)
+		assert(last_ack == (resp_fifo_fill + 1 >= lastid_fifo_fill));
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg [3:0]	cvr_reads, cvr_read_bursts, cvr_rdid_bursts;
+	reg [C_AXI_ID_WIDTH-1:0]	cvr_read_id;
+
+	initial	cvr_reads = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_reads <= 1;
+	else if (i_wb_err)
+		cvr_reads <= 0;
+	else if (S_AXI_RVALID && S_AXI_RREADY && !cvr_reads[3]
+			&& cvr_reads > 0)
+		cvr_reads <= cvr_reads + 1;
+
+	initial	cvr_read_bursts = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_read_bursts <= 1;
+	else if (S_AXI_ARVALID && S_AXI_ARLEN < 1)
+		cvr_read_bursts <= 0;
+	else if (i_wb_err)
+		cvr_read_bursts <= 0;
+	else if (S_AXI_RVALID && S_AXI_RREADY && S_AXI_RLAST
+			&& !cvr_read_bursts[3] && cvr_read_bursts > 0)
+		cvr_read_bursts <= cvr_read_bursts + 1;
+
+	initial	cvr_read_id = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_read_id <= 1;
+	else if (S_AXI_RVALID && S_AXI_RREADY && S_AXI_RLAST)
+		cvr_read_id <= cvr_read_id + 1;
+
+	initial	cvr_rdid_bursts = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_rdid_bursts <= 1;
+	else if (S_AXI_ARVALID && S_AXI_ARLEN < 1)
+		cvr_rdid_bursts <= 0;
+	else if (i_wb_err)
+		cvr_rdid_bursts <= 0;
+	else if (S_AXI_RVALID && S_AXI_RREADY && S_AXI_RLAST
+			&& S_AXI_RID == cvr_read_id
+			&& !cvr_rdid_bursts[3] && cvr_rdid_bursts > 0)
+		cvr_rdid_bursts <= cvr_rdid_bursts + 1;
+
+	always @(*)
+		cover(cvr_reads == 4);
+
+	always @(*)
+		cover(cvr_read_bursts == 4);
+
+	always @(*)
+		cover(cvr_rdid_bursts == 4);
+
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/aximwr2wbsp.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/aximwr2wbsp.v
new file mode 100644
index 0000000..a16d89a
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/aximwr2wbsp.v
@@ -0,0 +1,573 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	aximwr2wbsp.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Convert the three AXI4 write channels to a single wishbone
+//		channel to write the results.
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2015-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+//
+module aximwr2wbsp #(
+	parameter C_AXI_ID_WIDTH	= 6, // The AXI id width used for R&W
+                                             // This is an int between 1-16
+	parameter C_AXI_DATA_WIDTH	= 32,// Width of the AXI R&W data
+	parameter C_AXI_ADDR_WIDTH	= 28,	// AXI Address width
+	parameter [0:0] OPT_SWAP_ENDIANNESS = 1'b0, // Lil to Big Endian swap
+	localparam AXI_LSBS		= $clog2(C_AXI_DATA_WIDTH)-3,
+	localparam AW			= C_AXI_ADDR_WIDTH-AXI_LSBS,
+	localparam DW			= C_AXI_DATA_WIDTH,
+
+	parameter LGFIFO                =  5
+	) (
+	input	wire			S_AXI_ACLK,	// System clock
+	input	wire			S_AXI_ARESETN,
+
+// AXI write address channel signals
+	input	wire			S_AXI_AWVALID,	// Write address valid
+	output	wire			S_AXI_AWREADY, // Slave is ready to accept
+	input	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_AWID,	// Write ID
+	input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_AWADDR,	// Write address
+	input	wire	[7:0]		S_AXI_AWLEN,	// Write Burst Length
+	input	wire	[2:0]		S_AXI_AWSIZE,	// Write Burst size
+	input	wire	[1:0]		S_AXI_AWBURST,	// Write Burst type
+	input	wire	[0:0]		S_AXI_AWLOCK,	// Write lock type
+	input	wire	[3:0]		S_AXI_AWCACHE,	// Write Cache type
+	input	wire	[2:0]		S_AXI_AWPROT,	// Write Protection type
+	input	wire	[3:0]		S_AXI_AWQOS,	// Write Quality of Svc
+  
+// AXI write data channel signals
+	input	wire			S_AXI_WVALID,	// Write valid
+	output	wire			S_AXI_WREADY,  // Write data ready
+	input	wire	[C_AXI_DATA_WIDTH-1:0]	S_AXI_WDATA,	// Write data
+	input	wire	[C_AXI_DATA_WIDTH/8-1:0] S_AXI_WSTRB,	// Write strobes
+	input	wire			S_AXI_WLAST,	// Last write transaction   
+  
+// AXI write response channel signals
+	output	wire			S_AXI_BVALID,  // Write reponse valid
+	input	wire			S_AXI_BREADY,  // Response ready
+	output	wire [C_AXI_ID_WIDTH-1:0] S_AXI_BID,	// Response ID
+	output	wire [1:0]		S_AXI_BRESP,	// Write response
+  
+	// We'll share the clock and the reset
+	output	reg			o_wb_cyc,
+	output	reg			o_wb_stb,
+	output	reg [(AW-1):0]		o_wb_addr,
+	output	reg [(C_AXI_DATA_WIDTH-1):0]	o_wb_data,
+	output	reg [(C_AXI_DATA_WIDTH/8-1):0]	o_wb_sel,
+	input	wire			i_wb_stall,
+	input	wire			i_wb_ack,
+	// input	[(C_AXI_DATA_WIDTH-1):0]	i_wb_data,
+	input	wire			i_wb_err
+);
+
+	wire	w_reset;
+
+	wire			skid_awvalid;
+	reg			accept_write_burst;
+	wire [C_AXI_ID_WIDTH-1:0]	skid_awid;
+	wire [C_AXI_ADDR_WIDTH-1:0]	skid_awaddr;
+	wire	[7:0]		skid_awlen;
+	wire	[2:0]		skid_awsize;
+	wire	[1:0]		skid_awburst;
+	//
+	wire				skid_wvalid, skid_wlast;
+	reg				skid_wready;
+	wire [C_AXI_DATA_WIDTH-1:0]	skid_wdata;
+	wire [C_AXI_DATA_WIDTH/8-1:0]	skid_wstrb;
+
+	reg				skid_awready;
+	reg	[7:0]			axi_wlen, wlen;
+	reg [C_AXI_ID_WIDTH-1:0]	axi_wid;
+	reg [C_AXI_ADDR_WIDTH-1:0]	axi_waddr;
+	wire [C_AXI_ADDR_WIDTH-1:0]	next_addr;
+	reg	[1:0]			axi_wburst;
+	reg	[2:0]			axi_wsize;
+
+	reg	[LGFIFO+7:0]	acks_expected;
+	reg	[LGFIFO:0]	writes_expected;
+	reg			last_ack;
+	reg			err_state;
+
+	reg				read_ack_fifo;
+	wire	[7:0]			fifo_ack_ln;
+	reg	[8:0]			acklen;
+	reg				ack_last, ack_err, ack_empty;
+
+	reg	[LGFIFO:0]	total_fifo_fill;
+	reg			total_fifo_full;
+
+	wire			wb_ack_fifo_full, wb_ack_fifo_empty;
+	wire	[LGFIFO:0]	wb_ack_fifo_fill;
+
+	wire			err_fifo_full, err_fifo_empty;
+	wire	[LGFIFO:0]	err_fifo_fill;
+	reg			err_fifo_write;
+
+	wire			bid_fifo_full, bid_fifo_empty;
+	wire	[LGFIFO:0]	bid_fifo_fill;
+
+
+	assign	w_reset = (S_AXI_ARESETN == 1'b0);
+
+	// Step 1: a pair of skid buffers
+	skidbuffer #(
+		.OPT_OUTREG(0),
+		.DW(C_AXI_ADDR_WIDTH+C_AXI_ID_WIDTH+8+3+2))
+	awskid(S_AXI_ACLK, !S_AXI_ARESETN, S_AXI_AWVALID, S_AXI_AWREADY,
+		{ S_AXI_AWID, S_AXI_AWADDR, S_AXI_AWLEN,
+			S_AXI_AWSIZE, S_AXI_AWBURST },
+		skid_awvalid, accept_write_burst,
+		{ skid_awid, skid_awaddr, skid_awlen,
+			skid_awsize, skid_awburst });
+
+	skidbuffer #(
+		.OPT_OUTREG(0),
+		.DW(C_AXI_DATA_WIDTH + C_AXI_DATA_WIDTH/8+1))
+	wskid(S_AXI_ACLK, !S_AXI_ARESETN,
+		S_AXI_WVALID, S_AXI_WREADY,
+		{ S_AXI_WDATA, S_AXI_WSTRB, S_AXI_WLAST },
+		skid_wvalid, skid_wready,
+		{ skid_wdata, skid_wstrb, skid_wlast });
+
+	always @(*)
+	begin
+		accept_write_burst = (skid_awready)&&(!o_wb_stb || !i_wb_stall)
+				&&(!err_state)&&(skid_awvalid)
+				&&(!total_fifo_full);
+		if (axi_wid != skid_awid && (acks_expected > 0))
+			accept_write_burst = 0;
+		if (!skid_wvalid)
+			accept_write_burst = 0;
+	end
+
+	always @(*)
+		skid_wready = (!o_wb_stb || !i_wb_stall || err_state)
+			&&(!skid_awready || accept_write_burst);
+
+
+	initial	skid_awready = 1'b1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		skid_awready <= 1'b1;
+	else if (accept_write_burst)
+		skid_awready <= (skid_awlen == 0)&&(skid_wvalid)&&(skid_wlast);
+	else if (skid_wvalid && skid_wready && skid_wlast)
+		skid_awready <= 1'b1;
+
+
+	always @(posedge S_AXI_ACLK)
+	if (accept_write_burst)
+	begin
+		axi_wid   <= skid_awid;
+		axi_waddr <= skid_awaddr;
+		axi_wsize  <= skid_awsize;
+		axi_wburst <= skid_awburst;
+		axi_wlen   <= skid_awlen;
+		wlen <= skid_awlen;
+	end else if (skid_wvalid && skid_wready)
+	begin
+		axi_waddr <= next_addr;
+		if (!skid_awready)
+			wlen <= wlen - 1;
+	end
+
+	axi_addr #(.AW(C_AXI_ADDR_WIDTH), .DW(C_AXI_DATA_WIDTH))
+	next_write_addr(axi_waddr, axi_wsize, axi_wburst, axi_wlen, next_addr);
+
+	initial	{ o_wb_cyc, o_wb_stb } = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || err_state || (o_wb_cyc && i_wb_err))
+	begin
+		o_wb_cyc <= 1'b0;
+		o_wb_stb <= 1'b0;
+	end else if (accept_write_burst)
+	begin
+		o_wb_cyc <= 1'b1;
+		o_wb_stb <= skid_wvalid && skid_wready;
+	end else begin
+		if (!o_wb_stb || !i_wb_stall)
+			o_wb_stb <= (!skid_awready)&&(skid_wvalid&&skid_wready);
+		if (o_wb_cyc && last_ack && i_wb_ack && !skid_awvalid)
+			o_wb_cyc <= 0;
+	end
+		
+	always @(*)
+		o_wb_addr = axi_waddr[C_AXI_ADDR_WIDTH-1:AXI_LSBS];
+	
+	generate if (OPT_SWAP_ENDIANNESS)
+	begin : SWAP_ENDIANNESS
+		integer	ik;
+
+		always @(posedge S_AXI_ACLK)
+		if (!o_wb_stb || !i_wb_stall)
+		begin
+			for(ik=0; ik<DW/8; ik=ik+1)
+			begin
+				o_wb_data[ik*8 +: 8]
+					<= skid_wdata[(DW/8-1-ik)*8 +: 8];
+				o_wb_sel[ik]  <= skid_wstrb[DW/8-1-ik];
+			end
+		end
+
+	end else begin : KEEP_ENDIANNESS
+
+		always @(posedge S_AXI_ACLK)
+		if (!o_wb_stb || !i_wb_stall)
+		begin
+			o_wb_data <= skid_wdata;
+			o_wb_sel  <= skid_wstrb;
+		end
+
+	end endgenerate
+
+
+	initial	writes_expected = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		writes_expected <= 0;
+	end else case({skid_wvalid && skid_wready && skid_wlast,
+			S_AXI_BVALID && S_AXI_BREADY })
+	2'b01:	writes_expected <= writes_expected - 1;
+	2'b10:	writes_expected <= writes_expected + 1;
+	default: begin end
+	endcase
+
+
+	initial	acks_expected = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || i_wb_err || err_state)
+	begin
+		acks_expected <= 0;
+	end else case({skid_awvalid && accept_write_burst, {i_wb_ack|i_wb_err}})
+	2'b01:	acks_expected <= acks_expected - 1;
+	2'b10:	acks_expected <= acks_expected + ({{(LGFIFO){1'b0}},skid_awlen} + 1);
+	2'b11:	acks_expected <= acks_expected +  {{(LGFIFO){1'b0}},skid_awlen};
+	default: begin end
+	endcase
+
+	initial	last_ack = 1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || i_wb_err || err_state)
+	begin
+		last_ack <= 1;
+	end else case({skid_awvalid && accept_write_burst, i_wb_ack })
+	2'b01:	last_ack <= (acks_expected <= 2);
+	2'b10:	last_ack <= (acks_expected == 0)&&(skid_awlen == 0);
+	2'b11:	last_ack <= last_ack && (skid_awlen == 0);
+	default: begin end
+	endcase
+
+	initial	total_fifo_fill = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		total_fifo_fill <= 0;
+	else case({ accept_write_burst, S_AXI_BVALID && S_AXI_BREADY })
+	2'b01: total_fifo_fill <= total_fifo_fill - 1;
+	2'b10: total_fifo_fill <= total_fifo_fill + 1;
+	default: begin end
+	endcase
+
+	always @(*)
+		total_fifo_full = total_fifo_fill[LGFIFO];
+
+	sfifo #(.BW(8), .LGFLEN(LGFIFO),
+		.OPT_ASYNC_READ(1'b1))
+	wb_ack_fifo(S_AXI_ACLK, !S_AXI_ARESETN,
+		accept_write_burst, skid_awlen,
+		wb_ack_fifo_full, wb_ack_fifo_fill,
+		read_ack_fifo, fifo_ack_ln, wb_ack_fifo_empty);
+
+	always @(*)
+	begin
+		read_ack_fifo = ack_last && (i_wb_ack || i_wb_err);
+		if (err_state || ack_empty)
+			read_ack_fifo = 1;
+		if (wb_ack_fifo_empty)
+			read_ack_fifo = 1'b0;
+	end
+
+	reg	[8:0]	next_acklen;
+	reg	[1:0]	next_acklow;
+
+	always @(*)
+		next_acklen = fifo_ack_ln + ((acklen[0] ? 1:0)
+				+ ((i_wb_ack|i_wb_err)? 0:1));
+
+	always @(*)
+		next_acklow = fifo_ack_ln[0] + ((acklen[0] ? 1:0)
+				+ ((i_wb_ack|i_wb_err)? 0:1));
+
+	initial	acklen    = 0;
+	initial	ack_last  = 0;
+	initial	ack_empty = 1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || err_state)
+	begin
+		acklen   <= 0;
+		ack_last <= 0;
+		ack_empty<= 1;
+	end else if (read_ack_fifo)
+	begin
+		acklen   <= next_acklen;
+		ack_last <= (fifo_ack_ln < 2)&&(next_acklow == 1);
+		ack_empty<= (fifo_ack_ln == 0)&&(!acklen[0])
+					&&(i_wb_ack || i_wb_err);
+	end else if (i_wb_ack || i_wb_err)
+	begin
+		if (acklen > 0)
+			acklen <= acklen - 1;
+		ack_last <= (acklen == 2);
+		ack_empty <= ack_last;
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (read_ack_fifo)
+	begin
+		ack_err <= (wb_ack_fifo_empty) || err_state || i_wb_err;
+	end else if (i_wb_ack || i_wb_err || err_state)
+		ack_err <= ack_err || (i_wb_err || err_state);
+
+	initial	err_state = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		err_state <= 0;
+	else if (o_wb_cyc && i_wb_err)
+		err_state <= 1;
+	else if ((total_fifo_fill == bid_fifo_fill)
+		&&(total_fifo_fill == err_fifo_fill))
+		err_state <= 0;
+
+	initial	err_fifo_write = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		err_fifo_write <= 0;
+	else if (read_ack_fifo && ack_empty && fifo_ack_ln == 0)
+		err_fifo_write <= (i_wb_ack || i_wb_err || err_state);
+	else if (ack_last)
+		err_fifo_write <= (i_wb_ack || i_wb_err || err_state);
+	else
+		err_fifo_write <= 1'b0;
+
+	sfifo #(.BW(C_AXI_ID_WIDTH), .LGFLEN(LGFIFO))
+	bid_fifo(S_AXI_ACLK, !S_AXI_ARESETN,
+		skid_wvalid && skid_wready && skid_wlast,
+			(total_fifo_fill == bid_fifo_fill) ? skid_awid:axi_wid,
+		bid_fifo_full, bid_fifo_fill,
+		S_AXI_BVALID & S_AXI_BREADY, S_AXI_BID, bid_fifo_empty);
+
+	sfifo #(.BW(1), .LGFLEN(LGFIFO))
+	err_fifo(S_AXI_ACLK, !S_AXI_ARESETN,
+		err_fifo_write, { ack_err || i_wb_err },
+		err_fifo_full, err_fifo_fill,
+		S_AXI_BVALID & S_AXI_BREADY, S_AXI_BRESP[1], err_fifo_empty);
+
+	assign	S_AXI_BVALID = !bid_fifo_empty && !err_fifo_empty;
+	assign	S_AXI_BRESP[0]= 1'b0;
+
+
+	// Make Verilator happy
+	// verilator lint_on  UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, S_AXI_AWBURST, S_AXI_AWSIZE,
+			S_AXI_AWLOCK, S_AXI_AWCACHE, S_AXI_AWPROT,
+			S_AXI_AWQOS, S_AXI_WLAST,
+			wb_ack_fifo_full, wb_ack_fifo_fill,
+			bid_fifo_full, err_fifo_full,
+			w_reset
+			};
+	// verilator lint_off UNUSED
+
+`ifdef	FORMAL
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The following are a subset of the properties used to verify this
+	// core
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	f_past_valid;
+	initial	f_past_valid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1'b1;
+
+	localparam	F_LGDEPTH = (LGFIFO>8) ? LGFIFO+1 : 10, F_LGRDFIFO = 72; // 9*F_LGFIFO;
+	wire	[(F_LGDEPTH-1):0]
+			fwb_nreqs, fwb_nacks, fwb_outstanding;
+	//
+	// ...
+	//
+
+	//
+	fwb_master #(.AW(AW), .DW(C_AXI_DATA_WIDTH), .F_MAX_STALL(2),
+		.F_MAX_ACK_DELAY(3), .F_LGDEPTH(F_LGDEPTH),
+		.F_OPT_DISCONTINUOUS(1))
+		fwb(S_AXI_ACLK, w_reset,
+			o_wb_cyc, o_wb_stb, 1'b1, o_wb_addr, o_wb_data, o_wb_sel,
+			i_wb_ack, i_wb_stall, {(DW){1'b0}}, i_wb_err,
+			fwb_nreqs, fwb_nacks, fwb_outstanding);
+
+	//
+	// ...
+	//
+
+	faxi_slave	#(.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+			.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+			.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+			.F_LGDEPTH(F_LGDEPTH),
+			.F_AXI_MAXSTALL(0),
+			.F_AXI_MAXDELAY(0))
+		faxi(.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+			.i_axi_awready(S_AXI_AWREADY),
+			.i_axi_awid(   S_AXI_AWID),
+			.i_axi_awaddr( S_AXI_AWADDR),
+			.i_axi_awlen(  S_AXI_AWLEN),
+			.i_axi_awsize( S_AXI_AWSIZE),
+			.i_axi_awburst(S_AXI_AWBURST),
+			.i_axi_awlock( S_AXI_AWLOCK),
+			.i_axi_awcache(S_AXI_AWCACHE),
+			.i_axi_awprot( S_AXI_AWPROT),
+			.i_axi_awqos(  S_AXI_AWQOS),
+			.i_axi_awvalid(S_AXI_AWVALID),
+			//
+			.i_axi_wready(S_AXI_WREADY),
+			.i_axi_wdata( S_AXI_WDATA),
+			.i_axi_wstrb( S_AXI_WSTRB),
+			.i_axi_wlast( S_AXI_WLAST),
+			.i_axi_wvalid(S_AXI_WVALID),
+			//
+			.i_axi_bid(   S_AXI_BID),
+			.i_axi_bresp( S_AXI_BRESP),
+			.i_axi_bvalid(S_AXI_BVALID),
+			.i_axi_bready(S_AXI_BREADY),
+			//
+			.i_axi_arready(1'b0),
+			.i_axi_arid( {(C_AXI_ID_WIDTH){1'b0}}),
+			.i_axi_araddr({(C_AXI_ADDR_WIDTH){1'b0}}),
+			.i_axi_arlen(  8'h0),
+			.i_axi_arsize( 3'h0),
+			.i_axi_arburst(2'h0),
+			.i_axi_arlock( 1'b0),
+			.i_axi_arcache(4'h0),
+			.i_axi_arprot( 3'h0),
+			.i_axi_arqos(  4'h0),
+			.i_axi_arvalid(1'b0),
+			//
+			.i_axi_rresp( 2'h0),
+			.i_axi_rid(  {(C_AXI_ID_WIDTH){1'b0}}),
+			.i_axi_rvalid(1'b0),
+			.i_axi_rdata( {(C_AXI_DATA_WIDTH){1'b0}}),
+			.i_axi_rlast( 1'b0),
+			.i_axi_rready(1'b0)
+			//
+			// ...
+			//
+			);
+
+	(* anyconst *)	reg	never_err;
+	always @(*)
+	if (never_err)
+	begin
+		assume(!i_wb_err);
+		assert(!err_state);
+		if (!skid_awvalid)
+			assert(o_wb_cyc == (acks_expected != 0));
+		if (!skid_awready)
+			assert(o_wb_cyc);
+		if (S_AXI_BVALID)
+			assert(!S_AXI_BRESP[1]);
+		assert(!S_AXI_BRESP[0]);
+	end
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg [3:0]	cvr_writes, cvr_write_bursts, cvr_wrid_bursts;
+	reg [C_AXI_ID_WIDTH-1:0]	cvr_write_id;
+
+	initial	cvr_writes = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_writes <= 1;
+	else if (i_wb_err)
+		cvr_writes <= 0;
+	else if (S_AXI_BVALID && S_AXI_BREADY && !cvr_writes[3]
+			&& cvr_writes > 0)
+		cvr_writes <= cvr_writes + 1;
+
+	initial	cvr_write_bursts = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_write_bursts <= 1;
+	else if (S_AXI_AWVALID && S_AXI_AWLEN < 1)
+		cvr_write_bursts <= 0;
+	else if (i_wb_err)
+		cvr_write_bursts <= 0;
+	else if (S_AXI_BVALID && S_AXI_BREADY
+			&& !cvr_write_bursts[3] && cvr_write_bursts > 0)
+		cvr_write_bursts <= cvr_write_bursts + 1;
+
+	initial	cvr_write_id = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_write_id <= 1;
+	else if (S_AXI_BVALID && S_AXI_BREADY)
+		cvr_write_id <= cvr_write_id + 1;
+
+	initial	cvr_wrid_bursts = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		cvr_wrid_bursts <= 1;
+	else if (S_AXI_AWVALID && S_AXI_AWLEN < 1)
+		cvr_wrid_bursts <= 0;
+	else if (i_wb_err)
+		cvr_wrid_bursts <= 0;
+	else if (S_AXI_BVALID && S_AXI_BREADY
+			&& S_AXI_BID == cvr_write_id
+			&& !cvr_wrid_bursts[3] && cvr_wrid_bursts > 0)
+		cvr_wrid_bursts <= cvr_wrid_bursts + 1;
+
+	always @(*)
+		cover(cvr_writes == 4);
+
+	always @(*)
+		cover(cvr_write_bursts == 4);
+
+	always @(*)
+		cover(cvr_wrid_bursts == 4);
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axiperf.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axiperf.v
new file mode 100644
index 0000000..c523974
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axiperf.v
@@ -0,0 +1,1173 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axiperf
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Measure the performance of a high speed AXI interface.  The
+//		following monitor requires connecting to both an AXI-lite slave
+//	interface, as well as a second AXI interface as a monitor.  The AXI
+//	monitor interface is read only, and (ideally) shouldn't be corrupted by
+//	the inclusion of the AXI-lite interface on the same bus.
+//
+//	The core works by counting clock cycles in a fashion that should
+//	supposedly make it easy to calculate 1) throughput, and 2) lag.
+//	Moreover, the counters are arranged such that after the fact, the
+//	various contributors to throughput can be measured and evaluted: was
+//	the slave the holdup?  Or was it the master?
+//
+//	To use the core, connect it and build your design.  Then write a '3'
+//	to register 15 (address 60).  Once the bus returns to idle, the core
+//	will begin capturing data and statistics.  When done, write a '0' to
+//	the same register.  This will create a stop request.  Once the bus
+//	comes to a stop, the core will stop accumulating values into its
+//	statistics.  Those statistics can then be read out from the AXI-lite
+//	bus and analyzed.
+// }}}
+// Goals:
+// {{{
+//	My two biggest goals are to measure throughput and lag.  Defining those
+//	two measures, of course, is half the battle.   The other half of the
+//	battle is knowing which side to blame for any particular issue.
+//
+//	Throughput can easily be defined as bytes transferred over time,
+//	to give a measure of bytes / second, or beats transferred over some
+//	number of cycles, to give a measure in percentage.  The units of
+//	each are somewhat different, although both measures are supported
+//	below.
+//
+//	Lag is a bit more difficult, and it is compounded by the fact that
+//	not every master or slave can handle multiple outstanding bursts.
+//	So let's define lag as the time period between when a request is
+//	available, and the time when the request is complete.  Hence, lag
+//	on a write channel is the time between WLAST and BVALID.  If multiple
+//	bursts are in flight, then we'll ignore any AW* or W* signals during
+//	this time to just grab lag.  On the read channel, lag is the time
+//	between AR* and the first R*.  If multiple AR* requests are outstanding,
+//	lag is only counted when no R* values have (yet) to be returned for
+//	any of them.
+//
+//	The challenge of all of this is to avoid counting things twice, and
+//	to allow a slave to not be penalized for having some internal packet
+//	limit.  The particular challenge on the write channels is handling the
+//	AW* vs W* synchronization, since both channels need to make a request
+//	for the request to ever be responded to.  On the read channels, the
+//	particular challenge is being able to properly score what's going on
+//	when one (or more) bursts are being responded to at any given time.
+//	Orthogonal measures are required, and every effort below has been
+//	made to create such measures.  By "orthogonal", I simply mean that the
+//	total number of cycles is broken up into independent counters, so that
+//	no two counters ever respond to the same clock cycle.  Not all
+//	counters are orthogonal in this fashion, but each channel (read/write)
+//	has a set of orthogonal counters.  (See the *ORTHOGONAL* flag in the
+//	list below.)
+//
+//	Lag, therefore, is defined by the number of cycles where the master
+//	is waiting for the slave to respond--but only if the slave isn't
+//	already responding to anything else.  A slow link is defined by the
+//	number of cycles where 1) WVALID is low, and no write bursts have been
+//	completed that haven't been responded to, or 2) RVALID is low but yet
+//	the first RVALID of a burst has already come back.  (Up until that
+//	first RVALID, the cycle is counted as lag--but only if nothing else
+//	is in the process of returning anything.)
+//	
+// }}}
+// Registers
+// {{{
+//	  0: Active time
+//		Number of clock periods that the performance monitor has been
+//		accumulating data for.
+//	  4: Max bursts
+//	   Bits 31:24 -- the maximum number of outstanding write bursts at any
+//			given time.  A write burst begins with either
+//			AWVALID && AWREADY or WVALID && WREADY and ends with
+//			BVALID && BREADY
+//	   Bits 23:16 -- the maximum number of outstanding read bursts at any
+//			given time.  A read burst begins with ARVALID &&ARREADY,
+//			and ends with RVALID && RLAST
+//	   Bits 15: 8 -- the maximum write burst size seen, as captured by AWLEN
+//	   Bits  7: 0 -- the maximum read burst size seen, as captured by ARLEN
+//	  8: Write idle cycles
+//		Number of cycles where the write channel is totally idle.
+//						*ORTHOGONAL*
+//	 12: AWBurst count
+//		Number of AWVALID && AWREADY's
+//	 16: Write beat count
+//		Number of write beats, WVALID && WREADYs
+//	 20: AW Byte count
+//		Number of bytes written, as recorded by the AW* channel (not the
+//		W* channel and WSTRB signals)
+//	 24: Write Byte count
+//		Number of bytes written, as recorded by the W* channel and the
+//		non zero WSTRB's
+//	 28: Write slow data
+//		Number of cycles where a write has started, that is WVALID
+//		and WREADY (but !WLAST) have been seen, but yet WVALID is now
+//		low.  These are only counted if a write address request has
+//		already been recceived, and if no completed write packets are
+//		awaiting their respective BVALIDs.
+//						*ORTHOGONAL*
+//	 32: wr_stall--Write stalls
+//		Counts the number of cycles where a write address request has
+//		been issued, but not (yet) enough data writes are outstanding
+//		to complete the burst.  In this context, it counts WVALID &&
+//		!WREADY cycles.
+//						*ORTHOGONAL*
+//	 36: wr_addr_lag--Write address channel lagging
+//		Counts one of three conditions, but only assuming that no
+//		write address has been issued and is outstanding waiting on a
+//		BVALID.  1) Writes are outstanding, possibly even a WLAST has
+//		been received, for which no address has yet been received.
+//		2) The WVALID comes before AWVALID.  3) A WVALID && WREADY
+//		have already taken place, and so there's a write burst in
+//		progress, but one which hasn't yet seen its address.
+//						*ORTHOGONAL*
+//	 40: wr_data_lag--Write data laggging
+//		The AWVALID && AWREADY has been received, but no data has
+//		yet been received for this write burst and WVALID remains
+//		low.  (i.e., no BVALIDs are pending either.)
+//						*ORTHOGONAL*
+//	 44: wr_beat--Write beats (different from the write beat count above)
+//		The big difference between this and the total number of write
+//		beats is that this counts the number of clock cycles where
+//		the write data is on the critical path.  It doesn't count
+///		cycles where no AWVALID has been seen, nor does it count clock
+//		cycles where additional data is passing between one WLAST and
+//		its corresponding BVALID.
+//						*ORTHOGONAL*
+//	 48: aw_burst--AWVALID request accepted
+//		But this particular measure is only counted if there's already
+//		been a full write burst received (and no BVALIDs can yet be
+//		pending--those take precedence)  See the AWW* measures below
+//		for other AWVALID cycles.
+//						*ORTHOGONAL*
+//	 52: addr_stall--Write address channel is stalled
+//		This counts any cycle where AWVALID && !AWREADY and no bursts
+//		are outstanding waiting on BVALID.
+//						*ORTHOGONAL*
+//	 56: aww_stall-- Write address and data, address accepted but not data
+//		Counts AWVALID && AWREADY && WVALID && !WREADY cycles, but
+//		only when 
+//						*ORTHOGONAL*
+//	 60: aww_slow--AWVALID and write data is in process, but not ready
+//		Counts the number of cycles, following the first WVALID,
+//		where WVALID is low and AWVALID && AWREADY are both true
+//		(and no completed bursts are waiting on BVALID--cause then
+//		this cycle wouldn't be on a critical path)
+//						*ORTHOGONAL*
+//	 64: aww_nodata--AWVALID && AWREADY && !WVALID
+//		... and no data for this burst has yet been received, neither
+//		are any BVALIDs pending
+//						*ORTHOGONAL*
+//	 68: aww_beat-Counts the number of cycles beginning a burst where
+//		AWVALID && AWREADY && WVALID && WREADY and the channel is
+//		otherwise idle (no BVALIDs pending)
+//						*ORTHOGONAL*
+//	 72: b_lag_count
+//		Counts the number of cycles between the last accepted AWVALID
+//		and WVALID && WLAST and its corresponding BVALID.  This is
+//		the number of cycles where BVALID could be high in response
+//		to any burst, but yet where it isn't.
+//						*ORTHOGONAL*
+//	 76: b_stall_count
+//		Number of cycles where BVALID && !BREADY.  This could be a
+//		possible indication of backpressure in the interconnect.
+//						*ORTHOGONAL*
+//	 80: (Unused)
+//	 84: (Unused)
+//
+//	 88: Read idle cycles
+//		Number of clock cycles, while the core is collecting, where
+//		nothing is happening on the read channel--ARVALID is low,
+//		nothing is outstanding, etc.	*ORTHOGONAL*
+//	 92: Max responding bursts
+//		This is the maximum number of bursts that have been responding
+//		at the same time, as counted by the maximum number of ID's
+//		which have seen an RVALID but not RLAST.  It's an estimate of
+//		how out of order the channel has become.
+//	 96: Read burst count
+//		The total number of RVALID && RREADY && RLAST's seen
+//	100: Read beat count
+//		The total number of beats requested, as measured by
+//		RVALID && RREADY (or equivalently by ARLEN ... but we measure
+//		RVALID && RREADY here).		*ORTHOGONAL*
+//	104: Read byte count
+//		The total number of bytes requested, as measured by ARSIZE
+//		and ARLEN.
+//	108: AR stalls
+//		Total number of clock cycles where ARVALID && !ARREADY, but
+//		only under the condition that nothing is currently outstanding.
+//		If the master refuses to allow a second AR* burst into the
+//		pipeline, this should show in the maximum number of outstanding
+//		read bursts ever allowed.	*ORTHOGONAL*
+//	112: R stalls
+//		Total number of clock cycles where RVALID && !RREADY.  This is
+//		an indication of a slave that has issued more read requests
+//		than it can process, and so it is suffering from internal
+//		back pressure.			*ORTHOGONAL*
+//	116: Lag counter
+//		Counts the number of clock cycles where an outstanding read
+//		request exists, but for which no data has (yet) been returned.
+//						*ORTHOGONAL*
+//	120: Slow link
+//		Counts the number of clock cycles where RVALID is low, but yet
+//		a burst return has already started but not yet been completed.
+//						*ORTHOGONAL*
+//
+//		If we've done this right, then
+//
+//			active_time == read idle cycles (channel is idle)
+//				+ read_beat_count (data is transferred)_
+//				+ r stalls	(Master isn't ready)
+//				+ lag counter	(No data is ready)
+//				+ slow link	(Slave isn't ready))
+//				+ rd_ar_stalls	(Slave not ready for AR*)
+//
+//		We can then measure read throughput as the number of
+//		active cycles (active time - read idle counts) divided by the
+//		number of bytes (or beats) transferred (depending upon the
+//		units you want.
+//
+//		Lag would be measured by the lag counter divided by the number
+//		of read bursts.
+//
+//	124: Control register
+//		Write a 1 to this register to start recording, and a 0 to this
+//		register to stop.  Writing a 2 will clear the counters as
+//		well.
+// }}}
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+//
+`default_nettype none
+//
+module	axiperf #(
+		// {{{
+		//
+		// Size of the AXI-lite bus.  These are fixed, since 1) AXI-lite
+		// is fixed at a width of 32-bits by Xilinx def'n, and 2) since
+		// we only ever have 4 configuration words.
+		parameter	C_AXIL_ADDR_WIDTH = 7,
+		localparam	C_AXIL_DATA_WIDTH = 32,
+		parameter	C_AXI_DATA_WIDTH = 32,
+		parameter	C_AXI_ADDR_WIDTH = 32,
+		parameter	C_AXI_ID_WIDTH = 4,
+		parameter [0:0]	OPT_SKIDBUFFER = 1'b0,
+		parameter [0:0]	OPT_LOWPOWER = 0,
+		parameter	LGCNT = 32,
+		localparam	ADDRLSB = $clog2(C_AXI_DATA_WIDTH)-3
+		// }}}
+	) (
+		// {{{
+		input	wire					S_AXI_ACLK,
+		input	wire					S_AXI_ARESETN,
+		//
+		input	wire					S_AXIL_AWVALID,
+		output	wire					S_AXIL_AWREADY,
+		input	wire	[C_AXIL_ADDR_WIDTH-1:0]		S_AXIL_AWADDR,
+		input	wire	[2:0]				S_AXIL_AWPROT,
+		//
+		input	wire					S_AXIL_WVALID,
+		output	wire					S_AXIL_WREADY,
+		input	wire	[C_AXIL_DATA_WIDTH-1:0]		S_AXIL_WDATA,
+		input	wire	[C_AXIL_DATA_WIDTH/8-1:0]	S_AXIL_WSTRB,
+		//
+		output	wire					S_AXIL_BVALID,
+		input	wire					S_AXIL_BREADY,
+		output	wire	[1:0]				S_AXIL_BRESP,
+		//
+		input	wire					S_AXIL_ARVALID,
+		output	wire					S_AXIL_ARREADY,
+		input	wire	[C_AXIL_ADDR_WIDTH-1:0]		S_AXIL_ARADDR,
+		input	wire	[2:0]				S_AXIL_ARPROT,
+		//
+		output	wire					S_AXIL_RVALID,
+		input	wire					S_AXIL_RREADY,
+		output	wire	[C_AXIL_DATA_WIDTH-1:0]		S_AXIL_RDATA,
+		output	wire	[1:0]				S_AXIL_RRESP,
+		//
+		//
+		// The AXI Monitor interface
+		//
+		input	wire				M_AXI_AWVALID,
+		input	wire				M_AXI_AWREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_AWID,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_AWADDR,
+		input	wire	[7:0]			M_AXI_AWLEN,
+		input	wire	[2:0]			M_AXI_AWSIZE,
+		input	wire	[1:0]			M_AXI_AWBURST,
+		input	wire				M_AXI_AWLOCK,
+		input	wire	[3:0]			M_AXI_AWCACHE,
+		input	wire	[2:0]			M_AXI_AWPROT,
+		input	wire	[3:0]			M_AXI_AWQOS,
+		//
+		//
+		input	wire				M_AXI_WVALID,
+		input	wire				M_AXI_WREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_WDATA,
+		input	wire [C_AXI_DATA_WIDTH/8-1:0]	M_AXI_WSTRB,
+		input	wire				M_AXI_WLAST,
+		//
+		//
+		input	wire				M_AXI_BVALID,
+		input	wire				M_AXI_BREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_BID,
+		input	wire	[1:0]			M_AXI_BRESP,
+		//
+		//
+		input	wire				M_AXI_ARVALID,
+		input	wire				M_AXI_ARREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_ARID,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_ARADDR,
+		input	wire	[7:0]			M_AXI_ARLEN,
+		input	wire	[2:0]			M_AXI_ARSIZE,
+		input	wire	[1:0]			M_AXI_ARBURST,
+		input	wire				M_AXI_ARLOCK,
+		input	wire	[3:0]			M_AXI_ARCACHE,
+		input	wire	[2:0]			M_AXI_ARPROT,
+		input	wire	[3:0]			M_AXI_ARQOS,
+		//
+		input	wire				M_AXI_RVALID,
+		input	wire				M_AXI_RREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_RID,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_RDATA,
+		input	wire				M_AXI_RLAST,
+		input	wire	[1:0]			M_AXI_RRESP
+		//
+		// }}}
+	);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Register/wire signal declarations
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	wire	i_reset = !S_AXI_ARESETN;
+
+	wire				axil_write_ready;
+	wire	[C_AXIL_ADDR_WIDTH-ADDRLSB-1:0]	awskd_addr;
+	//
+	wire	[C_AXIL_DATA_WIDTH-1:0]	wskd_data;
+	wire [C_AXIL_DATA_WIDTH/8-1:0]	wskd_strb;
+	reg				axil_bvalid;
+	//
+	wire				axil_read_ready;
+	wire	[C_AXIL_ADDR_WIDTH-ADDRLSB-1:0]	arskd_addr;
+	reg	[C_AXIL_DATA_WIDTH-1:0]	axil_read_data;
+	reg				axil_read_valid;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite signaling
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	//
+	// Write signaling
+	//
+	// {{{
+
+	wire	awskd_valid, wskd_valid;
+
+	skidbuffer #(.OPT_OUTREG(0),
+			.OPT_LOWPOWER(OPT_LOWPOWER),
+			.DW(C_AXIL_ADDR_WIDTH-ADDRLSB))
+	axilawskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_AWVALID), .o_ready(S_AXIL_AWREADY),
+		.i_data(S_AXIL_AWADDR[C_AXIL_ADDR_WIDTH-1:ADDRLSB]),
+		.o_valid(awskd_valid), .i_ready(axil_write_ready),
+		.o_data(awskd_addr));
+
+	skidbuffer #(.OPT_OUTREG(0),
+			.OPT_LOWPOWER(OPT_LOWPOWER),
+			.DW(C_AXIL_DATA_WIDTH+C_AXIL_DATA_WIDTH/8))
+	axilwskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_WVALID), .o_ready(S_AXIL_WREADY),
+		.i_data({ S_AXIL_WDATA, S_AXIL_WSTRB }),
+		.o_valid(wskd_valid), .i_ready(axil_write_ready),
+		.o_data({ wskd_data, wskd_strb }));
+
+	assign	axil_write_ready = awskd_valid && wskd_valid
+			&& (!S_AXIL_BVALID || S_AXIL_BREADY);
+
+	initial	axil_bvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		axil_bvalid <= 0;
+	else if (axil_write_ready)
+		axil_bvalid <= 1;
+	else if (S_AXIL_BREADY)
+		axil_bvalid <= 0;
+
+	assign	S_AXIL_BVALID = axil_bvalid;
+	assign	S_AXIL_BRESP = 2'b00;
+	// }}}
+
+	//
+	// Read signaling
+	//
+	// {{{
+
+	wire	arskd_valid;
+
+	skidbuffer #(.OPT_OUTREG(0),
+			.OPT_LOWPOWER(OPT_LOWPOWER),
+			.DW(C_AXIL_ADDR_WIDTH-ADDRLSB))
+	axilarskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_ARVALID), .o_ready(S_AXIL_ARREADY),
+		.i_data(S_AXIL_ARADDR[C_AXIL_ADDR_WIDTH-1:ADDRLSB]),
+		.o_valid(arskd_valid), .i_ready(axil_read_ready),
+		.o_data(arskd_addr));
+
+	assign	axil_read_ready = arskd_valid
+			&& (!axil_read_valid || S_AXIL_RREADY);
+
+	initial	axil_read_valid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		axil_read_valid <= 1'b0;
+	else if (axil_read_ready)
+		axil_read_valid <= 1'b1;
+	else if (S_AXIL_RREADY)
+		axil_read_valid <= 1'b0;
+
+	assign	S_AXIL_RVALID = axil_read_valid;
+	assign	S_AXIL_RDATA  = axil_read_data;
+	assign	S_AXIL_RRESP = 2'b00;
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite register logic
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	reg		idle_bus, triggered, stop_request,
+			clear_request, start_request;
+	reg	[LGCNT-1:0]	active_time;
+	reg	[7:0]	wr_max_burst_size;
+	reg	[LGCNT-1:0]	wr_awburst_count, wr_wburst_count, wr_beat_count;
+	reg	[LGCNT-1:0]	wr_aw_byte_count, wr_w_byte_count;
+	reg	[7:0]	wr_aw_outstanding, wr_w_outstanding,
+			wr_aw_max_outstanding, wr_w_max_outstanding,
+			wr_max_outstanding;
+	reg		wr_aw_zero_outstanding, wr_w_zero_outstanding,
+			wr_in_progress;
+	reg	[LGCNT-1:0]	wr_idle_cycles,
+			wr_b_lag_count, wr_b_stall_count,
+			wr_slow_data, wr_stall,
+			wr_addr_lag, wr_data_lag,
+			wr_beat,
+			wr_aw_burst, wr_addr_stall,
+			wr_aww_stall, wr_aww_slow, wr_aww_nodata, wr_aww_beat;
+	reg[C_AXI_DATA_WIDTH/8:0]	wstrb_count;
+
+	reg [LGCNT-1:0]	rd_idle_cycles, rd_lag_counter, rd_slow_link,
+			rd_burst_count, rd_byte_count, rd_beat_count,
+			rd_ar_stalls, rd_r_stalls;
+	reg	[7:0]	rd_outstanding_bursts, rd_max_burst_size,
+			rd_max_outstanding_bursts;
+	reg [7:0]	rd_outstanding_bursts_id [0:(1<<C_AXI_ID_WIDTH)-1];
+	reg [(1<<C_AXI_ID_WIDTH)-1:0]	rd_nonzero_outstanding_id,
+			rd_bursts_in_flight;
+	reg [C_AXI_ID_WIDTH:0]	rd_total_in_flight, rd_responding,
+			rd_max_responding_bursts;
+	reg		rd_responding_d;
+
+	integer		ik;
+	genvar		gk;
+
+	always @(posedge S_AXI_ACLK)
+	begin
+		if (axil_write_ready)
+		begin
+			clear_request <= 1'b0;
+			if (!clear_request && idle_bus)
+			begin
+				start_request <= 0;
+				stop_request <= 0;
+			end
+			case(awskd_addr)
+			5'h1f:	if (wskd_strb[0]) begin
+				// Start, stop, clear, reset
+				//
+				clear_request <=  wskd_data[1] && !wskd_data[0];
+				stop_request  <= !wskd_data[0];
+				start_request <=  wskd_data[0] && (!stop_request);
+				end
+			default: begin end
+			endcase
+		end
+
+		if (!S_AXI_ARESETN)
+		begin
+			clear_request <= 1'b0;
+			stop_request <= 1'b0;
+			start_request <= 1'b0;
+		end
+	end
+
+	initial	axil_read_data = 0;
+	always @(posedge S_AXI_ACLK)
+	if (OPT_LOWPOWER && !S_AXI_ARESETN)
+		axil_read_data <= 0;
+	else if (!S_AXIL_RVALID || S_AXIL_RREADY)
+	begin
+		axil_read_data <= 0;
+		case(arskd_addr)
+		5'h00: axil_read_data[LGCNT-1:0] <= active_time;
+		5'h01: axil_read_data <= { wr_max_outstanding,
+					rd_max_outstanding_bursts,
+					wr_max_burst_size,
+					rd_max_burst_size };
+		5'h02: axil_read_data[LGCNT-1:0] <= wr_idle_cycles;
+		5'h03: axil_read_data[LGCNT-1:0] <= wr_awburst_count;
+		5'h04: axil_read_data[LGCNT-1:0] <= wr_beat_count;
+		5'h05: axil_read_data[LGCNT-1:0] <= wr_aw_byte_count;
+		5'h06: axil_read_data[LGCNT-1:0] <= wr_w_byte_count;
+		5'h07: axil_read_data[LGCNT-1:0] <= wr_slow_data;
+		5'h08: axil_read_data[LGCNT-1:0] <= wr_stall;
+		5'h09: axil_read_data[LGCNT-1:0] <= wr_addr_lag;
+		5'h0a: axil_read_data[LGCNT-1:0] <= wr_data_lag;
+		5'h0b: axil_read_data[LGCNT-1:0] <= wr_beat;
+		5'h0c: axil_read_data[LGCNT-1:0] <= wr_aw_burst;
+		5'h0d: axil_read_data[LGCNT-1:0] <= wr_addr_stall;
+		5'h0e: axil_read_data[LGCNT-1:0] <= wr_aww_stall;
+		5'h0f: axil_read_data[LGCNT-1:0] <= wr_aww_slow;
+		5'h10: axil_read_data[LGCNT-1:0] <= wr_aww_nodata;
+		5'h11: axil_read_data[LGCNT-1:0] <= wr_aww_beat;
+		5'h12: axil_read_data[LGCNT-1:0] <= wr_b_lag_count;
+		5'h13: axil_read_data[LGCNT-1:0] <= wr_b_stall_count;
+		//
+		5'h16: axil_read_data[LGCNT-1:0] <= rd_idle_cycles;
+		5'h17: axil_read_data	<= {
+				{(C_AXIL_DATA_WIDTH-C_AXI_ID_WIDTH-1){1'b0}},
+				rd_max_responding_bursts };
+		5'h18: axil_read_data[LGCNT-1:0] <= rd_burst_count;
+		5'h19: axil_read_data[LGCNT-1:0] <= rd_beat_count;
+		5'h1a: axil_read_data[LGCNT-1:0] <= rd_byte_count;
+		5'h1b: axil_read_data[LGCNT-1:0] <= rd_ar_stalls;
+		5'h1c: axil_read_data[LGCNT-1:0] <= rd_r_stalls;
+		5'h1d: axil_read_data[LGCNT-1:0] <= rd_lag_counter;
+		5'h1e: axil_read_data[LGCNT-1:0] <= rd_slow_link;
+		5'h1f: axil_read_data <= {
+				// pending_idle,
+				// pending_first_burst,
+				// cleared,
+				28'h0, 1'b0,
+				triggered,
+				clear_request,
+				start_request
+				};
+		default: begin end
+		endcase
+
+		if (OPT_LOWPOWER && !axil_read_ready)
+			axil_read_data <= 0;
+	end
+
+	function [C_AXI_DATA_WIDTH-1:0]	apply_wstrb;
+		input	[C_AXI_DATA_WIDTH-1:0]		prior_data;
+		input	[C_AXI_DATA_WIDTH-1:0]		new_data;
+		input	[C_AXI_DATA_WIDTH/8-1:0]	wstrb;
+
+		integer	k;
+		for(k=0; k<C_AXI_DATA_WIDTH/8; k=k+1)
+		begin
+			apply_wstrb[k*8 +: 8]
+				= wstrb[k] ? new_data[k*8 +: 8] : prior_data[k*8 +: 8];
+		end
+	endfunction
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI performance counters
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		triggered <= 0;
+	else if (start_request)
+	begin
+		if (idle_bus)
+			triggered <= 1'b1;
+	end else if (stop_request && idle_bus)
+		triggered <= 0;
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		active_time <= 0;
+	else if (triggered)
+		active_time <= active_time + 1;
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		idle_bus <= 1;
+	else if (M_AXI_AWVALID || M_AXI_WVALID || M_AXI_ARVALID)
+		idle_bus <= 0;
+	else if ((wr_aw_outstanding
+			==((M_AXI_BVALID && M_AXI_BREADY) ? 1:0))
+		&& (wr_w_outstanding == ((M_AXI_BVALID && M_AXI_BREADY) ? 1:0))
+		&& (rd_outstanding_bursts
+			==((M_AXI_RVALID && M_AXI_RREADY && M_AXI_RLAST)? 1:0)))
+		idle_bus <= 1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write statistics
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	initial	wr_max_burst_size = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		wr_max_burst_size <= 0;
+	else if (triggered)
+	begin
+		if (M_AXI_AWVALID && M_AXI_AWLEN > wr_max_burst_size)
+			wr_max_burst_size <= M_AXI_AWLEN;
+	end
+
+	initial	wr_awburst_count = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		wr_awburst_count <= 0;
+	else if (triggered && M_AXI_AWVALID && M_AXI_AWREADY)
+		wr_awburst_count <= wr_awburst_count + 1;
+
+	initial	wr_wburst_count = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		wr_wburst_count <= 0;
+	else if (triggered && M_AXI_WVALID && M_AXI_WREADY && M_AXI_WLAST)
+		wr_wburst_count <= wr_wburst_count + 1;
+
+	initial	wr_beat_count = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		wr_beat_count <= 0;
+	else if (triggered && M_AXI_WVALID && M_AXI_WREADY)
+		wr_beat_count <= wr_beat_count + 1;
+
+	always @(*)
+	begin
+		wstrb_count = 0;
+		for(ik=0; ik<C_AXI_DATA_WIDTH/8; ik=ik+1)
+		if (M_AXI_WSTRB[ik])
+			wstrb_count = wstrb_count + 1;
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		wr_aw_byte_count <= 0;
+	else if (triggered && M_AXI_AWVALID && M_AXI_AWREADY)
+	begin
+		wr_aw_byte_count <= wr_aw_byte_count
+			+ (({ 24'b0, M_AXI_AWLEN}+32'h1) << M_AXI_AWSIZE);
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		wr_w_byte_count <= 0;
+	else if (triggered && M_AXI_WVALID && M_AXI_WREADY)
+	begin
+		wr_w_byte_count <= wr_w_byte_count
+			+ { {(32-C_AXI_DATA_WIDTH/8-1){1'b0}}, wstrb_count };
+	end
+
+	initial	wr_aw_outstanding = 0;
+	initial	wr_aw_zero_outstanding = 1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		wr_aw_outstanding <= 0;
+		wr_aw_zero_outstanding <= 1;
+	end else case ({ M_AXI_AWVALID && M_AXI_AWREADY,
+				M_AXI_BVALID && M_AXI_BREADY })
+	2'b10: begin
+		wr_aw_outstanding <= wr_aw_outstanding + 1;
+		wr_aw_zero_outstanding <= 0;
+		end
+	2'b01: begin
+		wr_aw_outstanding <= wr_aw_outstanding - 1;
+		wr_aw_zero_outstanding <= (wr_aw_outstanding <= 1);
+		end
+	default: begin end
+	endcase
+
+	initial	wr_aw_max_outstanding = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		wr_aw_max_outstanding <= 0;
+	else if (triggered && (wr_aw_max_outstanding > wr_aw_outstanding))
+		wr_aw_max_outstanding <= wr_aw_outstanding;
+
+	initial	wr_w_outstanding = 0;
+	initial	wr_w_zero_outstanding = 1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		wr_w_outstanding <= 0;
+		wr_w_zero_outstanding <= 1;
+	end else case ({ M_AXI_WVALID && M_AXI_WREADY && M_AXI_WLAST,
+				M_AXI_BVALID && M_AXI_BREADY })
+	2'b10: begin
+		wr_w_outstanding <= wr_w_outstanding + 1;
+		wr_w_zero_outstanding <= 0;
+		end
+	2'b01: begin
+		wr_w_outstanding <= wr_w_outstanding - 1;
+		wr_w_zero_outstanding <= (wr_w_outstanding <= 1);
+		end
+	default: begin end
+	endcase
+
+	initial	wr_w_max_outstanding = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		wr_w_max_outstanding <= 0;
+	else if (triggered)
+	begin
+		if (wr_w_max_outstanding > wr_w_outstanding)
+			wr_w_max_outstanding <= wr_w_outstanding;
+	end
+
+	initial	wr_max_outstanding = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		wr_max_outstanding <= 0;
+	else if (wr_aw_max_outstanding > wr_w_max_outstanding
+						+ (wr_in_progress ? 1:0))
+		wr_max_outstanding <= wr_aw_max_outstanding;
+	else
+		wr_max_outstanding <= wr_w_max_outstanding
+						+ (wr_in_progress ? 1:0);
+
+	initial	wr_in_progress = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		wr_in_progress <= 0;
+	else case ({ M_AXI_WVALID, M_AXI_WLAST })
+	2'b10: wr_in_progress <= 1;
+	2'b11: wr_in_progress <= 0;
+	default: begin end
+	endcase
+
+	// Orthogonal write statistics
+	// {{{
+	// Here's where we capture our orthogonal measures for the write
+	// channel.  It's important that, for all of these counters, only
+	// one of them ever counts a given burst.  Hence, our criteria are
+	// binned and orthogonalized below.
+	//
+	//	AW_O W_O WIP AWV AWR WV WR BV BR
+	//	0    0	 0   0       0		IDLE-CYCLE
+	//	1    1	            	   0	B-LAG
+	//	1    1	            	   1  0	B-STALL
+	//	1    1	            	   1  1	(BURSTS COMPLETED)
+	//	1    0	 1           0  	W-SLOW
+	//	1    0	             1  0	W-STALL
+	//	1    0   0           0          DATA-LAG
+	//	1    0	             1  1	W-BEAT
+	//	0    1       0                  ADDR-LAG
+	//	0    1	     1   1       	AW-BURST
+	//	0     	     1   0       	AW-STALL
+	//	0    0   0   0       1          ADDR-LAG
+	//	0    0   1   0                  ADDR-LAG
+	//
+	//	0    0	     1   1   1  0	AWW-STALL
+	//	0    0	 1   1   1   0  	AWW-SLOW
+	//	0    0   0   1   1   0          AWW-NO-DATA
+	//	0    0       1   1   1  1       AWW-BEAT
+	//
+	//
+	//	      	     1   1       	AW-BURST (Counted elsewhere)
+	//	      	             1  1	W-BEAT   (Counted elsewhere)
+	// Skip the boring stuffs (if using VIM folding)
+	// {{{
+	initial	wr_data_lag      = 0;
+	initial	wr_idle_cycles   = 0;
+	initial	wr_b_lag_count   = 0;
+	initial	wr_b_stall_count = 0;
+	initial	wr_slow_data     = 0;
+	initial	wr_stall         = 0;
+	initial	wr_data_lag      = 0;
+	initial	wr_beat          = 0;
+	initial	wr_aw_burst      = 0;
+	initial	wr_addr_stall    = 0;
+	initial	wr_addr_lag      = 0;
+	initial	wr_aww_stall     = 0;
+	initial	wr_aww_slow      = 0;
+	initial	wr_aww_nodata    = 0;
+	initial	wr_aww_beat      = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+	begin
+		wr_data_lag      <= 0;
+		wr_idle_cycles   <= 0;
+		wr_b_lag_count   <= 0;
+		wr_b_stall_count <= 0;
+		wr_slow_data     <= 0;
+		wr_stall         <= 0;
+		wr_data_lag      <= 0;
+		wr_beat          <= 0;
+		wr_aw_burst      <= 0;
+		wr_addr_stall    <= 0;
+		wr_addr_lag      <= 0;
+		wr_aww_stall     <= 0;
+		wr_aww_slow      <= 0;
+		wr_aww_nodata    <= 0;
+		wr_aww_beat      <= 0;
+	end else if (triggered)
+	// }}}
+	casez({ !wr_aw_zero_outstanding, !wr_w_zero_outstanding,
+		wr_in_progress,
+		M_AXI_AWVALID, M_AXI_AWREADY,
+		M_AXI_WVALID,  M_AXI_WREADY,
+		M_AXI_BVALID,  M_AXI_BREADY })
+	9'b0000?0???: wr_idle_cycles   <= wr_idle_cycles   + 1;
+	9'b11?????0?: wr_b_lag_count   <= wr_b_lag_count   + 1;
+	9'b11?????10: wr_b_stall_count <= wr_b_stall_count + 1;
+	9'b11?????11: begin end // BURST count
+	9'b101??0???: wr_slow_data <= wr_slow_data  + 1;
+	9'b10???10??: wr_stall     <= wr_stall      + 1;
+	9'b100??0???: wr_data_lag  <= wr_data_lag   + 1;
+	9'b100??11??: wr_beat      <= wr_beat       + 1;
+	9'b01?0?????: wr_addr_lag  <= wr_addr_lag   + 1;
+	9'b01?11????: wr_aw_burst  <= wr_aw_burst   + 1;
+	9'b0??10????: wr_addr_stall<= wr_addr_stall + 1;
+	9'b0000?1???: wr_addr_lag  <= wr_addr_lag   + 1;
+	9'b0010?????: wr_addr_lag  <= wr_addr_lag   + 1;
+	9'b00?1110??: wr_aww_stall <= wr_aww_stall  + 1;
+	9'b001110???: wr_aww_slow  <= wr_aww_slow   + 1;
+	9'b000110???: wr_aww_nodata<= wr_aww_nodata + 1;
+	9'b00?1111??: wr_aww_beat  <= wr_aww_beat   + 1;
+	default: begin end
+	endcase
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read statistics
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		rd_max_burst_size <= 0;
+	else if (triggered)
+	begin
+		if (M_AXI_ARVALID && M_AXI_ARLEN > rd_max_burst_size)
+			rd_max_burst_size <= M_AXI_ARLEN;
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		rd_burst_count <= 0;
+	else if (triggered && M_AXI_RVALID && M_AXI_RREADY && M_AXI_RLAST)
+		rd_burst_count <= rd_burst_count + 1;
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		rd_byte_count <= 0;
+	else if (triggered && (M_AXI_ARVALID && M_AXI_ARREADY))
+		rd_byte_count <= rd_byte_count
+			+ (({ 24'h0, M_AXI_ARLEN} + 32'h1)<< M_AXI_ARSIZE);
+
+	initial	rd_beat_count = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		rd_beat_count <= 0;
+	else if (triggered && (M_AXI_RVALID && M_AXI_RREADY))
+		rd_beat_count <= rd_beat_count+ 1;
+
+
+	initial	rd_outstanding_bursts = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		rd_outstanding_bursts <= 0;
+	else case ({ M_AXI_ARVALID && M_AXI_ARREADY,
+				M_AXI_RVALID && M_AXI_RREADY && M_AXI_RLAST})
+	2'b10: rd_outstanding_bursts <= rd_outstanding_bursts + 1;
+	2'b01: rd_outstanding_bursts <= rd_outstanding_bursts - 1;
+	default: begin end
+	endcase
+
+	generate for(gk=0; gk < (1<<C_AXI_ID_WIDTH); gk=gk+1)
+	begin : PER_ID_READ_STATISTICS
+
+		initial	rd_outstanding_bursts_id[gk]  = 0;	
+		initial	rd_nonzero_outstanding_id[gk] = 0;	
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+		begin
+			rd_outstanding_bursts_id[gk]  <= 0;
+			rd_nonzero_outstanding_id[gk] <= 0;
+		end else case(
+			{ M_AXI_ARVALID && M_AXI_ARREADY && (M_AXI_ARID == gk),
+				M_AXI_RVALID && M_AXI_RREADY && M_AXI_RLAST
+					&& (M_AXI_RID == gk) })
+		2'b10: begin
+			rd_outstanding_bursts_id[gk]
+					<= rd_outstanding_bursts_id[gk] + 1;
+			rd_nonzero_outstanding_id[gk] <= 1'b1;
+			end
+		2'b01: begin
+			rd_outstanding_bursts_id[gk]
+					<= rd_outstanding_bursts_id[gk] - 1;
+			rd_nonzero_outstanding_id[gk]
+					<= (rd_outstanding_bursts_id[gk] > 1);
+			end
+		default: begin end
+		endcase
+
+		initial	rd_bursts_in_flight = 0;	
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			rd_bursts_in_flight[gk] <= 0;
+		else case({ M_AXI_RVALID && (M_AXI_RID == gk), M_AXI_RLAST })
+		2'b10: rd_bursts_in_flight[gk] <= 1'b1;
+		2'b11: rd_bursts_in_flight[gk] <= 1'b0;
+		default: begin end
+		endcase
+
+	end endgenerate
+
+	always @(*)
+	begin
+		rd_total_in_flight = 0;
+		for(ik=0; ik<(1<<C_AXI_ID_WIDTH); ik=ik+1)
+		if (rd_bursts_in_flight[ik])
+			rd_total_in_flight = rd_total_in_flight + 1;
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+	begin
+		rd_responding <= 0;
+		rd_responding_d <= 0;
+	end else if (triggered)
+	begin
+		rd_responding <= rd_total_in_flight;
+		rd_responding_d <= 1;
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		rd_max_responding_bursts <= 0;
+	else if (rd_responding_d)
+	begin
+		if (rd_responding > rd_max_responding_bursts)
+			rd_max_responding_bursts <= rd_responding;
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		rd_max_outstanding_bursts <= 0;
+	else if (triggered)
+	begin
+		if (rd_outstanding_bursts > rd_max_outstanding_bursts)
+			rd_max_outstanding_bursts <= rd_outstanding_bursts;
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+		rd_r_stalls <= 0;
+	else if (triggered && M_AXI_RVALID && !M_AXI_RREADY)
+		rd_r_stalls <= rd_r_stalls + 1;
+
+	//
+	// Orthogonal read statistics
+	// {{{
+	initial	rd_idle_cycles = 0;
+	initial	rd_lag_counter = 0;
+	initial	rd_slow_link   = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_request)
+	begin
+		rd_idle_cycles <= 0;
+		rd_lag_counter <= 0;
+		rd_slow_link   <= 0;
+		rd_ar_stalls <= rd_ar_stalls + 1;
+	end else if (triggered)
+	begin
+		if (!M_AXI_RVALID)
+		begin
+			if (rd_bursts_in_flight != 0)
+				rd_slow_link <= rd_slow_link + 1;
+			else if (rd_nonzero_outstanding_id != 0)
+				rd_lag_counter <= rd_lag_counter + 1;
+			else if (!M_AXI_ARVALID)
+				rd_idle_cycles <= rd_idle_cycles + 1;
+			else if (M_AXI_ARVALID && !M_AXI_ARREADY)
+				rd_ar_stalls <= rd_ar_stalls + 1;
+		end // else if (M_AXI_RREADDY) rd_beat_count <= rd_beat_count+1;
+	end
+	// }}}
+	// }}}
+
+
+	// Make Verilator happy
+	// {{{
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, S_AXIL_AWPROT, S_AXIL_ARPROT,
+			S_AXIL_ARADDR[ADDRLSB-1:0],
+			S_AXIL_AWADDR[ADDRLSB-1:0],
+			wskd_data, wskd_strb,
+			M_AXI_AWBURST, M_AXI_AWLOCK, M_AXI_AWCACHE, M_AXI_AWQOS,
+			M_AXI_AWID, M_AXI_AWADDR, M_AXI_ARADDR,
+			M_AXI_AWPROT, M_AXI_ARPROT,
+			M_AXI_BID, M_AXI_BRESP,
+			M_AXI_ARBURST, M_AXI_ARLOCK, M_AXI_ARCACHE, M_AXI_ARQOS,
+			M_AXI_WDATA, M_AXI_RDATA,
+			M_AXI_RRESP
+			};
+	// Verilator lint_on  UNUSED
+	// }}}
+`ifdef	FORMAL
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Formal properties used in verfiying this core
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	reg	f_past_valid;
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The AXI-lite control interface
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	localparam	F_AXIL_LGDEPTH = 4;
+	wire	[F_AXIL_LGDEPTH-1:0]	faxil_rd_outstanding,
+					faxil_wr_outstanding,
+					faxil_awr_outstanding;
+
+	faxil_slave #(
+		// {{{
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.F_LGDEPTH(F_AXIL_LGDEPTH),
+		.F_AXI_MAXWAIT(2),
+		.F_AXI_MAXDELAY(2),
+		.F_AXI_MAXRSTALL(3),
+		.F_OPT_COVER_BURST(4)
+		// }}}
+	) faxil(
+		// {{{
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXIL_AWVALID),
+		.i_axi_awready(S_AXIL_AWREADY),
+		.i_axi_awaddr( S_AXIL_AWADDR),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot( S_AXIL_AWPROT),
+		//
+		.i_axi_wvalid(S_AXIL_WVALID),
+		.i_axi_wready(S_AXIL_WREADY),
+		.i_axi_wdata( S_AXIL_WDATA),
+		.i_axi_wstrb( S_AXIL_WSTRB),
+		//
+		.i_axi_bvalid(S_AXIL_BVALID),
+		.i_axi_bready(S_AXIL_BREADY),
+		.i_axi_bresp( S_AXIL_BRESP),
+		//
+		.i_axi_arvalid(S_AXIL_ARVALID),
+		.i_axi_arready(S_AXIL_ARREADY),
+		.i_axi_araddr( S_AXIL_ARADDR),
+		.i_axi_arcache(4'h0),
+		.i_axi_arprot( S_AXIL_ARPROT),
+		//
+		.i_axi_rvalid(S_AXIL_RVALID),
+		.i_axi_rready(S_AXIL_RREADY),
+		.i_axi_rdata( S_AXIL_RDATA),
+		.i_axi_rresp( S_AXIL_RRESP),
+		//
+		.f_axi_rd_outstanding(faxil_rd_outstanding),
+		.f_axi_wr_outstanding(faxil_wr_outstanding),
+		.f_axi_awr_outstanding(faxil_awr_outstanding)
+		// }}}
+		);
+
+	always @(*)
+	begin
+		assert(faxil_awr_outstanding== (S_AXIL_BVALID ? 1:0)
+			+(S_AXIL_AWREADY ? 0:1));
+		assert(faxil_wr_outstanding == (S_AXIL_BVALID ? 1:0)
+			+(S_AXIL_WREADY ? 0:1));
+
+		assert(faxil_rd_outstanding == (S_AXIL_RVALID ? 1:0)
+			+(S_AXIL_ARREADY ? 0:1));
+	end
+
+	//
+	// Check that our low-power only logic works by verifying that anytime
+	// S_AXI_RVALID is inactive, then the outgoing data is also zero.
+	//
+	always @(*)
+	if (OPT_LOWPOWER && !S_AXIL_RVALID)
+		assert(S_AXIL_RDATA == 0);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	// While there are already cover properties in the formal property
+	// set above, you'll probably still want to cover something
+	// application specific here
+
+	// }}}
+	// }}}
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axis2mm.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axis2mm.v
new file mode 100644
index 0000000..9755d48
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axis2mm.v
@@ -0,0 +1,1809 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axis2mm
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Converts an AXI-stream (input) to an AXI (full) memory
+//		interface.
+// // {{{
+//	While I am aware that other vendors sell similar components, if you
+//	look under the hood you'll find no relation to anything but my own
+//	work here.
+//
+// Registers:
+//
+//  0:	CMD_CONTROL
+//		Controls the transaction via either starting or aborting an
+//		ongoing transaction, provides feedback regarding the current
+//		status.
+//
+//	[31]	r_busy
+//		True if the core is in the middle of a transaction
+//
+//	[30]	r_err
+//		True if the core has detected an error, such as FIFO
+//		overflow while writing, or FIFO overflow in continuous mode.
+//
+//		Writing a '1' to this bit while the core is idle will clear it.
+//		New transfers will not start until this bit is cleared.
+//
+//	[29]	r_complete
+//		True if the transaction has completed, whether normally or
+//		abnormally (error or abort).
+//
+//		Any write to the CMD_CONTROL register will clear this flag.
+//
+//	[28]	r_continuous
+//		Normally the FIFO gets cleared and reset between operations.
+//		However, if you set r_continuous, the core will then expectt
+//		a second operation to take place following the first one.
+//		In this case, the FIFO doesn't get cleared.  However, if the
+//		FIFO fills and the incoming data is both valid and changing,
+//		the r_err flag will be set.
+//
+//		Any write to the CMD_CONTROL register while the core is not
+//		busy will adjust this bit.
+//
+//	[27]	!r_increment
+//
+//		If clear, the core writes to subsequent and incrementing
+//		addresses.  If set, the core writes to the same address
+//		throughout a transaction.
+//
+//		Writes to CMD_CONTROL while the core is idle will adjust this
+//		bit.
+//
+//	[26]	!r_tlast_syncd
+//
+//		Read only status indicator.  Reads 0 if OPT_TLAST_SYNC isn't
+//		set.  If set, this bit indicates whether or not the memory
+//		transfer is currently aligned with any stream packets, or
+//		whether it is out of synchronization and waiting to sync with
+//		the incoming stream.  If it is out of alignment, the core
+//		will synchronize itself automatically.
+//
+//	[25]	Error code, decode error
+//
+//		Read only bit.  True following any AXI decode error.  Cleared
+//		whenever the error bit is cleared.
+//
+//	[24]	Error code, slave error
+//
+//		Read only bit.  True following any AXI slave error.  Cleared
+//		whenever the error bit is cleared.
+//
+//	[23]	Error code, overflow error
+//
+//		Read only bit.  True following any AXI stream overflow.
+//		Cleared whenever the error bit is cleared.
+//
+//	[22]	Abort in progress
+//
+//		Read only bit.  This bit will be true following any abort until
+//		the bus transactions complete.  Self-clearing.
+//
+//	[20:16]	LGFIFO
+//		These are read-only bits, returning the size of the FIFO.
+//
+//	ABORT
+//		If the core is busy, and ABORT_KEY (currently set to 8'h26
+//		below) is written to the top 8-bits of this register,
+//		the current transfer will be aborted.  Any pending writes
+//		will be completed, but nothing more will be written.
+//
+//		Alternatively, the core will enter into an abort state
+//		following any returned bus error indications.
+//
+//  x4-c:	(Unused and reserved)
+//
+//  x10-14:	CMD_ADDR
+//	[C_AXI_ADDR_WIDTH-1:($clog2(C_AXI_DATA_WIDTH)-3)]
+//		If idle, the address the core will write to when it starts.
+//		If busy, the address the core is currently writing to.
+//		Upon completion, the address either returns to the starting
+//		address (if r_continuous is clear), or otherwise becomes the
+//		address where the core left off.  In the case of an abort or an
+//		error, this will be (near) the address that was last written.
+//
+//		Why "near"?  Because this address records the writes that have
+//		been issued while no error is pending.  If a bus error return
+//		comes back, there may have been several writes issued before
+//		that error address.
+//
+//  x18-1c:  CMD_LEN
+//	[LGLEN-1:0]
+//		The size of the transfer in bytes.  Only accepts aligned
+//		addresses, therefore bits [($clog2(C_AXI_DATA_WIDTH)-3):0]
+//		will always be forced to zero.  To find out what size bus
+//		this core is conencted to, or the maximum transfer length,
+//		write a -1 to this value and read the returning result.
+//		Only the active bits will be set.
+//
+//		While the core is busy, reads from this address will return
+//		the number of items still to be written to the bus.
+//
+//		I hope to eventually add support for unaligned bursts.  Such
+//		support is not currently part of this core.
+//
+//
+// }}}
+//
+// Status:
+// {{{
+//	1. The core passes both cover checks and formal property (assertion)
+//		based checks.  It has not (yet) been tested in real hardware.
+//
+//	2. I'd also like to support unaligned addresses and lengths.  This will
+//		require aligning the data coming out of the FIFO as well.
+//		As written, the core doesn't yet support these features.
+//
+// }}}
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+module	axis2mm #(
+		// {{{
+		//
+		// Downstream AXI (MM) address width.  Remember, this is *byte*
+		// oriented, so an address width of 32 means this core can
+		// interact with a full 2^(C_AXI_ADDR_WIDTH) *bytes*.
+		parameter	C_AXI_ADDR_WIDTH = 32,
+		// ... and the downstream AXI (MM) data width.  High speed can
+		// be achieved by increasing this data width.
+		parameter	C_AXI_DATA_WIDTH = 32,
+		parameter	C_AXI_ID_WIDTH = 1,
+		parameter	C_AXIS_TUSER_WIDTH = 0,
+		//
+		// OPT_TLAST_SYNC will synchronize the write with any incoming
+		// packets.  Packets are assumed to be synchronized initially
+		// after any reset, or on the TVALID following any TLAST
+		parameter [0:0]	OPT_TLAST_SYNC = 1,
+		//
+		// OPT_TREADY_WHILE_IDLE controls how the stream idle is set
+		// when the memory copy isn't running.  If 1, then TREADY will
+		// be 1 and the core will ignore/throw out data when the core
+		// isn't busy.  Otherwise, if this is set to 0, the core will
+		// force the stream to stall if ever no data is being copied.
+		parameter [0:0]	OPT_TREADY_WHILE_IDLE = 1,
+		//
+		// If the ABORT_KEY is written to the upper 8-bits of the
+		// control/status word, the current operation will be halted.
+		// Any currently active (AxVALID through xVALID & xREADY)
+		// requests will continue to completion, and the core will then
+		// come to a halt.
+		parameter [7:0]	ABORT_KEY = 8'h26,
+		//
+		// The size of the FIFO, log-based two.  Hence LGFIFO=9 gives
+		// you a FIFO of size 2^(LGFIFO) or 512 elements.  This is about
+		// as big as the FIFO should ever need to be, since AXI bursts
+		// can be 256 in length.
+		parameter	LGFIFO = 9,
+		//
+		// Maximum number of bytes that can ever be transferred, in
+		// log-base 2.  Hence LGLEN=20 will transfer 1MB of data.
+		parameter	LGLEN  = C_AXI_ADDR_WIDTH-1,
+		//
+		// We only ever use one AXI ID for all of our transactions.
+		// Here it is given as 0.  Feel free to change it as necessary.
+		parameter [C_AXI_ID_WIDTH-1:0]	AXI_ID = 0,
+		//
+		// Set OPT_UNALIGNED to be able to transfer from unaligned
+		// addresses.  Only applies to non fixed addresses and
+		// (possibly) non-continuous bursts.  (THIS IS A PLACEHOLDER.
+		// UNALIGNED ADDRESSING IS NOT CURRENTLY SUPPORTED.)
+		localparam [0:0]	OPT_UNALIGNED = 0,
+		//
+		// Size of the AXI-lite bus.  These are fixed, since 1) AXI-lite
+		// is fixed at a width of 32-bits by Xilinx def'n, and 2) since
+		// we only ever have 4 configuration words.
+		localparam	C_AXIL_ADDR_WIDTH = 5,
+		localparam	C_AXIL_DATA_WIDTH = 32,
+		localparam	AXILLSB = $clog2(C_AXIL_DATA_WIDTH)-3,
+		localparam	ADDRLSB = $clog2(C_AXI_DATA_WIDTH)-3
+		// }}}
+	) (
+		// {{{
+		input	wire					S_AXI_ACLK,
+		input	wire					S_AXI_ARESETN,
+		//
+		// The stream interface
+		// {{{
+		input	wire					S_AXIS_TVALID,
+		output	wire					S_AXIS_TREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]		S_AXIS_TDATA,
+		input	wire					S_AXIS_TLAST,
+		input wire [((C_AXIS_TUSER_WIDTH>0) ? C_AXIS_TUSER_WIDTH-1:0):0]
+								S_AXIS_TUSER,
+		// }}}
+		//
+		// The control interface
+		// {{{
+		input	wire					S_AXIL_AWVALID,
+		output	wire					S_AXIL_AWREADY,
+		input	wire	[C_AXIL_ADDR_WIDTH-1:0]		S_AXIL_AWADDR,
+		input	wire	[2:0]				S_AXIL_AWPROT,
+		//
+		input	wire					S_AXIL_WVALID,
+		output	wire					S_AXIL_WREADY,
+		input	wire	[C_AXIL_DATA_WIDTH-1:0]		S_AXIL_WDATA,
+		input	wire	[C_AXIL_DATA_WIDTH/8-1:0]	S_AXIL_WSTRB,
+		//
+		output	wire					S_AXIL_BVALID,
+		input	wire					S_AXIL_BREADY,
+		output	wire	[1:0]				S_AXIL_BRESP,
+		//
+		input	wire					S_AXIL_ARVALID,
+		output	wire					S_AXIL_ARREADY,
+		input	wire	[C_AXIL_ADDR_WIDTH-1:0]		S_AXIL_ARADDR,
+		input	wire	[2:0]				S_AXIL_ARPROT,
+		//
+		output	wire					S_AXIL_RVALID,
+		input	wire					S_AXIL_RREADY,
+		output	wire	[C_AXIL_DATA_WIDTH-1:0]		S_AXIL_RDATA,
+		output	wire	[1:0]				S_AXIL_RRESP,
+		// }}}
+		//
+
+		//
+		// The AXI (full) write interface
+		// {{{
+		output	wire				M_AXI_AWVALID,
+		input	wire				M_AXI_AWREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_AWID,
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_AWADDR,
+		output	wire	[7:0]			M_AXI_AWLEN,
+		output	wire	[2:0]			M_AXI_AWSIZE,
+		output	wire	[1:0]			M_AXI_AWBURST,
+		output	wire				M_AXI_AWLOCK,
+		output	wire	[3:0]			M_AXI_AWCACHE,
+		output	wire	[2:0]			M_AXI_AWPROT,
+		output	wire	[3:0]			M_AXI_AWQOS,
+		//
+		output	wire				M_AXI_WVALID,
+		input	wire				M_AXI_WREADY,
+		output	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_WDATA,
+		output	wire	[C_AXI_DATA_WIDTH/8-1:0] M_AXI_WSTRB,
+		output	wire				M_AXI_WLAST,
+		output wire [(C_AXIS_TUSER_WIDTH>0 ? C_AXIS_TUSER_WIDTH-1:0):0]
+							M_AXI_WUSER,
+		//
+		input	wire				M_AXI_BVALID,
+		output	wire				M_AXI_BREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_BID,
+		input	wire	[1:0]			M_AXI_BRESP,
+		// }}}
+		//
+		//
+		// Create an output signal to indicate that we've finished
+		output	reg				o_int
+		// }}}
+	);
+	localparam [2:0]	CMD_CONTROL   = 3'b000,
+				CMD_UNUSED_1  = 3'b001,
+				CMD_UNUSED_2  = 3'b010,
+				CMD_UNUSED_3  = 3'b011,
+				CMD_ADDRLO    = 3'b100,
+				CMD_ADDRHI    = 3'b101,
+				CMD_LENLO     = 3'b110,
+				CMD_LENHI     = 3'b111;
+				// CMD_RESERVED = 2'b11;
+	localparam	LGMAXBURST=(LGFIFO > 8) ? 8 : LGFIFO-1;
+	localparam	LGMAX_FIXED_BURST = (LGMAXBURST > 4) ? 4 : LGMAXBURST;
+	localparam	MAX_FIXED_BURST = (1<<LGMAX_FIXED_BURST);
+	localparam	LGLENW  = LGLEN  - ($clog2(C_AXI_DATA_WIDTH)-3);
+	localparam	LGFIFOB = LGFIFO + ($clog2(C_AXI_DATA_WIDTH)-3);
+	localparam [ADDRLSB-1:0] LSBZEROS = 0;
+	localparam	ERRCODE_NOERR    = 0,
+			ERRCODE_OVERFLOW = 0,
+			ERRCODE_SLVERR   = 1,
+			ERRCODE_DECERR   = 2;
+
+
+	wire	i_clk   =  S_AXI_ACLK;
+	wire	i_reset = !S_AXI_ARESETN;
+
+	// Signal declarations
+	// {{{
+	reg	r_busy, r_err, r_complete, r_continuous, r_increment,
+		cmd_abort, zero_length, r_pre_start,
+		w_cmd_start, w_complete, w_cmd_abort;
+	reg	[2:0]		r_errcode;
+	// reg	cmd_start;
+	reg			axi_abort_pending;
+
+	reg	[LGLENW-1:0]	aw_requests_remaining,
+				aw_bursts_outstanding,
+				aw_next_remaining;
+	reg	[LGMAXBURST:0]	wr_writes_pending;
+	reg	[LGMAXBURST:0]		r_max_burst;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	axi_addr;
+
+	reg	[C_AXI_ADDR_WIDTH-1:0]	cmd_addr;
+	reg	[LGLENW-1:0]		cmd_length_w;
+
+	reg	[2*C_AXIL_DATA_WIDTH-1:0]	wide_address, wide_length,
+					new_wideaddr, new_widelen;
+	wire	[C_AXIL_DATA_WIDTH-1:0]	new_cmdaddrlo, new_cmdaddrhi,
+					new_lengthlo,  new_lengthhi;
+
+	// FIFO signals
+	wire				reset_fifo, write_to_fifo,
+					read_from_fifo;
+	wire [C_AXIS_TUSER_WIDTH+C_AXI_DATA_WIDTH-1:0]	fifo_data;
+	wire	[LGFIFO:0]		fifo_fill;
+	wire				fifo_full, fifo_empty;
+
+	wire				awskd_valid, axil_write_ready;
+	wire	[C_AXIL_ADDR_WIDTH-AXILLSB-1:0]	awskd_addr;
+	//
+	wire				wskd_valid;
+	wire	[C_AXIL_DATA_WIDTH-1:0]	wskd_data;
+	wire [C_AXIL_DATA_WIDTH/8-1:0]	wskd_strb;
+	reg				axil_bvalid;
+	//
+	wire				arskd_valid, axil_read_ready;
+	wire	[C_AXIL_ADDR_WIDTH-AXILLSB-1:0]	arskd_addr;
+	reg	[C_AXIL_DATA_WIDTH-1:0]	axil_read_data;
+	reg				axil_read_valid;
+	reg				last_stalled, overflow, last_tlast;
+	reg	[C_AXI_DATA_WIDTH-1:0]	last_tdata;
+	reg	[C_AXIL_DATA_WIDTH-1:0]	w_status_word;
+
+	reg	[LGLENW-1:0]		r_remaining_w;
+
+	reg				axi_awvalid;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	axi_awaddr;
+	reg	[7:0]			axi_awlen;
+	reg				axi_wvalid, axi_wlast;
+	reg [C_AXI_DATA_WIDTH/8-1:0]	axi_wstrb;
+
+	// Speed up checking for zeros
+	reg				aw_none_remaining,
+					aw_last_outstanding,
+					wr_none_pending; // r_none_remaining;
+
+	reg				w_phantom_start, phantom_start;
+	reg	[LGMAXBURST:0]	initial_burstlen;
+	reg	[LGMAXBURST-1:0] addralign;
+
+	//
+	// Option processing
+	reg			r_tlast_syncd;
+
+	reg			aw_multiple_full_bursts,
+				aw_multiple_fixed_bursts,
+				aw_multiple_bursts_remaining,
+				aw_needs_alignment;
+	reg	[LGFIFO:0]	data_available;
+	reg			sufficiently_filled;
+
+
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite signaling
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// This is mostly the skidbuffer logic, and handling of the VALID
+	// and READY signals for the AXI-lite control logic in the next
+	// section.
+	// {{{
+
+	//
+	// Write signaling
+	//
+	// {{{
+
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_ADDR_WIDTH-AXILLSB))
+	axilawskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_AWVALID), .o_ready(S_AXIL_AWREADY),
+		.i_data(S_AXIL_AWADDR[C_AXIL_ADDR_WIDTH-1:AXILLSB]),
+		.o_valid(awskd_valid), .i_ready(axil_write_ready),
+		.o_data(awskd_addr));
+
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_DATA_WIDTH+C_AXIL_DATA_WIDTH/8))
+	axilwskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_WVALID), .o_ready(S_AXIL_WREADY),
+		.i_data({ S_AXIL_WDATA, S_AXIL_WSTRB }),
+		.o_valid(wskd_valid), .i_ready(axil_write_ready),
+		.o_data({ wskd_data, wskd_strb }));
+
+	assign	axil_write_ready = awskd_valid && wskd_valid
+			&& (!S_AXIL_BVALID || S_AXIL_BREADY);
+
+	initial	axil_bvalid = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		axil_bvalid <= 0;
+	else if (axil_write_ready)
+		axil_bvalid <= 1;
+	else if (S_AXIL_BREADY)
+		axil_bvalid <= 0;
+
+	assign	S_AXIL_BVALID = axil_bvalid;
+	assign	S_AXIL_BRESP = 2'b00;
+	// }}}
+
+	//
+	// Read signaling
+	//
+	// {{{
+
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_ADDR_WIDTH-AXILLSB))
+	axilarskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_ARVALID), .o_ready(S_AXIL_ARREADY),
+		.i_data(S_AXIL_ARADDR[C_AXIL_ADDR_WIDTH-1:AXILLSB]),
+		.o_valid(arskd_valid), .i_ready(axil_read_ready),
+		.o_data(arskd_addr));
+
+	assign	axil_read_ready = arskd_valid
+				&& (!axil_read_valid || S_AXIL_RREADY);
+
+	initial	axil_read_valid = 1'b0;
+	always @(posedge i_clk)
+	if (i_reset)
+		axil_read_valid <= 1'b0;
+	else if (axil_read_ready)
+		axil_read_valid <= 1'b1;
+	else if (S_AXIL_RREADY)
+		axil_read_valid <= 1'b0;
+
+	assign	S_AXIL_RVALID = axil_read_valid;
+	assign	S_AXIL_RDATA  = axil_read_data;
+	assign	S_AXIL_RRESP = 2'b00;
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite controlled logic
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	initial	last_stalled = 1'b0;
+	always @(posedge i_clk)
+		last_stalled <= (!i_reset) && (S_AXIS_TVALID && !S_AXIS_TREADY);
+
+	always @(posedge i_clk)
+	if (!OPT_TLAST_SYNC)
+		last_tlast <= 0;
+	else
+		last_tlast <= S_AXIS_TLAST;
+
+	always @(posedge i_clk)
+		last_tdata <= S_AXIS_TDATA;
+
+
+	initial	overflow = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		overflow <= 0;
+	else if (last_stalled)
+	begin
+		// The overflow pulse is only one clock period long
+		overflow <= 0;
+		if (!S_AXIS_TVALID)
+			overflow <= 1;
+		if (S_AXIS_TDATA != last_tdata)
+			overflow <= 1;
+		if (OPT_TLAST_SYNC && S_AXIS_TLAST != last_tlast)
+			overflow <= 1;
+
+		// This will be caught by r_err and r_continuous
+	end
+
+	//
+	// Abort transaction
+	//
+	always @(*)
+	begin
+		w_cmd_abort = 0;
+		w_cmd_abort = (axil_write_ready && awskd_addr == CMD_CONTROL)
+			&& (wskd_strb[3] && wskd_data[31:24] == ABORT_KEY);
+		if (!r_busy)
+			w_cmd_abort = 0;
+	end
+
+	initial	cmd_abort = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		cmd_abort <= 0;
+	else if (!r_busy)
+		cmd_abort <= 0;
+	else
+		cmd_abort <= cmd_abort || w_cmd_abort;
+
+	//
+	// Start command
+	//
+	always @(*)
+	if (r_busy)
+		w_cmd_start = 0;
+	else begin
+		w_cmd_start = 0;
+		if ((axil_write_ready && awskd_addr == CMD_CONTROL)
+			&& (wskd_strb[3] && wskd_data[31]))
+			w_cmd_start = 1;
+		if (r_err && !wskd_data[30])
+			w_cmd_start = 0;
+		if (zero_length)
+			w_cmd_start = 0;
+	end
+
+	// initial	cmd_start = 0;
+	// always @(posedge i_clk)
+	//	cmd_start <= (!i_reset)&&(w_cmd_start);
+
+	//
+	// Recognize the last ack
+	//
+	// assign	w_complete = something
+
+	//
+	// Calculate busy or complete flags
+	//
+	initial	r_busy     = 0;
+	initial	r_complete = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		r_busy     <= 0;
+		r_complete <= 0;
+	end else if (!r_busy)
+	begin
+		// Core is idle, waiting for a command to start
+		if (w_cmd_start)
+			r_busy <= 1'b1;
+
+		// Any write to the control register will clear the
+		// completion flag
+		if (axil_write_ready && awskd_addr == CMD_CONTROL)
+			r_complete <= 1'b0;
+	end else if (w_complete)
+	begin
+		// Clear busy once the transaction is complete
+		//  This includes clearing busy on any error
+		r_complete <= 1;
+		r_busy <= 1'b0;
+	end
+
+	//
+	// Interrupts
+	//
+	initial	o_int = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		o_int <= 0;
+	else
+		o_int <= (r_busy && w_complete)
+			|| (r_continuous && overflow);
+
+	//
+	// Error conditions
+	//
+	initial	r_err = 0;
+	initial	r_errcode = ERRCODE_NOERR;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		r_err <= 0;
+		r_errcode <= ERRCODE_NOERR;
+	end else if (!r_busy)
+	begin
+		if (r_continuous && overflow)
+		begin
+			r_err <= 1;
+			r_errcode[ERRCODE_OVERFLOW] <= 1'b1;
+		end
+
+		if (axil_write_ready && awskd_addr == CMD_CONTROL
+			&& wskd_strb[3] && wskd_data[30])
+		begin
+			r_err     <= 0;
+			r_errcode <= ERRCODE_NOERR;
+		end
+	end else if (r_busy)
+	begin
+		if (M_AXI_BVALID && M_AXI_BREADY && M_AXI_BRESP[1])
+		begin
+			r_err <= 1'b1;
+			if (M_AXI_BRESP[0])
+				r_errcode[ERRCODE_DECERR] <= 1'b1;
+			else
+				r_errcode[ERRCODE_SLVERR] <= 1'b1;
+		end
+
+		if (overflow)
+		begin
+			r_err <= 1'b1;
+			r_errcode[ERRCODE_OVERFLOW] <= 1'b1;
+		end
+	end
+
+	initial	r_continuous = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		r_continuous <= 0;
+	else begin
+		if (r_continuous && overflow)
+			r_continuous <= 1'b0;
+		if (!r_busy && axil_write_ready && awskd_addr == CMD_CONTROL)
+			r_continuous <= wskd_strb[3] && wskd_data[28];
+	end
+
+	always @(*)
+	begin
+		wide_address = 0;
+		wide_address[C_AXI_ADDR_WIDTH-1:0] = cmd_addr;
+
+		wide_length = 0;
+		wide_length[ADDRLSB +: LGLENW] = cmd_length_w;
+	end
+
+
+	assign	new_cmdaddrlo= apply_wstrb(
+			wide_address[C_AXIL_DATA_WIDTH-1:0],
+			wskd_data, wskd_strb);
+	assign	new_cmdaddrhi=apply_wstrb(
+			wide_address[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH],
+			wskd_data, wskd_strb);
+	assign	new_lengthlo= apply_wstrb(
+			wide_length[C_AXIL_DATA_WIDTH-1:0],
+			wskd_data, wskd_strb);
+	assign	new_lengthhi= apply_wstrb(
+			wide_length[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH],
+			wskd_data, wskd_strb);
+
+	always @(*)
+	begin
+		new_wideaddr = wide_address;
+		if (awskd_addr == CMD_ADDRLO)
+			new_wideaddr[C_AXIL_DATA_WIDTH-1:0]
+				= new_cmdaddrlo;
+		if (awskd_addr == CMD_ADDRHI)
+			new_wideaddr[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH]
+				= new_cmdaddrhi;
+		if (!OPT_UNALIGNED)
+			new_wideaddr[ADDRLSB-1:0] = 0;
+
+		// We only support C_AXI_ADDR_WIDTH address bits
+		new_wideaddr[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH] = 0;
+
+		//
+		///////////////
+		//
+
+		new_widelen = wide_length;
+		if (awskd_addr == CMD_LENLO)
+			new_widelen[C_AXIL_DATA_WIDTH-1:0] = new_lengthlo;
+		if (awskd_addr == CMD_LENHI)
+			new_widelen[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH]
+				= new_lengthhi;
+
+		// We only support integer numbers of words--even if unaligned
+		new_widelen[ADDRLSB-1:0] = 0;
+
+		// We only support LGLEN length bits
+		new_widelen[2*C_AXIL_DATA_WIDTH-1:LGLEN] = 0;
+	end
+
+	initial	r_increment   = 1'b1;
+	initial	cmd_addr      = 0;
+	initial	cmd_length_w  = 0;	// Counts in bytes
+	initial	zero_length   = 1;
+	initial aw_multiple_full_bursts  = 0;
+	initial aw_multiple_fixed_bursts = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		r_increment <= 1'b1;
+		cmd_addr      <= 0;
+		cmd_length_w  <= 0;
+		zero_length   <= 1;
+		aw_multiple_full_bursts  <= 0;
+		aw_multiple_fixed_bursts <= 0;
+	end else if (axil_write_ready && !r_busy)
+	begin
+		case(awskd_addr)
+		CMD_CONTROL:
+			r_increment <= !wskd_data[27];
+		CMD_ADDRLO: begin
+			cmd_addr <= new_wideaddr[C_AXI_ADDR_WIDTH-1:0];
+			end
+		CMD_ADDRHI: if (C_AXI_ADDR_WIDTH > C_AXIL_DATA_WIDTH)
+			begin
+			cmd_addr <= new_wideaddr[C_AXI_ADDR_WIDTH-1:0];
+			end
+		CMD_LENLO: begin
+			cmd_length_w <= new_widelen[ADDRLSB +: LGLENW];
+			zero_length <= (new_widelen[ADDRLSB +: LGLENW] == 0);
+			aw_multiple_full_bursts  <= |new_widelen[LGLEN-1:(ADDRLSB+LGMAXBURST)];
+			aw_multiple_fixed_bursts <= |new_widelen[LGLEN-1:(ADDRLSB+LGMAX_FIXED_BURST)];
+
+			end
+		CMD_LENHI: if (LGLEN > C_AXIL_DATA_WIDTH)
+			begin
+			cmd_length_w <= new_widelen[ADDRLSB +: LGLENW];
+			zero_length <= (new_widelen[ADDRLSB +: LGLENW] == 0);
+			aw_multiple_full_bursts  <= |new_widelen[LGLEN-1:(ADDRLSB+LGMAXBURST)];
+			aw_multiple_fixed_bursts <= |new_widelen[LGLEN-1:(ADDRLSB+LGMAX_FIXED_BURST)];
+			end
+		default: begin end
+		endcase
+	end else if (r_busy && r_continuous)
+		cmd_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+					<= axi_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB];
+
+	always @(*)
+	begin
+		w_status_word = 0;
+
+		// The ABORT_KEY needs to be chosen so as not to look
+		// like these bits, lest someone read from the register
+		// and write back to it accidentally aborting any transaction
+		w_status_word[31] = r_busy;
+		w_status_word[30] = r_err;
+		w_status_word[29] = r_complete;
+		w_status_word[28] = r_continuous;
+		w_status_word[27] = !r_increment;
+		w_status_word[26] = !r_tlast_syncd;
+		w_status_word[25:23] = r_errcode;
+		w_status_word[22] = cmd_abort;
+		w_status_word[20:16] = LGFIFO;
+	end
+
+	always @(posedge i_clk)
+	if (!axil_read_valid || S_AXIL_RREADY)
+	begin
+		case(arskd_addr)
+		CMD_CONTROL: axil_read_data <= w_status_word;
+		CMD_ADDRLO:  axil_read_data <= wide_address[C_AXIL_DATA_WIDTH-1:0];
+		CMD_ADDRHI:  axil_read_data <= wide_address[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+		CMD_LENLO:   axil_read_data <= wide_length[C_AXIL_DATA_WIDTH-1:0];
+		CMD_LENHI:   axil_read_data <= wide_length[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+		default:     axil_read_data <= 0;
+		endcase
+	end
+
+	function [C_AXIL_DATA_WIDTH-1:0] apply_wstrb;
+		input   [C_AXIL_DATA_WIDTH-1:0]  prior_data;
+		input   [C_AXIL_DATA_WIDTH-1:0]  new_data;
+		input   [C_AXIL_DATA_WIDTH/8-1:0]   wstrb;
+
+		integer k;
+		for(k=0; k<C_AXIL_DATA_WIDTH/8; k=k+1)
+		begin
+			apply_wstrb[k*8 +: 8]
+				= wstrb[k] ? new_data[k*8 +: 8] : prior_data[k*8 +: 8];
+		end
+	endfunction
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The data FIFO section
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	assign	reset_fifo = i_reset || (!r_busy && (!r_continuous || r_err));
+	assign	write_to_fifo  = S_AXIS_TVALID && S_AXIS_TREADY&& r_tlast_syncd;
+	assign	read_from_fifo = M_AXI_WVALID  && M_AXI_WREADY
+					&& !axi_abort_pending;
+
+	// We are ready if the FIFO isn't full and ...
+	//	if OPT_TREADY_WHILE_IDLE is true
+	//		at which point we ignore incoming data when we aren't
+	//		busy, or
+	//	if we aren't resetting the FIFO--that is, if data is actually
+	//		going into the FIFO, or
+	// 	if we are ever out of synchronization--then we can ignore data
+	//		until the next TLAST comes, where we must realign
+	//		ourselves
+	assign	S_AXIS_TREADY  = !fifo_full && (OPT_TREADY_WHILE_IDLE
+					|| !reset_fifo || !r_tlast_syncd);
+
+	generate if (OPT_TLAST_SYNC)
+	begin
+		// If the user has set OPT_TLAST_SYNC, then he wants to make
+		// certain that we don't start writing until the first stream
+		// value after the TLAST packet indicating an end of packet.
+		// For this cause, we'll maintain an r_tlast_syncd value
+		// indicating that the last value was a TLAST.  If, at any
+		// time afterwards, a value is accepted into the stream but not
+		// into the FIFO, then the stream is now out of sync and
+		// r_tlast_syncd will drop.
+		//
+		// Note, this doesn't catch the case where the FIFO can't keep
+		// up.  Lost data (might be) caught by overflow below.
+		initial	r_tlast_syncd = 1;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			r_tlast_syncd <= 1;
+		else if (S_AXIS_TVALID && S_AXIS_TREADY && S_AXIS_TLAST)
+			r_tlast_syncd <= 1;
+		else if (S_AXIS_TVALID && S_AXIS_TREADY && !write_to_fifo)
+			r_tlast_syncd <= 0;
+
+	end else begin
+
+		//
+		// If the option isn't set, then we are always synchronized.
+		//
+		always @(*)
+			r_tlast_syncd = 1;
+	end endgenerate
+
+	generate if (C_AXIS_TUSER_WIDTH > 0)
+	begin : FIFO_WITH_USER_DATA
+
+		sfifo #(.BW(C_AXIS_TUSER_WIDTH + C_AXI_DATA_WIDTH), .LGFLEN(LGFIFO))
+		sfifo(i_clk, reset_fifo,
+			write_to_fifo, { S_AXIS_TUSER, S_AXIS_TDATA },
+						fifo_full, fifo_fill,
+			read_from_fifo, fifo_data, fifo_empty);
+
+		assign	{ M_AXI_WUSER, M_AXI_WDATA }  = fifo_data;
+
+	end else begin : NO_USER_DATA
+
+		sfifo #(.BW(C_AXI_DATA_WIDTH), .LGFLEN(LGFIFO))
+		sfifo(i_clk, reset_fifo,
+			write_to_fifo, S_AXIS_TDATA, fifo_full, fifo_fill,
+			read_from_fifo, fifo_data, fifo_empty);
+
+		assign	M_AXI_WDATA = fifo_data;
+		assign	M_AXI_WUSER = 0;
+
+		// Verilator lint_off UNUSED
+		wire	unused_tuser;
+		assign	unused_tuser = &{ 1'b0, S_AXIS_TUSER };
+		// Verilator lint_on UNUSED
+	end endgenerate
+
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The outgoing AXI (full) protocol section
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// {{{
+
+	// Some counters to keep track of our state
+	// {{{
+
+
+	// Count the number of word writes left to be requested, starting
+	// with the overall command length and then reduced by M_AWLEN on
+	// each address write
+	// {{{
+	always @(*)
+	begin
+		// aw_next_remaining = aw_requests_remaining;
+		// if (phantom_start)
+		//	aw_next_remaining = aw_requests_remaining
+		//		+  (~{{ (LGLENW-8){1'b0}}, M_AXI_AWLEN });
+		//		// - (M_AXI_AWLEN+1)
+		//		// + (~M_AXI_AWLEN+1) - 1
+		//		// + ~M_AXI_AWLEN
+		aw_next_remaining = aw_requests_remaining
+			+ { {(LGLENW-8){phantom_start}},
+					(phantom_start) ? ~M_AXI_AWLEN : 8'h00};
+	end
+
+	initial	r_pre_start = 1;
+	always @(posedge i_clk)
+	if (!r_busy)
+		r_pre_start <= 1;
+	else
+		r_pre_start <= 0;
+
+	always @(posedge i_clk)
+	if (!r_busy)
+	begin
+		aw_needs_alignment <= 0;
+
+		if (|new_wideaddr[ADDRLSB +: LGMAXBURST])
+		begin
+			if (|new_widelen[LGLEN-1:(LGMAXBURST+ADDRLSB)])
+				aw_needs_alignment <= 1;
+			if (~new_wideaddr[ADDRLSB +: LGMAXBURST]
+					< new_widelen[ADDRLSB +: LGMAXBURST])
+				aw_needs_alignment <= 1;
+		end
+	end
+
+	initial	aw_none_remaining = 1;
+	initial	aw_requests_remaining = 0;
+	always @(posedge i_clk)
+	if (!r_busy)
+	begin
+		aw_requests_remaining <= cmd_length_w;
+		aw_none_remaining     <= zero_length;
+		aw_multiple_bursts_remaining <= |cmd_length_w[LGLENW-1:LGMAXBURST+1];
+	end else if (cmd_abort || axi_abort_pending)
+	begin
+		aw_requests_remaining <= 0;
+		aw_none_remaining <= 1;
+		aw_multiple_bursts_remaining <= 0;
+	end else if (phantom_start)
+	begin
+		aw_requests_remaining <= aw_next_remaining;
+		aw_none_remaining<= !aw_multiple_bursts_remaining
+			&&(aw_next_remaining[LGMAXBURST:0] == 0);
+		aw_multiple_bursts_remaining
+				<= |aw_next_remaining[LGLENW-1:LGMAXBURST+1];
+	end
+	// }}}
+
+	// Calculate the maximum possible burst length, ignoring 4kB boundaries
+	// {{{
+	always @(*)
+		addralign = 1+(~cmd_addr[ADDRLSB +: LGMAXBURST]);
+
+	always @(*)
+	begin
+		initial_burstlen = (1<<LGMAXBURST);
+		if (!r_increment)
+		begin
+			initial_burstlen = MAX_FIXED_BURST;
+			if (!aw_multiple_fixed_bursts)
+				initial_burstlen = { 1'b0, cmd_length_w[LGMAXBURST-1:0] };
+		end else if (aw_needs_alignment)
+			initial_burstlen = { 1'b0, addralign };
+		else if (!aw_multiple_full_bursts)
+			initial_burstlen = { 1'b0, cmd_length_w[LGMAXBURST-1:0] };
+	end
+
+	initial	r_max_burst = 0;
+	always @(posedge i_clk)
+	if (!r_busy || r_pre_start)
+	begin
+		// Force us to align ourself early
+		//   That way we don't need to check for
+		//   alignment (again) later
+		r_max_burst <= initial_burstlen;
+	end else if (phantom_start)
+	begin
+		// Verilator lint_off WIDTH
+		if (r_increment || LGMAXBURST <= LGMAX_FIXED_BURST)
+		begin
+			if (!aw_multiple_bursts_remaining
+				&& aw_next_remaining[LGMAXBURST:0] < (1<<LGMAXBURST))
+				r_max_burst <= { 1'b0, aw_next_remaining[7:0] };
+			else
+				r_max_burst <= (1<<LGMAXBURST);
+		end else begin
+			if (!aw_multiple_bursts_remaining
+				&& aw_next_remaining[LGMAXBURST:0] < MAX_FIXED_BURST)
+				r_max_burst <= { 1'b0, aw_next_remaining[7:0] };
+			else
+				r_max_burst <= MAX_FIXED_BURST;
+		end
+		// Verilator lint_on WIDTH
+	end
+	// }}}
+
+	// Count the number of bursts outstanding--these are the number of
+	// AWVALIDs that have been accepted, but for which the BVALID has not
+	// (yet) been returned.
+	// {{{
+	initial	aw_last_outstanding   = 0;
+	initial	aw_bursts_outstanding = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		aw_bursts_outstanding <= 0;
+		aw_last_outstanding <= 0;
+	end else case ({ phantom_start, M_AXI_BVALID && M_AXI_BREADY })
+	2'b01:	begin
+		aw_bursts_outstanding <= aw_bursts_outstanding - 1;
+		aw_last_outstanding <= (aw_bursts_outstanding == 2);
+		end
+	2'b10:	begin
+		aw_bursts_outstanding <= aw_bursts_outstanding + 1;
+		aw_last_outstanding   <= (aw_bursts_outstanding == 0);
+		end
+	default: begin end
+	endcase
+	// }}}
+
+	// Are we there yet?
+	// {{{
+	always @(*)
+	if (!r_busy)
+		w_complete = 0;
+	else
+		w_complete = !M_AXI_AWVALID && (aw_none_remaining)&&(aw_last_outstanding) && (M_AXI_BVALID);
+	// }}}
+
+	// Are we stopping early?  Aborting something ongoing?
+	// {{{
+	initial	axi_abort_pending = 0;
+	always @(posedge i_clk)
+	if (i_reset || !r_busy)
+		axi_abort_pending <= 0;
+	else begin
+		if (M_AXI_BVALID && M_AXI_BREADY && M_AXI_BRESP[1])
+			axi_abort_pending <= 1;
+		if (cmd_abort)
+			axi_abort_pending <= 1;
+		if (r_err)
+			axi_abort_pending <= 1;
+	end
+	// }}}
+
+	// Count the number of WVALIDs yet to be sent on the write channel
+	// {{{
+	initial	wr_none_pending = 1;
+	initial	wr_writes_pending = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		wr_writes_pending <= 0;
+		wr_none_pending   <= 1;
+	end else case ({ phantom_start,
+			M_AXI_WVALID && M_AXI_WREADY })
+	2'b00: begin end
+	2'b01: begin
+		wr_writes_pending <= wr_writes_pending - 1;
+		wr_none_pending   <= (wr_writes_pending == 1);
+		end
+	2'b10: begin
+		wr_writes_pending <= wr_writes_pending + (M_AXI_AWLEN + 1);
+		wr_none_pending   <= 0;
+		end
+	2'b11: begin
+		wr_writes_pending <= wr_writes_pending + (M_AXI_AWLEN);
+		wr_none_pending   <= (M_AXI_WLAST);
+		end
+	endcase
+	// }}}
+
+	// So that we can monitor where we are at, and perhaps restart it
+	// later, keep track of the current address used by the W-channel
+	// {{{
+	initial	axi_addr = 0;
+	always @(posedge i_clk)
+	begin
+		if (!r_busy)
+			axi_addr <= cmd_addr;
+		else if (axi_abort_pending || !r_increment)
+			// Stop incrementing the address following an abort
+			axi_addr <= axi_addr;
+		else if (M_AXI_WVALID && M_AXI_WREADY)
+			axi_addr <= axi_addr + (1<<ADDRLSB);
+
+		if (!OPT_UNALIGNED)
+			axi_addr[ADDRLSB-1:0] <= 0;
+	end
+	// }}}
+
+	// Count the number of words remaining to be written on the W channel
+	// {{{
+	// initial	r_none_remaining = 1;
+	initial	r_remaining_w = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		r_remaining_w <= 0;
+		// r_none_remaining <= 1;
+	end else if (!r_busy)
+	begin
+		r_remaining_w<= cmd_length_w;
+		// r_none_remaining <= zero_length;
+	end else if (M_AXI_WVALID && M_AXI_WREADY)
+	begin
+		r_remaining_w <= r_remaining_w - 1;
+		// r_none_remaining <= (r_remaining_w == 1);
+	end
+	// }}}
+
+	//
+	// }}}
+
+	// Phantom starts
+	// {{{
+	// Since we can't use the xREADY signals in our signaling, we hvae to
+	// be ready to generate both AWVALID and WVALID on the same cycle,
+	// and then hold AWVALID until it has been accepted.  This means we
+	// can't use AWVALID as our burst start signal like we could in the
+	// slave.  Instead, we'll use a "phantom" start signal.  This signal
+	// is local here in our code.  When this signal goes high, AWVALID
+	// and WVALID go high at the same time.  Then, if AWREADY isn't held,
+	// we can still update all of our internal counters as though it were,
+	// based upon the phantom_start signal, and continue as though
+	// AWVALID were accepted on its first clock period.
+
+	always @(*)
+	begin
+		// We start again if there's more information to transfer
+		w_phantom_start = !aw_none_remaining;
+
+		// But not if the amount of information we need isn't (yet)
+		// in the FIFO.
+		if (!sufficiently_filled)
+			w_phantom_start = 0;
+
+		// Insist on a minimum of one clock between burst starts,
+		// since our burst length calculation takes a clock to do
+		if (phantom_start || r_pre_start)
+			w_phantom_start = 0;
+
+		if (M_AXI_AWVALID && !M_AXI_AWREADY)
+			w_phantom_start = 0;
+
+		// If we're still writing the last burst, then don't start
+		// any new ones
+		if (M_AXI_WVALID && (!M_AXI_WLAST || !M_AXI_WREADY))
+			w_phantom_start = 0;
+
+		// Finally, don't start any new bursts if we aren't already
+		// busy transmitting, or if we are in the process of aborting
+		// our transfer
+		if (!r_busy || cmd_abort || axi_abort_pending)
+			w_phantom_start = 0;
+	end
+
+	initial	phantom_start = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		phantom_start <= 0;
+	else
+		phantom_start <= w_phantom_start;
+	// }}}
+
+
+	//
+	// WLAST
+	// {{{
+	always @(posedge i_clk)
+	if (!r_busy)
+	begin
+		axi_wlast <= (cmd_length_w == 1);
+	end else if (!M_AXI_WVALID || M_AXI_WREADY)
+	begin
+		if (w_phantom_start)
+			axi_wlast <= (r_max_burst == 1);
+		else if (phantom_start)
+			axi_wlast <= (M_AXI_AWLEN == 1);
+		else
+			axi_wlast <= (wr_writes_pending == 1 + (M_AXI_WVALID ? 1:0));
+	end
+	// }}}
+
+	// Calculate AWLEN and AWADDR for the next AWVALID
+	// {{{
+	//
+	initial	data_available = 0;
+	always @(posedge i_clk)
+	if (reset_fifo)
+		data_available <= 0;
+	else if (axi_abort_pending)
+		data_available <= fifo_fill + (write_to_fifo ? 1:0);
+	else case({ write_to_fifo, phantom_start })
+	2'b10: data_available <= data_available + 1;
+	// Verilator lint_off WIDTH
+	2'b01: data_available <= data_available - (M_AXI_AWLEN+1);
+	2'b11: data_available <= data_available - (M_AXI_AWLEN);
+	// Verilator lint_on  WIDTH
+	default: begin end
+	endcase
+
+	always @(*)
+	if (|aw_requests_remaining[LGLENW-1:LGMAXBURST])
+		sufficiently_filled = |data_available[LGFIFO:LGMAXBURST];
+	else
+		sufficiently_filled = (data_available[LGMAXBURST-1:0]
+				>= aw_requests_remaining[LGMAXBURST-1:0]);
+
+	//
+	//
+	always @(posedge i_clk)
+	begin
+		if (!M_AXI_AWVALID || M_AXI_AWREADY)
+			axi_awlen  <= r_max_burst[7:0] - 8'd1;
+
+		if (M_AXI_AWVALID && M_AXI_AWREADY)
+		begin
+			axi_awaddr[ADDRLSB-1:0] <= 0;
+			// Verilator lint_off WIDTH
+			if (r_increment)
+				axi_awaddr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+				    <= axi_awaddr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+						+ (M_AXI_AWLEN+1);
+			// Verilator lint_on WIDTH
+		end
+
+		if (!r_busy)
+			axi_awaddr<= cmd_addr;
+
+		if (!OPT_UNALIGNED)
+			axi_awaddr[ADDRLSB-1:0] <= 0;
+	end
+	// }}}
+
+	// AWVALID
+	// {{{
+	initial	axi_awvalid = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		axi_awvalid <= 0;
+	else if (!M_AXI_AWVALID || M_AXI_AWREADY)
+		axi_awvalid <= w_phantom_start;
+	// }}}
+
+	// WVALID
+	// {{{
+	initial	axi_wvalid = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		axi_wvalid <= 0;
+	else if (!M_AXI_WVALID || M_AXI_WREADY)
+	begin
+		if (M_AXI_WVALID && !M_AXI_WLAST)
+			axi_wvalid <= 1;
+		else
+			axi_wvalid <= w_phantom_start;
+	end
+	// }}}
+
+	always @(posedge i_clk)
+	if (!M_AXI_WVALID || M_AXI_WREADY)
+		axi_wstrb <= (axi_abort_pending) ? 0:-1;
+	// }}}
+
+	// {{{
+	assign	M_AXI_AWVALID= axi_awvalid;
+	assign	M_AXI_AWID   = AXI_ID;
+	assign	M_AXI_AWADDR = axi_awaddr;
+	assign	M_AXI_AWLEN  = axi_awlen;
+	// Verilator lint_off WIDTH
+	assign	M_AXI_AWSIZE = $clog2(C_AXI_DATA_WIDTH)-3;
+	// Verilator lint_on  WIDTH
+	assign	M_AXI_AWBURST= { 1'b0, r_increment };
+	assign	M_AXI_AWLOCK = 0;
+	assign	M_AXI_AWCACHE= 0;
+	assign	M_AXI_AWPROT = 0;
+	assign	M_AXI_AWQOS  = 0;
+
+	assign	M_AXI_WVALID = axi_wvalid;
+	assign	M_AXI_WSTRB  = axi_wstrb;
+	assign	M_AXI_WLAST  = axi_wlast;
+	// M_AXI_WLAST = ??
+
+	assign	M_AXI_BREADY = 1;
+
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, S_AXIL_AWPROT, S_AXIL_ARPROT, M_AXI_BID,
+			M_AXI_BRESP[0], fifo_empty,
+			wr_none_pending, S_AXIL_ARADDR[AXILLSB-1:0],
+			S_AXIL_AWADDR[AXILLSB-1:0],
+			new_wideaddr[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH],
+			new_widelen[2*C_AXIL_DATA_WIDTH-1:LGLEN],
+			new_widelen[AXILLSB-1:0] };
+	// Verilator lint_on  UNUSED
+	// }}}
+`ifdef	FORMAL
+	//
+	// The formal properties for this unit are maintained elsewhere.
+	// This core does, however, pass a full prove (w/ induction) for all
+	// bus properties.
+	//
+	// ...
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The AXI-stream data interface
+	// {{{
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// (These are captured by the FIFO within)
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The AXI-lite control interface
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	localparam	F_AXIL_LGDEPTH = 4;
+
+	faxil_slave #(
+		// {{{
+		.C_AXI_DATA_WIDTH(C_AXIL_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXIL_ADDR_WIDTH),
+		.F_LGDEPTH(F_AXIL_LGDEPTH),
+		.F_AXI_MAXWAIT(2),
+		.F_AXI_MAXDELAY(2),
+		.F_AXI_MAXRSTALL(3)
+		// }}}
+	) faxil(
+		// {{{
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXIL_AWVALID),
+		.i_axi_awready(S_AXIL_AWREADY),
+		.i_axi_awaddr( S_AXIL_AWADDR),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot( S_AXIL_AWPROT),
+		//
+		.i_axi_wvalid(S_AXIL_WVALID),
+		.i_axi_wready(S_AXIL_WREADY),
+		.i_axi_wdata( S_AXIL_WDATA),
+		.i_axi_wstrb( S_AXIL_WSTRB),
+		//
+		.i_axi_bvalid(S_AXIL_BVALID),
+		.i_axi_bready(S_AXIL_BREADY),
+		.i_axi_bresp( S_AXIL_BRESP),
+		//
+		.i_axi_arvalid(S_AXIL_ARVALID),
+		.i_axi_arready(S_AXIL_ARREADY),
+		.i_axi_araddr( S_AXIL_ARADDR),
+		.i_axi_arcache(4'h0),
+		.i_axi_arprot( S_AXIL_ARPROT),
+		//
+		.i_axi_rvalid(S_AXIL_RVALID),
+		.i_axi_rready(S_AXIL_RREADY),
+		.i_axi_rdata( S_AXIL_RDATA),
+		.i_axi_rresp( S_AXIL_RRESP),
+		//
+		.f_axi_rd_outstanding(faxil_rd_outstanding),
+		.f_axi_wr_outstanding(faxil_wr_outstanding),
+		.f_axi_awr_outstanding(faxil_awr_outstanding)
+		// }}}
+		);
+
+	always @(*)
+	begin
+		assert(faxil_rd_outstanding == (S_AXIL_RVALID ? 1:0)
+			+(S_AXIL_ARREADY ? 0:1));
+		assert(faxil_wr_outstanding == (S_AXIL_BVALID ? 1:0)
+			+(S_AXIL_WREADY ? 0:1));
+		assert(faxil_awr_outstanding== (S_AXIL_BVALID ? 1:0)
+			+(S_AXIL_AWREADY ? 0:1));
+	end
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The AXI master memory interface
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	//
+	// ...
+	//
+
+	faxi_master #(
+		// {{{
+		.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		//
+		.OPT_EXCLUSIVE(1'b0),
+		.OPT_NARROW_BURST(1'b0),
+		//
+		// ...
+		// }}}
+	) faxi(
+		// {{{
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(M_AXI_AWVALID),
+		.i_axi_awready(M_AXI_AWREADY),
+		.i_axi_awid(   M_AXI_AWID),
+		.i_axi_awaddr( M_AXI_AWADDR),
+		.i_axi_awlen(  M_AXI_AWLEN),
+		.i_axi_awsize( M_AXI_AWSIZE),
+		.i_axi_awburst(M_AXI_AWBURST),
+		.i_axi_awlock( M_AXI_AWLOCK),
+		.i_axi_awcache(M_AXI_AWCACHE),
+		.i_axi_awprot( M_AXI_AWPROT),
+		.i_axi_awqos(  M_AXI_AWQOS),
+		//
+		.i_axi_wvalid(M_AXI_WVALID),
+		.i_axi_wready(M_AXI_WREADY),
+		.i_axi_wdata( M_AXI_WDATA),
+		.i_axi_wstrb( M_AXI_WSTRB),
+		.i_axi_wlast( M_AXI_WLAST),
+		//
+		.i_axi_bvalid(M_AXI_BVALID),
+		.i_axi_bready(M_AXI_BREADY),
+		.i_axi_bid(   M_AXI_BID),
+		.i_axi_bresp( M_AXI_BRESP),
+		//
+		.i_axi_arvalid(1'b0),
+		.i_axi_arready(1'b0),
+		.i_axi_arid(   M_AXI_AWID),
+		.i_axi_araddr( M_AXI_AWADDR),
+		.i_axi_arlen(  M_AXI_AWLEN),
+		.i_axi_arsize( M_AXI_AWSIZE),
+		.i_axi_arburst(M_AXI_AWBURST),
+		.i_axi_arlock( M_AXI_AWLOCK),
+		.i_axi_arcache(M_AXI_AWCACHE),
+		.i_axi_arprot( M_AXI_AWPROT),
+		.i_axi_arqos(  M_AXI_AWQOS),
+		//
+		.i_axi_rvalid(1'b0),
+		.i_axi_rready(1'b0),
+		.i_axi_rdata({(C_AXI_DATA_WIDTH){1'b0}}),
+		.i_axi_rlast(1'b0),
+		.i_axi_rresp(2'b00)
+		//
+		//
+		// }}}
+	);
+
+	//
+	// ...
+	//
+
+	always @(*)
+		assert(aw_bursts_outstanding
+			== faxi_awr_nbursts
+				+ ((M_AXI_AWVALID&&!phantom_start) ? 1:0));
+
+	//
+	// ...
+	//
+
+	always @(posedge i_clk)
+	if (M_AXI_AWVALID)
+	begin
+		// ...
+		if (phantom_start)
+		begin
+			assert(wr_writes_pending == 0);
+			assert(wr_none_pending);
+		end else if ($past(phantom_start))
+		begin
+			assert(wr_writes_pending <= M_AXI_AWLEN+1);
+		end
+	end else begin
+		// ...
+		assert(wr_none_pending == (wr_writes_pending == 0));
+	end
+
+	always @(*)
+	if (r_busy && !OPT_UNALIGNED)
+		assert(M_AXI_AWADDR[ADDRLSB-1:0] == 0);
+
+	always @(*)
+	if (!OPT_UNALIGNED)
+		assert(cmd_addr[ADDRLSB-1:0] == 0);
+
+	//
+	// ...
+	//
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Other formal properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	// ...
+
+	always @(*)
+	if (!r_busy)
+	begin
+		assert(!M_AXI_AWVALID);
+		assert(!M_AXI_WVALID);
+		assert(!M_AXI_BVALID);
+		//
+		// ...
+		//
+	end
+
+	always @(*)
+		assert(zero_length == (cmd_length_w == 0));
+
+	//
+	// ...
+	//
+	always @(*)
+	if (phantom_start)
+		assert(data_available >= (M_AXI_AWLEN+1));
+	else if (M_AXI_AWVALID)
+		assert(data_available >= 0 && data_available <= (1<<LGFIFO));
+
+
+	always @(*)
+	if (phantom_start)
+		assert(wr_writes_pending == 0);
+
+	always @(*)
+	if (phantom_start)
+		assert(fifo_fill >= (M_AXI_AWLEN+1));
+
+	else if (!axi_abort_pending)
+		assert(fifo_fill >= wr_writes_pending);
+
+	always @(*)
+	if (r_busy)
+	begin
+		if (!aw_none_remaining && !phantom_start)
+		begin
+			assert(aw_requests_remaining
+				+ wr_writes_pending == r_remaining_w);
+
+			// Make sure we don't wrap
+			assert(wr_writes_pending <= r_remaining_w);
+		end else if (!aw_none_remaining)
+		begin
+			assert(aw_requests_remaining == r_remaining_w);
+
+			// Make sure we don't wrap
+			assert(wr_writes_pending == 0);
+		end
+	end else
+		assert(!M_AXI_WVALID);
+
+	always @(*)
+		assert(aw_none_remaining == (aw_requests_remaining == 0));
+
+	always @(*)
+	if (r_busy)
+		assert(aw_multiple_bursts_remaining == (|aw_requests_remaining[LGLENW-1:LGMAXBURST+1]));
+
+	always @(*)
+		assert(aw_last_outstanding == (aw_bursts_outstanding == 1));
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (r_complete)
+		assert(!r_busy);
+
+	always @(*)
+		assert(fifo_fill >= wr_writes_pending);
+
+	always @(*)
+	if (r_busy)
+		assert(r_max_burst <= (1<<LGMAXBURST));
+
+	always @(*)
+	if (r_busy && !r_pre_start)
+		assert((r_max_burst > 0) || (aw_requests_remaining == 0));
+
+
+	always @(*)
+	if (phantom_start)
+	begin
+		assert(M_AXI_AWVALID && M_AXI_WVALID);
+		assert(wr_none_pending);
+		// assert(drain_triggered);
+	end
+
+	always @(posedge i_clk)
+	if (phantom_start)
+	begin
+		assert(r_max_burst > 0);
+		assert(M_AXI_AWLEN == $past(r_max_burst)-1);
+	end
+
+	always @(*)
+	if (r_busy && aw_requests_remaining == f_length)
+		assert(initial_burstlen > 0);
+
+	always @(*)
+	if ((LGMAXBURST < 8) && (r_busy))
+		assert(M_AXI_AWLEN+1 <= (1<<LGMAXBURST));
+
+	always @(*)
+	if (r_busy && !r_increment && (M_AXI_AWVALID
+				|| ((aw_requests_remaining < cmd_length_w)
+					&& (aw_requests_remaining > 0))))
+		assert(M_AXI_AWLEN+1 <= MAX_FIXED_BURST);
+
+	always @(*)
+	if (M_AXI_AWVALID && M_AXI_AWADDR[ADDRLSB +: LGMAXBURST])
+	begin
+		// If we are ever unaligned, our first step should be to
+		// align ourselves
+		assert(M_AXI_AWLEN+1 <=
+			1 +(~M_AXI_AWADDR[ADDRLSB +: LGMAXBURST]));
+	end
+
+	always @(*)
+	if (!wr_none_pending)
+	begin
+		// Second alignment check: every burst must end aligned
+		if (r_increment)
+		assert(axi_addr[ADDRLSB +: LGMAXBURST] + wr_writes_pending
+			<= (1<<LGMAXBURST));
+	end
+
+	always @(posedge i_clk)
+	if (phantom_start)
+	begin
+		assert(axi_awlen == $past(r_max_burst[7:0]) - 8'd1);
+		if (r_increment && (cmd_length_w > axi_awlen + 1)
+			&&(aw_requests_remaining != cmd_length_w))
+			assert(M_AXI_AWADDR[ADDRLSB +: LGMAXBURST] == 0);
+	end
+
+	//
+	// ...
+	//
+
+	// }}}
+
+	//
+	// Synchronization properties
+	// {{{
+	always @(*)
+	if (fifo_full)
+		assert(!S_AXIS_TREADY);
+	else if (OPT_TREADY_WHILE_IDLE)
+		// If we aren't full, and we set TREADY whenever idle,
+		// then we should otherwise have TREADY set at all times
+		assert(S_AXIS_TREADY);
+	else if (!r_tlast_syncd)
+		// If we aren't syncd, always be ready until we finally sync up
+		assert(S_AXIS_TREADY);
+	else if (reset_fifo)
+		// If we aren't accepting any data, but are idling with TREADY
+		// low, then make sure we drop TREADY when idle
+		assert(!S_AXIS_TREADY);
+	else
+		// In all other cases, assert TREADY
+		assert(S_AXIS_TREADY);
+
+
+	//
+	// ...
+	//
+	// }}}
+
+	//
+	// Error logic checking
+	// {{{
+	always @(*)
+	if (!r_err)
+		assert(r_errcode == 0);
+	else
+		assert(r_errcode != 0);
+
+	//
+	// ...
+	//
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $past(S_AXI_ARESETN) && $past(w_cmd_start)
+		&&!$past(overflow && r_continuous))
+		assert(!r_err);
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Contract checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	// 1. All data values must get sent, and none skipped
+	//	Captured in logic above, since M_AXI_WDATA is registered
+	//	within the FIFO and not our interface
+	//
+	// 2. No addresses skipped.
+	// ...
+	//
+
+	// 3. If we aren't incrementing addresses, then our current address
+	//	should always be the axi address
+	always @(*)
+	if (r_busy && !r_increment)
+		assert(axi_addr == cmd_addr);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	reg		cvr_aborted, cvr_buserr;
+	reg	[2:0]	cvr_continued;
+
+	initial	{ cvr_aborted, cvr_buserr } = 0;
+	always @(posedge i_clk)
+	if (i_reset || !r_busy)
+		{ cvr_aborted, cvr_buserr } <= 0;
+	else if (r_busy && !axi_abort_pending)
+	begin
+		if (cmd_abort && wr_writes_pending > 0)
+			cvr_aborted <= 1;
+		if (M_AXI_BVALID && M_AXI_BRESP[1])
+			cvr_buserr <= 1;
+	end
+
+	initial	cvr_continued = 0;
+	always @(posedge i_clk)
+	if (i_reset || r_err || cmd_abort)
+		cvr_continued <= 0;
+	else begin
+		// Cover a continued transaction across two separate bursts
+		if (r_busy && r_continuous)
+			cvr_continued[0] <= 1;
+		if (!r_busy && cvr_continued[0])
+			cvr_continued[1] <= 1;
+		if (r_busy && cvr_continued[1])
+			cvr_continued[2] <= 1;
+
+		//
+		// Artificially force us to look for two separate runs
+		if((!r_busy)&&($changed(cmd_length_w)))
+			cvr_continued <= 0;
+	end
+
+	always @(posedge i_clk)
+	if (f_past_valid && !$past(i_reset) && !i_reset && $fell(r_busy))
+	begin
+		cover( r_err && cvr_aborted);
+		cover( r_err && cvr_buserr);
+		cover(!r_err);
+		if (!r_err && !axi_abort_pending && !cvr_aborted && !cvr_buserr)
+		begin
+			cover(cmd_length_w > 5);
+			cover(cmd_length_w > 8);
+			cover((cmd_length_w > 5)&&(cmd_addr[11:0] == 12'hff0));
+			cover(&cvr_continued && (cmd_length_w > 5));
+		end
+	end
+	// }}}
+
+	// This ends our formal property set
+`endif
+	// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axisafety.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axisafety.v
new file mode 100644
index 0000000..fa93b87
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axisafety.v
@@ -0,0 +1,2085 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axisafety.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Given that 1) AXI interfaces can be difficult to write and to
+//		get right, 2) my experiences with the AXI infrastructure of an
+//	ARM+FPGA is that the device needs a power cycle following a bus fault,
+//	and given that I've now found multiple interfaces that had some bug
+//	or other within them, the following is a bus fault isolator.  It acts
+//	as a bump in the log between the interconnect and the user core.  As
+//	such, it has two interfaces:  The first is the slave interface,
+//	coming from the interconnect.  The second interface is the master
+//	interface, proceeding to a slave that might be faulty.
+//
+//		INTERCONNECT --> (S) AXISAFETY (M) --> POTENTIALLY FAULTY CORE
+//
+//	The slave interface has been formally verified to be a valid AXI
+//	slave, independent of whatever the potentially faulty core might do.
+//	If the user core (i.e. the potentially faulty one) responds validly
+//	to the requests of a master, then this core will turn into a simple
+//	delay on the bus.  If, on the other hand, the user core suffers from
+//	a protocol error, then this core will set one of two output
+//	flags--either o_write_fault or o_read_fault indicating whether a write
+//	or a read fault was detected.  Further attempts to access the user
+//	core will result in bus errors, generated by the AXISAFETY core.
+//
+//	Assuming the bus master can properly detect and deal with a bus error,
+//	this should then make it possible to properly recover from a bus
+//	protocol error without later needing to cycle power.
+//
+//	The core does have a couple of limitations.  For example, it can only
+//	handle one burst transaction, and one ID at a time.  This matches the
+//	performances of Xilinx's example AXI full core, from which many user
+//	cores have have been copied/modified from.  Therefore, there will be
+//	no performance loss for such a core.
+//
+//	Because of this, it is still possible that the user core might have an
+//	undetected fault when using this core.  For example, if the interconnect
+//	issues more than one bus request before receiving the response from the
+//	first request, this safety core will stall the second request,
+//	preventing the downstream core from seeing this second request.  If the
+//	downstream core would suffer from an error while handling the second
+//	request, by preventing the user core from seeing the second request this
+//	core eliminates that potential for error.
+//
+// Usage:	The important part of using this core is to connect the slave
+//		side to the interconnect, and the master side to the user core.
+//
+//	Some options are available:
+//
+//	1) C_S_AXI_ADDR_WIDTH	The number of address bits in the AXI channel
+//	1) C_S_AXI_DATA_WIDTH	The number of data bits in the AXI channel
+//	3) C_S_AXI_ID_WIDTH	The number of bits in an AXI ID.  As currently
+//		written, this number cannot be zero.  You can, however, set it
+//		to '1' and connect all of the relevant ID inputs to zero.
+//
+//	These three parameters have currently been abbreviated with AW, DW, and
+//	IW.  I anticipate returning them to their original meanings, I just
+//	haven't done so (yet).
+//
+//	4) OPT_TIMEOUT		This is the number of clock periods, from
+//		interconnect request to interconnect response, that the
+//		slave needs to respond within.  (The actual timeout from the
+//		user slave's perspective will be shorter than this.)
+//
+//		This timeout is part of the check that a slave core will
+//		always return a response.  From the standpoint of this core,
+//		it can be set arbitrarily large.  (From the standpoint of
+//		formal verification, it needs to be kept short ...)
+//		Feel free to set this even as large as 1ms if you would like.
+//
+//	5) OPT_SELF_RESET	If set, will send a reset signal to the slave
+//		following any write or read fault.  This will cause the other
+//		side of the link (write or read) to fault as well.  Once the
+//		channel then becomes inactive, the slave will be released from
+//		reset and will be able to interact with the rest of the bus
+//		again.
+//
+// Performance:	As mentioned above, this core can handle one read burst and one
+//		write burst at a time, no more.  Further, the core will delay
+//	an input path by one clock and the output path by another clock, so that
+//	the latency involved with using this core is a minimum of two extra
+//	clocks beyond the latency user slave core.
+//
+//	Maximum write latency: N+3 clocks for a burst of N values
+//	Maximum read latency:  N+3 clocks for a burst of N values
+//
+// Faults detected:
+//
+//	Write channel:
+//		1. Raising BVALID prior to the last write value being sent
+//			to the user/slave core.
+//		2. Raising BVALID prior to accepting the write address
+//		3. A BID return ID that doesn't match the request AWID
+//		4. Sending too many returns, such as not dropping BVALID
+//			or raising it when there is no outstanding write
+//			request
+//
+//		While the following technically isn't a violation of the
+//		AXI protocol, it is treated as such by this fault isolator.
+//
+//		5. Accepting write data prior to the write address
+//
+//		The fault isolator will guarantee that AWVALID is raised before
+//		WVALID, so this shouldn't be a problem.
+//
+//	Read channel:
+//
+//		1. Raising RVALID before accepting the read address, ARVALID
+//		2. A return ID that doesn't match the ID that was sent.
+//		3. Raising RVALID after the last return value, and so returning
+//			too many response values
+//		4. Setting the RLAST value on anything but the last value from
+//			the bus.
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// }}}
+module axisafety #(
+	// {{{
+	parameter C_S_AXI_ID_WIDTH	= 1,
+	parameter C_S_AXI_DATA_WIDTH	= 32,
+	parameter C_S_AXI_ADDR_WIDTH	= 16,
+	parameter [0:0] OPT_SELF_RESET  = 0,
+	//
+	// I use the following abbreviations, IW, DW, and AW, to simplify
+	// the code below (and to help it fit within an 80 col terminal)
+	localparam	IW	= C_S_AXI_ID_WIDTH,
+	localparam	DW	= C_S_AXI_DATA_WIDTH,
+	localparam	AW	= C_S_AXI_ADDR_WIDTH,
+	//
+	// OPT_TIMEOUT references the number of clock cycles to wait
+	// between raising the *VALID signal and when the respective
+	// *VALID return signal must be high.  You might wish to set this
+	// to a very high number, to allow your core to work its magic.
+	parameter	OPT_TIMEOUT = 20
+	// }}}
+	) (
+		// {{{
+		output	reg	o_read_fault,
+		output	reg	o_write_fault,
+		// User ports ends
+		// Do not modify the ports beyond this line
+
+		// Global Clock Signal
+		input	wire			S_AXI_ACLK,
+		// Global Reset Signal. This Signal is Active LOW
+		input	wire			S_AXI_ARESETN,
+		output	reg			M_AXI_ARESETN,
+		//
+		// The input side.  This is where slave requests come into
+		// the core.
+		// {{{
+		//
+		//	Write address
+		input	wire [IW-1 : 0]		S_AXI_AWID,
+		input	wire [AW-1 : 0]		S_AXI_AWADDR,
+		input	wire [7 : 0]		S_AXI_AWLEN,
+		input	wire [2 : 0]		S_AXI_AWSIZE,
+		input	wire [1 : 0]		S_AXI_AWBURST,
+		input	wire			S_AXI_AWLOCK,
+		input	wire [3 : 0]		S_AXI_AWCACHE,
+		input	wire [2 : 0]		S_AXI_AWPROT,
+		input	wire [3 : 0]		S_AXI_AWQOS,
+		input	wire			S_AXI_AWVALID,
+		output	reg			S_AXI_AWREADY,
+		//	Write data
+		input	wire [DW-1 : 0]		S_AXI_WDATA,
+		input	wire [(DW/8)-1 : 0]	S_AXI_WSTRB,
+		input	wire			S_AXI_WLAST,
+		input	wire			S_AXI_WVALID,
+		output	reg			S_AXI_WREADY,
+		//	Write return
+		output	reg [IW-1 : 0]		S_AXI_BID,
+		output	reg [1 : 0]		S_AXI_BRESP,
+		output	reg			S_AXI_BVALID,
+		input	wire			S_AXI_BREADY,
+		//	Read address
+		input	wire [IW-1 : 0]		S_AXI_ARID,
+		input	wire [AW-1 : 0]		S_AXI_ARADDR,
+		input	wire [7 : 0]		S_AXI_ARLEN,
+		input	wire [2 : 0]		S_AXI_ARSIZE,
+		input	wire [1 : 0]		S_AXI_ARBURST,
+		input	wire			S_AXI_ARLOCK,
+		input	wire [3 : 0]		S_AXI_ARCACHE,
+		input	wire [2 : 0]		S_AXI_ARPROT,
+		input	wire [3 : 0]		S_AXI_ARQOS,
+		input	wire			S_AXI_ARVALID,
+		output	reg			S_AXI_ARREADY,
+		//	Read data
+		output	reg [IW-1 : 0]		S_AXI_RID,
+		output	reg [DW-1 : 0]		S_AXI_RDATA,
+		output	reg [1 : 0]		S_AXI_RRESP,
+		output	reg			S_AXI_RLAST,
+		output	reg			S_AXI_RVALID,
+		input	wire			S_AXI_RREADY,
+		// }}}
+		//
+		// The output side, where slave requests are forwarded to the
+		// actual slave
+		// {{{
+		//	Write address
+		// {{{
+		output	reg [IW-1 : 0]		M_AXI_AWID,
+		output	reg [AW-1 : 0]		M_AXI_AWADDR,
+		output	reg [7 : 0]		M_AXI_AWLEN,
+		output	reg [2 : 0]		M_AXI_AWSIZE,
+		output	reg [1 : 0]		M_AXI_AWBURST,
+		output	reg			M_AXI_AWLOCK,
+		output	reg [3 : 0]		M_AXI_AWCACHE,
+		output	reg [2 : 0]		M_AXI_AWPROT,
+		output	reg [3 : 0]		M_AXI_AWQOS,
+		output	reg			M_AXI_AWVALID,
+		input	wire			M_AXI_AWREADY,
+		//	Write data
+		output	reg [DW-1 : 0]		M_AXI_WDATA,
+		output	reg [(DW/8)-1 : 0]	M_AXI_WSTRB,
+		output	reg			M_AXI_WLAST,
+		output	reg			M_AXI_WVALID,
+		input	wire			M_AXI_WREADY,
+		//	Write return
+		input	wire [IW-1 : 0]		M_AXI_BID,
+		input	wire [1 : 0]		M_AXI_BRESP,
+		input	wire			M_AXI_BVALID,
+		output	wire			M_AXI_BREADY,
+		// }}}
+		//	Read address
+		// {{{
+		output	reg [IW-1 : 0]		M_AXI_ARID,
+		output	reg [AW-1 : 0]		M_AXI_ARADDR,
+		output	reg [7 : 0]		M_AXI_ARLEN,
+		output	reg [2 : 0]		M_AXI_ARSIZE,
+		output	reg [1 : 0]		M_AXI_ARBURST,
+		output	reg			M_AXI_ARLOCK,
+		output	reg [3 : 0]		M_AXI_ARCACHE,
+		output	reg [2 : 0]		M_AXI_ARPROT,
+		output	reg [3 : 0]		M_AXI_ARQOS,
+		output	reg			M_AXI_ARVALID,
+		input	wire			M_AXI_ARREADY,
+		//	Read data
+		input	wire [IW-1 : 0]		M_AXI_RID,
+		input	wire [DW-1 : 0]		M_AXI_RDATA,
+		input	wire [1 : 0]		M_AXI_RRESP,
+		input	wire			M_AXI_RLAST,
+		input	wire			M_AXI_RVALID,
+		output	wire			M_AXI_RREADY
+		// }}}
+		// }}}
+		// }}}
+	);
+
+	localparam	LGTIMEOUT = $clog2(OPT_TIMEOUT+1);
+	localparam	LSB = $clog2(DW)-3;
+	localparam	EXOKAY = 2'b01;
+	localparam	SLAVE_ERROR = 2'b10;
+	//
+	//
+	// Register declarations
+	// {{{
+	reg			faulty_write_return, faulty_read_return;
+	reg			clear_fault;
+	//
+	// Timer/timeout variables
+	reg	[LGTIMEOUT-1:0]	write_timer,   read_timer;
+	reg			write_timeout, read_timeout;
+
+	//
+	// Double buffer the write address channel
+	reg		r_awvalid, m_awvalid;
+	reg	[IW-1:0] r_awid,   m_awid;
+	reg	[AW-1:0] r_awaddr, m_awaddr;
+	reg	[7:0]	r_awlen,   m_awlen;
+	reg	[2:0]	r_awsize,  m_awsize;
+	reg	[1:0]	r_awburst, m_awburst;
+	reg		r_awlock,  m_awlock;
+	reg	[3:0]	r_awcache, m_awcache;
+	reg	[2:0]	r_awprot,  m_awprot;
+	reg	[3:0]	r_awqos,   m_awqos;
+
+	//
+	// Double buffer for the write channel
+	reg			r_wvalid,m_wvalid;
+	reg	[DW-1:0]	r_wdata, m_wdata;
+	reg	[DW/8-1:0]	r_wstrb, m_wstrb;
+	reg			r_wlast, m_wlast;
+
+	//
+	// Double buffer the write response channel
+	reg			m_bvalid;	// r_bvalid == 0
+	reg	[IW-1:0]	m_bid;
+	reg	[1:0]		m_bresp;
+
+	//
+	// Double buffer the read address channel
+	reg		r_arvalid, m_arvalid;
+	reg	[IW-1:0]	r_arid,    m_arid;
+	reg	[AW-1:0] r_araddr, m_araddr;
+	reg	[7:0]	r_arlen,   m_arlen;
+	reg	[2:0]	r_arsize,  m_arsize;
+	reg	[1:0]	r_arburst, m_arburst;
+	reg		r_arlock,  m_arlock;
+	reg	[3:0]	r_arcache, m_arcache;
+	reg	[2:0]	r_arprot,  m_arprot;
+	reg	[3:0]	r_arqos,   m_arqos;
+
+	//
+	// Double buffer the read data response channel
+	reg			r_rvalid,m_rvalid;
+	reg	[IW-1:0]	         m_rid;
+	reg	[1:0]		r_rresp, m_rresp;
+	reg			         m_rlast;
+	reg	[DW-1:0]	r_rdata, m_rdata;
+
+	//
+	// Write FIFO data
+	reg	[IW-1:0]	wfifo_id;
+	reg			wfifo_lock;
+
+	//
+	// Read FIFO data
+	reg	[IW-1:0]	rfifo_id;
+	reg			rfifo_lock;
+	reg	[8:0]		rfifo_counter;
+	reg			rfifo_empty, rfifo_last, rfifo_penultimate;
+
+	//
+	//
+	reg	[0:0]	s_wbursts;
+	reg	[8:0]	m_wpending;
+	reg		m_wempty, m_wlastctr;
+	reg		waddr_valid, raddr_valid;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write channel processing
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// Write address processing
+	// {{{
+	// S_AXI_AWREADY
+	// {{{
+	initial	S_AXI_AWREADY = (OPT_SELF_RESET) ? 0:1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		S_AXI_AWREADY <= !OPT_SELF_RESET;
+	else if (S_AXI_AWVALID && S_AXI_AWREADY)
+		S_AXI_AWREADY <= 0;
+	else if (clear_fault)
+		S_AXI_AWREADY <= 1;
+	else if (!S_AXI_AWREADY)
+		S_AXI_AWREADY <= !S_AXI_AWREADY && S_AXI_BVALID && S_AXI_BREADY;
+	// }}}
+
+	// waddr_valid
+	// {{{
+	generate if (OPT_SELF_RESET)
+	begin
+		initial	waddr_valid = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			waddr_valid <= 0;
+		else if (S_AXI_AWVALID && S_AXI_AWREADY)
+			waddr_valid <= 1;
+		else if (waddr_valid)
+			waddr_valid <= !S_AXI_BVALID || !S_AXI_BREADY;
+	end else begin
+		always @(*)
+			waddr_valid = !S_AXI_AWREADY;
+	end endgenerate
+	// }}}
+
+	// r_aw*
+	// {{{
+	// Double buffer for the AW* channel
+	//
+	initial	r_awvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	begin
+		if (S_AXI_AWVALID && S_AXI_AWREADY)
+		begin
+			r_awvalid <= 1'b0;
+			r_awid    <= S_AXI_AWID;
+			r_awaddr  <= S_AXI_AWADDR;
+			r_awlen   <= S_AXI_AWLEN;
+			r_awsize  <= S_AXI_AWSIZE;
+			r_awburst <= S_AXI_AWBURST;
+			r_awlock  <= S_AXI_AWLOCK;
+			r_awcache <= S_AXI_AWCACHE;
+			r_awprot  <= S_AXI_AWPROT;
+			r_awqos   <= S_AXI_AWQOS;
+		end else if (M_AXI_AWREADY)
+			r_awvalid <= 0;
+
+		if (!S_AXI_ARESETN)
+			r_awvalid <= 0;
+	end
+	// }}}
+
+	// m_aw*
+	// {{{
+	// Second half of the AW* double-buffer.  The m_* terms reference
+	// either the value in the double buffer (assuming one is in there),
+	// or the incoming value (if the double buffer is empty)
+	//
+	always @(*)
+	if (r_awvalid)
+	begin
+		m_awvalid = r_awvalid;
+		m_awid    = r_awid;
+		m_awaddr  = r_awaddr;
+		m_awlen   = r_awlen;
+		m_awsize  = r_awsize;
+		m_awburst = r_awburst;
+		m_awlock  = r_awlock;
+		m_awcache = r_awcache;
+		m_awprot  = r_awprot;
+		m_awqos   = r_awqos;
+	end else begin
+		m_awvalid = S_AXI_AWVALID && S_AXI_AWREADY;
+		m_awid    = S_AXI_AWID;
+		m_awaddr  = S_AXI_AWADDR;
+		m_awlen   = S_AXI_AWLEN;
+		m_awsize  = S_AXI_AWSIZE;
+		m_awburst = S_AXI_AWBURST;
+		m_awlock  = S_AXI_AWLOCK;
+		m_awcache = S_AXI_AWCACHE;
+		m_awprot  = S_AXI_AWPROT;
+		m_awqos   = S_AXI_AWQOS;
+	end
+	// }}}
+
+	// M_AXI_AW*
+	// {{{
+	// Set the output AW* channel outputs--but only on no fault
+	//
+	initial	M_AXI_AWVALID = 0;
+	always @(posedge S_AXI_ACLK)
+	begin
+		if (!M_AXI_AWVALID || M_AXI_AWREADY)
+		begin
+
+			if (o_write_fault)
+				M_AXI_AWVALID <= 0;
+			else
+				M_AXI_AWVALID <= m_awvalid;
+
+			M_AXI_AWID    <= m_awid;
+			M_AXI_AWADDR  <= m_awaddr;
+			M_AXI_AWLEN   <= m_awlen;
+			M_AXI_AWSIZE  <= m_awsize;
+			M_AXI_AWBURST <= m_awburst;
+			M_AXI_AWLOCK  <= m_awlock;
+			M_AXI_AWCACHE <= m_awcache;
+			M_AXI_AWPROT  <= m_awprot;
+			M_AXI_AWQOS   <= m_awqos;
+		end
+
+		if (!M_AXI_ARESETN)
+			M_AXI_AWVALID <= 0;
+	end
+	// }}}
+	// }}}
+
+	// s_wbursts
+	// {{{
+	// Count write bursts outstanding from the standpoint of
+	// the incoming (slave) channel
+	//
+	// Notice that, as currently built, the count can only ever be one
+	// or zero.
+	//
+	// We'll use this count in a moment to determine if a response
+	// has taken too long, or if a response is returned when there's
+	// no outstanding request
+	initial	s_wbursts = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		s_wbursts <= 0;
+	else if (S_AXI_WVALID && S_AXI_WREADY && S_AXI_WLAST)
+		s_wbursts <= 1;
+	else if (S_AXI_BVALID && S_AXI_BREADY)
+		s_wbursts <= 0;
+	// }}}
+
+	// wfifo_id, wfifo_lock
+	// {{{
+	// Keep track of the ID of the last transaction.  Since we only
+	// ever have one write transaction outstanding, this will need to be
+	// the ID of the returned value.
+	//
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_AWREADY && S_AXI_AWVALID)
+	begin
+		// {{{
+		wfifo_id   <= S_AXI_AWID;
+		wfifo_lock <= S_AXI_AWLOCK;
+		// }}}
+	end
+	// }}}
+
+	// m_wpending, m_wempty, m_wlastctr
+	// {{{
+	// m_wpending counts the number of (remaining) write data values that
+	// need to be sent to the slave.  It counts this number with respect
+	// to the *SLAVE*, not the master.  When m_wpending == 1, WLAST shall
+	// be true.  To make comparisons of (m_wpending == 0) or (m_wpending>0),
+	// m_wempty is assigned to (m_wpending).  Similarly, m_wlastctr is
+	// assigned to (m_wpending == 1).
+	//
+	initial	m_wpending = 0;
+	initial	m_wempty   = 1;
+	initial	m_wlastctr = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || o_write_fault)
+	begin
+		// {{{
+		m_wpending <= 0;
+		m_wempty   <= 1;
+		m_wlastctr <= 0;
+		// }}}
+	end else if (M_AXI_AWVALID && M_AXI_AWREADY)
+	begin
+		// {{{
+		if (M_AXI_WVALID && M_AXI_WREADY)
+		begin
+			// {{{
+			// Accepting AW* and W* packets on the same
+			// clock
+			if (m_wpending == 0)
+			begin
+				// The AW* and W* packets go together
+				m_wpending <= {1'b0, M_AXI_AWLEN};
+				m_wempty   <= (M_AXI_AWLEN == 0);
+				m_wlastctr <= (M_AXI_AWLEN == 1);
+			end else begin
+				// The W* packet goes with the last
+				// AW* command, the AW* packet with a
+				// new one
+				m_wpending <= M_AXI_AWLEN+1;
+				m_wempty   <= 0;
+				m_wlastctr <= (M_AXI_AWLEN == 0);
+			end
+			// }}}
+		end else begin
+			// {{{
+			m_wpending <= M_AXI_AWLEN+1;
+			m_wempty   <= 0;
+			m_wlastctr <= (M_AXI_AWLEN == 0);
+			// }}}
+		end
+		// }}}
+	end else if (M_AXI_WVALID && M_AXI_WREADY && (!m_wempty))
+	begin
+		// {{{
+		// The AW* channel is idle, and we just accepted a value
+		// on the W* channel
+		m_wpending <= m_wpending - 1;
+		m_wempty   <= (m_wpending <= 1);
+		m_wlastctr <= (m_wpending == 2);
+		// }}}
+	end
+	// }}}
+
+	// Write data processing
+	// {{{
+	// S_AXI_WREADY
+	// {{{
+	// The S_AXI_WREADY or write channel stall signal
+	//
+	// For this core, we idle at zero (stalled) until an AW* packet
+	// comes through
+	//
+	initial	S_AXI_WREADY = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		S_AXI_WREADY <= 0;
+	else if (S_AXI_WVALID && S_AXI_WREADY)
+	begin
+		// {{{
+		if (S_AXI_WLAST)
+			S_AXI_WREADY <= 0;
+		else if (o_write_fault)
+			S_AXI_WREADY <= 1;
+		else if (!M_AXI_WVALID || M_AXI_WREADY)
+			S_AXI_WREADY <= 1;
+		else
+			S_AXI_WREADY <= 0;
+		// }}}
+	end else if ((s_wbursts == 0)&&(waddr_valid)
+				&&(o_write_fault || M_AXI_WREADY))
+		S_AXI_WREADY <= 1;
+	else if (S_AXI_AWVALID && S_AXI_AWREADY)
+		S_AXI_WREADY <= 1;
+	// }}}
+
+	// r_w*
+	// {{{
+	// Double buffer for the write channel
+	//
+	// As before, the r_* values contain the values in the double
+	// buffer itself
+	//
+	initial	r_wvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		r_wvalid <= 0;
+	else if (!r_wvalid)
+	begin
+		// {{{
+		r_wvalid <= (S_AXI_WVALID && S_AXI_WREADY
+				&& M_AXI_WVALID && !M_AXI_WREADY);
+		r_wdata <= S_AXI_WDATA;
+		r_wstrb <= S_AXI_WSTRB;
+		r_wlast <= S_AXI_WLAST;
+		// }}}
+	end else if (o_write_fault || M_AXI_WREADY || !M_AXI_ARESETN)
+		r_wvalid <= 0;
+	// }}}
+
+	// m_w*
+	// {{{
+	// Here's the result of our double buffer
+	//
+	// m_* references the value within the double buffer in the case that
+	// something is in the double buffer.  Otherwise, it is the values
+	// directly from the inputs.  In the case of a fault, neither is true.
+	// Write faults override.
+	//
+	always @(*)
+	if (o_write_fault)
+	begin
+		// {{{
+		m_wvalid = !m_wempty;
+		m_wlast  = m_wlastctr;
+		m_wstrb  = 0;
+		// }}}
+	end else if (r_wvalid)
+	begin
+		// {{{
+		m_wvalid = 1;
+		m_wstrb  = r_wstrb;
+		m_wlast  = r_wlast;
+		// }}}
+	end else begin
+		// {{{
+		m_wvalid = S_AXI_WVALID && S_AXI_WREADY;
+		m_wstrb  = S_AXI_WSTRB;
+		m_wlast  = S_AXI_WLAST;
+		// }}}
+	end
+	// }}}
+
+	// m_wdata
+	// {{{
+	// The logic for the DATA output of the double buffer doesn't
+	// matter so much in the case of o_write_fault
+	always @(*)
+	if (r_wvalid)
+		m_wdata = r_wdata;
+	else
+		m_wdata = S_AXI_WDATA;
+	// }}}
+
+	// M_AXI_W*
+	// {{{
+	// Set the downstream write channel values
+	//
+	// As per AXI spec, these values *must* be registered.  Note that our
+	// source here is the m_* double buffer/incoming write data switch.
+	initial	M_AXI_WVALID = 0;
+	always @(posedge S_AXI_ACLK)
+	begin
+		if (!M_AXI_WVALID || M_AXI_WREADY)
+		begin
+			M_AXI_WVALID <= m_wvalid;
+			M_AXI_WDATA  <= m_wdata;
+			M_AXI_WSTRB  <= m_wstrb;
+			M_AXI_WLAST  <= m_wlast;
+		end
+
+		// Override the WVALID signal (only) on reset, voiding any
+		// output we might otherwise send.
+		if (!M_AXI_ARESETN)
+			M_AXI_WVALID <= 0;
+	end
+	// }}}
+	// }}}
+
+	// Write fault detection
+	// {{{
+	// write_timer
+	// {{{
+	// The write timer
+	//
+	// The counter counts up to saturation.  It is reset any time
+	// the write channel is either clear, or a value is accepted
+	// at the *MASTER* (not slave) side.  Why the master side?  Simply
+	// because it makes the proof below easier.  (At one time I checked
+	// both, but then couldn't prove that the faults wouldn't get hit
+	// if the slave responded in time.)
+	initial	write_timer = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !waddr_valid)
+		write_timer <= 0;
+	else if (!o_write_fault && M_AXI_BVALID)
+		write_timer <= 0;
+	else if (S_AXI_WREADY)
+		write_timer <= 0;
+	else if (!(&write_timer))
+		write_timer <= write_timer + 1;
+	// }}}
+
+	// write_timeout
+	// {{{
+	// Write timeout detector
+	//
+	// If the write_timer reaches the OPT_TIMEOUT, then the write_timeout
+	// will get set true.  This will force a fault, taking the write
+	// channel off line.
+	initial	write_timeout = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_fault)
+		write_timeout <= 0;
+	else if (M_AXI_BVALID)
+		write_timeout <= write_timeout;
+	else if (S_AXI_WVALID && S_AXI_WREADY)
+		write_timeout <= write_timeout;
+	else if (write_timer >= OPT_TIMEOUT)
+		write_timeout <= 1;
+	// }}}
+
+	// faulty_write_return
+	// {{{
+	// fault_write_return
+	//
+	// This combinational logic is used to catch an invalid return, and
+	// so take the slave off-line before the return can corrupt the master
+	// channel.  Reasons for taking the write return off line are listed
+	// below.
+	always @(*)
+	begin
+		faulty_write_return = 0;
+		if (M_AXI_WVALID && M_AXI_WREADY
+				&& M_AXI_AWVALID && !M_AXI_AWREADY)
+			// Accepting the write *data* prior to the write
+			// *address* is a fault
+			faulty_write_return = 1;
+		if (M_AXI_BVALID)
+		begin
+			if (M_AXI_AWVALID || M_AXI_WVALID)
+				// Returning a B* acknowledgement while the
+				// request remains outstanding is also a fault
+				faulty_write_return = 1;
+			if (!m_wempty)
+				// Same as above, but this time the write
+				// channel is neither complete, nor is *WVALID
+				// active.  Values remain to be written,
+				// and so a return is a fault.
+				faulty_write_return = 1;
+			if (s_wbursts <= (S_AXI_BVALID ? 1:0))
+				// Too many acknowledgments
+				//
+				// Returning more than one BVALID&BREADY for
+				// every AWVALID & AWREADY is a fault.
+				faulty_write_return = 1;
+			if (M_AXI_BID != wfifo_id)
+				// An attempt to return the wrong ID
+				faulty_write_return = 1;
+			if (M_AXI_BRESP == EXOKAY && !wfifo_lock)
+				// An attempt to return the wrong ID
+				faulty_write_return = 1;
+		end
+	end
+	// }}}
+
+	// o_write_fault
+	// {{{
+	// On a write fault, we're going to disconnect the write port from
+	// the slave, and return errors on each write connect.  o_write_fault
+	// is our signal determining if the write channel is disconnected.
+	//
+	// Most of this work is determined within faulty_write_return above.
+	// Here we do just a bit more:
+	initial	o_write_fault = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_fault)
+		o_write_fault <= 0;
+	else if ((!M_AXI_ARESETN&&o_read_fault) || write_timeout)
+		o_write_fault <= 1;
+	else if (M_AXI_BVALID && M_AXI_BREADY)
+		o_write_fault <= (o_write_fault) || faulty_write_return;
+	else if (M_AXI_WVALID && M_AXI_WREADY
+			&& M_AXI_AWVALID && !M_AXI_AWREADY)
+		// Accepting the write data prior to the write address
+		// is a fault
+		o_write_fault <= 1;
+	// }}}
+	// }}}
+
+	// Write return generation
+	// {{{
+	// m_b*
+	// {{{
+	// Since we only ever allow a single write burst at a time, we don't
+	// need to double buffer the return channel.  Hence, we'll set our
+	// return channel based upon the incoming values alone.  Note that
+	// we're overriding the M_AXI_BID below, in order to make certain that
+	// the return goes to the right source.
+	//
+	always @(*)
+	if (o_write_fault)
+	begin
+		m_bvalid = (s_wbursts > (S_AXI_BVALID ? 1:0));
+		m_bid    = wfifo_id;
+		m_bresp  = SLAVE_ERROR;
+	end else begin
+		m_bvalid = M_AXI_BVALID;
+		if (faulty_write_return)
+			m_bvalid = 0;
+		m_bid    = wfifo_id;
+		m_bresp  = M_AXI_BRESP;
+	end
+	// }}}
+
+	// S_AXI_B*
+	// {{{
+	// We'll *never* stall the slaves BREADY channel
+	//
+	// If the slave returns the response we are expecting, then S_AXI_BVALID
+	// will be low and it can go directly into the S_AXI_BVALID slot.  If
+	// on the other hand the slave returns M_AXI_BVALID at the wrong time,
+	// then we'll quietly accept it and send the write interface into
+	// fault detected mode, setting o_write_fault.
+	//
+	// Sadly, this will create a warning in Vivado.  If/when you see it,
+	// see this note and then just ignore it.
+	assign M_AXI_BREADY = 1;
+
+	//
+	// Return a write acknowlegement at the end of every write
+	// burst--regardless of whether or not the slave does so
+	//
+	initial	S_AXI_BVALID = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		S_AXI_BVALID <= 0;
+	else if (!S_AXI_BVALID || S_AXI_BREADY)
+		S_AXI_BVALID <= m_bvalid;
+
+	//
+	// Set the values associated with the response
+	//
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_BVALID || S_AXI_BREADY)
+	begin
+		S_AXI_BID    <= m_bid;
+		S_AXI_BRESP  <= m_bresp;
+	end
+	// }}}
+
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read channel processing
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// Read address channel
+	// {{{
+
+	// S_AXI_ARREADY
+	// {{{
+	initial	S_AXI_ARREADY = (OPT_SELF_RESET) ? 0:1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		S_AXI_ARREADY <= !OPT_SELF_RESET;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY)
+		S_AXI_ARREADY <= 0;
+	else if (clear_fault)
+		S_AXI_ARREADY <= 1;
+	else if (!S_AXI_ARREADY)
+		S_AXI_ARREADY <= (S_AXI_RVALID && S_AXI_RLAST && S_AXI_RREADY);
+	// }}}
+
+	// raddr_valid
+	// {{{
+	always @(*)
+	if (OPT_SELF_RESET)
+		raddr_valid = !rfifo_empty;
+	else
+		raddr_valid = !S_AXI_ARREADY;
+	// }}}
+
+	// r_ar*
+	// {{{
+	// Double buffer the values associated with any read address request
+	//
+	initial	r_arvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	begin
+		if (S_AXI_ARVALID && S_AXI_ARREADY)
+		begin
+			r_arvalid <= (M_AXI_ARVALID && !M_AXI_ARREADY);
+			r_arid    <= S_AXI_ARID;
+			r_araddr  <= S_AXI_ARADDR;
+			r_arlen   <= S_AXI_ARLEN;
+			r_arsize  <= S_AXI_ARSIZE;
+			r_arburst <= S_AXI_ARBURST;
+			r_arlock  <= S_AXI_ARLOCK;
+			r_arcache <= S_AXI_ARCACHE;
+			r_arprot  <= S_AXI_ARPROT;
+			r_arqos   <= S_AXI_ARQOS;
+		end else if (M_AXI_ARREADY)
+			r_arvalid <= 0;
+
+		if (!M_AXI_ARESETN)
+			r_arvalid <= 0;
+	end
+	// }}}
+
+	// m_ar*
+	// {{{
+	always @(*)
+	if (r_arvalid)
+	begin
+		m_arvalid = r_arvalid;
+		m_arid    = r_arid;
+		m_araddr  = r_araddr;
+		m_arlen   = r_arlen;
+		m_arsize  = r_arsize;
+		m_arburst = r_arburst;
+		m_arlock  = r_arlock;
+		m_arcache = r_arcache;
+		m_arprot  = r_arprot;
+		m_arqos   = r_arqos;
+	end else begin
+		m_arvalid = S_AXI_ARVALID && S_AXI_ARREADY;
+		m_arid    = S_AXI_ARID;
+		m_araddr  = S_AXI_ARADDR;
+		m_arlen   = S_AXI_ARLEN;
+		m_arsize  = S_AXI_ARSIZE;
+		m_arburst = S_AXI_ARBURST;
+		m_arlock  = S_AXI_ARLOCK;
+		m_arcache = S_AXI_ARCACHE;
+		m_arprot  = S_AXI_ARPROT;
+		m_arqos   = S_AXI_ARQOS;
+	end
+	// }}}
+
+	// M_AXI_AR*
+	// {{{
+	// Set the downstream values according to the transaction we've just
+	// received.
+	//
+	initial	M_AXI_ARVALID = 0;
+	always @(posedge S_AXI_ACLK)
+	begin
+		if (!M_AXI_ARVALID || M_AXI_ARREADY)
+		begin
+
+			if (o_read_fault)
+				M_AXI_ARVALID <= 0;
+			else
+				M_AXI_ARVALID <= m_arvalid;
+
+			M_AXI_ARID    <= m_arid;
+			M_AXI_ARADDR  <= m_araddr;
+			M_AXI_ARLEN   <= m_arlen;
+			M_AXI_ARSIZE  <= m_arsize;
+			M_AXI_ARBURST <= m_arburst;
+			M_AXI_ARLOCK  <= m_arlock;
+			M_AXI_ARCACHE <= m_arcache;
+			M_AXI_ARPROT  <= m_arprot;
+			M_AXI_ARQOS   <= m_arqos;
+		end
+
+		if (!M_AXI_ARESETN)
+			M_AXI_ARVALID <= 0;
+	end
+	// }}}
+
+	// }}}
+
+	//
+	// Read fault detection
+	// {{{
+
+	// read_timer
+	// {{{
+	// First step: a timer.  The timer starts as soon as the S_AXI_ARVALID
+	// is accepted.  Once that happens, rfifo_empty will no longer be true.
+	// The count is reset any time the slave produces a value for us to
+	// read.  Once the count saturates, it stops counting.
+	initial	read_timer = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_fault)
+		read_timer <= 0;
+	else if (rfifo_empty||(S_AXI_RVALID))
+		read_timer <= 0;
+	else if (M_AXI_RVALID)
+		read_timer <= 0;
+	else if (!(&read_timer))
+		read_timer <= read_timer + 1;
+	// }}}
+
+	// read_timeout
+	// {{{
+	// Once the counter > OPT_TIMEOUT, we have a timeout condition.
+	// We'll detect this one clock earlier below.  If we ever enter
+	// a read time out condition, we'll set the read fault.  The read
+	// timeout condition can only be cleared by a reset.
+	initial	read_timeout = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_fault)
+		read_timeout <= 0;
+	else if (rfifo_empty||S_AXI_RVALID)
+		read_timeout <= read_timeout;
+	else if (M_AXI_RVALID)
+		read_timeout <= read_timeout;
+	else if (read_timer == OPT_TIMEOUT)
+		read_timeout <= 1;
+	// }}}
+
+	//
+	// faulty_read_return
+	// {{{
+	// To avoid returning a fault from the slave, it is important to
+	// determine within a single clock period whether or not the slaves
+	// return value is at fault or not.  That's the purpose of the code
+	// below.
+	always @(*)
+	begin
+		faulty_read_return = 0;
+		if (M_AXI_RVALID)
+		begin
+			if (M_AXI_ARVALID)
+				// It is a fault to return data apart from a
+				// request.
+				faulty_read_return = 1;
+			if (M_AXI_RID != rfifo_id)
+				// It is a fault to return data from a
+				// different ID
+				faulty_read_return = 1;
+			if (rfifo_last && (S_AXI_RVALID || !M_AXI_RLAST))
+				faulty_read_return = 1;
+			if (rfifo_penultimate && S_AXI_RVALID && (r_rvalid || !M_AXI_RLAST))
+				faulty_read_return = 1;
+			if (M_AXI_RRESP == EXOKAY && !rfifo_lock)
+				// An attempt to return the wrong ID
+				faulty_read_return = 1;
+		end
+	end
+	// }}}
+
+	// o_read_fault
+	// {{{
+	initial	o_read_fault = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || clear_fault)
+		o_read_fault <= 0;
+	else if ((!M_AXI_ARESETN && o_write_fault) || read_timeout)
+		o_read_fault <= 1;
+	else if (M_AXI_RVALID)
+	begin
+		if (faulty_read_return)
+			o_read_fault <= 1;
+		if (!raddr_valid)
+			// It is a fault if we haven't issued an AR* request
+			// yet, and a value is returned
+			o_read_fault <= 1;
+	end
+	// }}}
+
+	// }}}
+
+	//
+	// Read return/acknowledgment processing
+	// {{{
+
+	// r_rvalid
+	// {{{
+	// Step one, set/create the read return double buffer.  If r_rvalid
+	// is true, there's a valid value in the double buffer location.
+	//
+	initial r_rvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || o_read_fault)
+		r_rvalid <= 0;
+	else if (!r_rvalid)
+	begin
+		// {{{
+		// Refuse to set the double-buffer valid on any fault.
+		// That will also keep (below) M_AXI_RREADY high--so that
+		// following the fault the slave might still (pretend) to
+		// respond properly
+		if (faulty_read_return)
+			r_rvalid <= 0;
+		else if (o_read_fault)
+			r_rvalid <= 0;
+		// If there's nothing in the double buffer, then we might
+		// place something in there.  The double buffer only gets
+		// filled under two conditions: 1) something is pending to be
+		// returned, and 2) there's another return that we can't
+		// stall and so need to accept here.
+		r_rvalid <= M_AXI_RVALID && M_AXI_RREADY
+				&& (S_AXI_RVALID && !S_AXI_RREADY);
+		// }}}
+	end else if (S_AXI_RREADY)
+		// Once the up-stream read-channel clears, we can always
+		// clear the double buffer
+		r_rvalid <= 0;
+	// }}}
+
+	// r_rresp, r_rdata
+	// {{{
+	// Here's the actual values kept whenever r_rvalid is true.  This is
+	// the double buffer.  Notice that r_rid and r_last are generated
+	// locally, so not recorded here.
+	//
+	always @(posedge S_AXI_ACLK)
+	if (!r_rvalid)
+	begin
+		r_rresp  <= M_AXI_RRESP;
+		r_rdata  <= M_AXI_RDATA;
+	end
+	// }}}
+
+	// M_AXI_RREADY
+	// {{{
+	// Stall the downstream channel any time there's something in the
+	// double buffer.  In spite of the ! here, this is a registered value.
+	assign M_AXI_RREADY = !r_rvalid;
+	// }}}
+
+	// rfifo_id, rfifo_lock
+	// {{{
+	// Copy the ID for later comparisons on the return
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARVALID && S_AXI_ARREADY)
+	begin
+		rfifo_id   <= S_AXI_ARID;
+		rfifo_lock <= S_AXI_ARLOCK;
+	end
+	// }}}
+
+	// rfifo_[counter|empty|last|penultimate
+	// {{{
+	// Count the number of outstanding read elements.  This is the number
+	// of read returns we still expect--from the upstream perspective.  The
+	// downstream perspective will be off by both what's waiting for
+	// S_AXI_RREADY and what's in the double buffer
+	//
+	initial	rfifo_counter    = 0;
+	initial	rfifo_empty      = 1;
+	initial	rfifo_last       = 0;
+	initial	rfifo_penultimate= 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		rfifo_counter    <= 0;
+		rfifo_empty      <= 1;
+		rfifo_last       <= 0;
+		rfifo_penultimate<= 0;
+	end else if (S_AXI_ARVALID && S_AXI_ARREADY)
+	begin
+		rfifo_counter <= S_AXI_ARLEN+1;
+		rfifo_empty   <= 0;
+		rfifo_last    <= (S_AXI_ARLEN == 0);
+		rfifo_penultimate <= (S_AXI_ARLEN == 1);
+	end else if (!rfifo_empty)
+	begin
+		if (S_AXI_RVALID && S_AXI_RREADY)
+		begin
+			rfifo_counter <= rfifo_counter - 1;
+			rfifo_empty   <= (rfifo_counter <= 1);
+			rfifo_last    <= (rfifo_counter == 2);
+			rfifo_penultimate <= (rfifo_counter == 3);
+		end
+	end
+	// }}}
+
+	// m_rvalid, m_rresp
+	// {{{
+	// Determine values to send back and return
+	//
+	// This data set includes all the return values, even though only
+	// RRESP and RVALID are set in this block.
+	always @(*)
+	if (o_read_fault || (!M_AXI_ARESETN && OPT_SELF_RESET))
+	begin
+		m_rvalid = !rfifo_empty;
+		if (S_AXI_RVALID && rfifo_last)
+			m_rvalid = 0;
+		m_rresp  = SLAVE_ERROR;
+	end else if (r_rvalid)
+	begin
+		m_rvalid = r_rvalid;
+		m_rresp  = r_rresp;
+	end else begin
+		m_rvalid = M_AXI_RVALID && raddr_valid && !faulty_read_return;
+		m_rresp  = M_AXI_RRESP;
+	end
+	// }}}
+
+	// m_rid
+	// {{{
+	// We've stored the ID locally, so that our response will never be in
+	// error
+	always @(*)
+		m_rid = rfifo_id;
+	// }}}
+
+	// m_rlast
+	// {{{
+	// Ideally, we'd want to say m_rlast = rfifo_last.  However, we might
+	// have a value in S_AXI_RVALID already.  In that case, the last
+	// value can only be true if we are one further away from the end.
+	// (Remember, rfifo_last and rfifo_penultimate are both dependent upon
+	// the *upstream* number of read values outstanding, not the downstream
+	// number which we can't trust in all cases)
+	always @(*)
+	if (S_AXI_RVALID)
+		m_rlast = rfifo_penultimate;
+	else
+		m_rlast = (rfifo_last);
+	// }}}
+
+	// m_rdata
+	// {{{
+	// In the case of a fault, rdata is a don't care.  Therefore we can
+	// always set it based upon the values returned from the slave.
+	always @(*)
+	if (r_rvalid)
+		m_rdata = r_rdata;
+	else
+		m_rdata = M_AXI_RDATA;
+	// }}}
+
+	// S_AXI_R*
+	// {{{
+	// Record our return data values
+	//
+	// These are the values from either the slave, the double buffer,
+	// or an error value bypassing either as determined by the m_* values.
+	// Per spec, all of these values must be registered.  First the valid
+	// signal
+	initial	S_AXI_RVALID = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		S_AXI_RVALID <= 0;
+	else if (!S_AXI_RVALID || S_AXI_RREADY)
+		S_AXI_RVALID <= m_rvalid;
+
+	// Then the various slave data channels
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_RVALID || S_AXI_RREADY)
+	begin
+		S_AXI_RID    <= m_rid;
+		S_AXI_RRESP  <= m_rresp;
+		S_AXI_RLAST  <= m_rlast;
+		S_AXI_RDATA  <= m_rdata;
+	end
+	// }}}
+
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Self-reset
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate if (OPT_SELF_RESET)
+	begin
+		// {{{
+		// Declarations
+		// {{{
+		reg	[4:0]	reset_counter;
+		reg		reset_timeout, r_clear_fault;
+		// }}}
+
+		// M_AXI_ARESETN
+		// {{{
+		initial	M_AXI_ARESETN = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			M_AXI_ARESETN <= 0;
+		else if (clear_fault)
+			M_AXI_ARESETN <= 1;
+		else if (o_read_fault || o_write_fault)
+			M_AXI_ARESETN <= 0;
+		// }}}
+
+		// reset_counter
+		// {{{
+		initial	reset_counter = 0;
+		always @(posedge S_AXI_ACLK)
+		if (M_AXI_ARESETN)
+			reset_counter <= 0;
+		else if (!reset_timeout)
+			reset_counter <= reset_counter+1;
+		// }}}
+
+		always @(*)
+			reset_timeout <= reset_counter[4];
+
+		// r_clear_fault
+		// {{{
+		initial	r_clear_fault <= 1;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			r_clear_fault <= 1;
+		else if (!M_AXI_ARESETN && !reset_timeout)
+			r_clear_fault <= 0;
+		else if (!o_read_fault && !o_write_fault)
+			r_clear_fault <= 0;
+		else if (raddr_valid || waddr_valid)
+			r_clear_fault <= 0;
+		else
+			r_clear_fault <= 1;
+		// }}}
+
+		// clear_fault
+		// {{{
+		always @(*)
+		if (S_AXI_AWVALID || S_AXI_ARVALID)
+			clear_fault = 0;
+		else if (raddr_valid || waddr_valid)
+			clear_fault = 0;
+		else
+			clear_fault = r_clear_fault;
+		// }}}
+
+		// }}}
+	end else begin
+		// {{{
+		always @(*)
+			M_AXI_ARESETN = S_AXI_ARESETN;
+		always @(*)
+			clear_fault = 0;
+		// }}}
+	end endgenerate
+	// }}}
+
+	// Make Verilator happy
+	// {{{
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0 };
+	// Verilator lint_on  UNUSED
+	// }}}
+// Add user logic here
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	// {{{
+	// Below are just some of the formal properties used to verify
+	// this core.  The full property set is maintained elsewhere.
+	//
+	parameter [0:0]	F_OPT_FAULTLESS = 1;
+
+	//
+	// ...
+	// }}}
+
+	faxi_slave	#(
+		// {{{
+		.C_AXI_ID_WIDTH(C_S_AXI_ID_WIDTH),
+		.C_AXI_DATA_WIDTH(C_S_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_S_AXI_ADDR_WIDTH)
+		// ...
+		// }}}
+		)
+		f_slave(
+		.i_clk(S_AXI_ACLK),
+		.i_axi_reset_n(S_AXI_ARESETN),
+		// {{{
+		//
+		// Address write channel
+		//
+		.i_axi_awid(S_AXI_AWID),
+		.i_axi_awaddr(S_AXI_AWADDR),
+		.i_axi_awlen(S_AXI_AWLEN),
+		.i_axi_awsize(S_AXI_AWSIZE),
+		.i_axi_awburst(S_AXI_AWBURST),
+		.i_axi_awlock(S_AXI_AWLOCK),
+		.i_axi_awcache(S_AXI_AWCACHE),
+		.i_axi_awprot(S_AXI_AWPROT),
+		.i_axi_awqos(S_AXI_AWQOS),
+		.i_axi_awvalid(S_AXI_AWVALID),
+		.i_axi_awready(S_AXI_AWREADY),
+	//
+	//
+		//
+		// Write Data Channel
+		//
+		// Write Data
+		.i_axi_wdata(S_AXI_WDATA),
+		.i_axi_wstrb(S_AXI_WSTRB),
+		.i_axi_wlast(S_AXI_WLAST),
+		.i_axi_wvalid(S_AXI_WVALID),
+		.i_axi_wready(S_AXI_WREADY),
+	//
+	//
+		// Response ID tag. This signal is the ID tag of the
+		// write response.
+		.i_axi_bid(S_AXI_BID),
+		.i_axi_bresp(S_AXI_BRESP),
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+	//
+	//
+		//
+		// Read address channel
+		//
+		.i_axi_arid(S_AXI_ARID),
+		.i_axi_araddr(S_AXI_ARADDR),
+		.i_axi_arlen(S_AXI_ARLEN),
+		.i_axi_arsize(S_AXI_ARSIZE),
+		.i_axi_arburst(S_AXI_ARBURST),
+		.i_axi_arlock(S_AXI_ARLOCK),
+		.i_axi_arcache(S_AXI_ARCACHE),
+		.i_axi_arprot(S_AXI_ARPROT),
+		.i_axi_arqos(S_AXI_ARQOS),
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+	//
+	//
+		//
+		// Read data return channel
+		//
+		.i_axi_rid(S_AXI_RID),
+		.i_axi_rdata(S_AXI_RDATA),
+		.i_axi_rresp(S_AXI_RRESP),
+		.i_axi_rlast(S_AXI_RLAST),
+		.i_axi_rvalid(S_AXI_RVALID),
+		// Read ready. This signal indicates that the master can
+		// accept the read data and response information.
+		.i_axi_rready(S_AXI_RREADY),
+		//
+		// Formal outputs
+		//
+		.f_axi_awr_nbursts(f_axi_awr_nbursts),
+		.f_axi_wr_pending(f_axi_wr_pending),
+		.f_axi_rd_nbursts(f_axi_rd_nbursts),
+		.f_axi_rd_outstanding(f_axi_rd_outstanding)
+		//
+		// ...
+		// }}}
+	);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write induction properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// {{{
+
+	// 1. We will only ever handle a single burst--never any more
+	always @(*)
+		assert(f_axi_awr_nbursts <= 1);
+
+	always @(*)
+	if (f_axi_awr_nbursts == 1)
+	begin
+		assert(!S_AXI_AWREADY);
+		if (S_AXI_BVALID)
+			assert(f_axi_wr_pending == 0);
+		if (!o_write_fault && M_AXI_AWVALID)
+			assert(f_axi_wr_pending == M_AXI_AWLEN + 1
+					- (M_AXI_WVALID ? 1:0)
+					- (r_wvalid ? 1 : 0));
+		if (!o_write_fault && f_axi_wr_pending > 0)
+			assert((!M_AXI_WVALID || !M_AXI_WLAST)
+					&&(!r_wvalid || !r_wlast));
+		if (!o_write_fault && M_AXI_WVALID && M_AXI_WLAST)
+			assert(!r_wvalid || !r_wlast);
+	end else begin
+		assert(s_wbursts == 0);
+		assert(!S_AXI_WREADY);
+		if (OPT_SELF_RESET)
+			assert(1 || S_AXI_AWREADY || !M_AXI_ARESETN || !S_AXI_ARESETN);
+		else
+			assert(S_AXI_AWREADY);
+	end
+
+	//
+	// ...
+	//
+
+	//
+	// AWREADY will always be low mid-burst
+	always @(posedge S_AXI_ACLK)
+	if (!f_past_valid || $past(!S_AXI_ARESETN))
+		assert(S_AXI_AWREADY == !OPT_SELF_RESET);
+	else if (f_axi_wr_pending > 0)
+		assert(!S_AXI_AWREADY);
+	else if (s_wbursts)
+		assert(!S_AXI_AWREADY);
+	else if (!OPT_SELF_RESET)
+		assert(S_AXI_AWREADY);
+	else if (!o_write_fault && !o_read_fault)
+		assert(S_AXI_AWREADY || OPT_SELF_RESET);
+
+	always @(*)
+	if (f_axi_wr_pending > 0)
+		assert(s_wbursts == 0);
+	else if (f_axi_awr_nbursts > 0)
+		assert(s_wbursts == f_axi_awr_nbursts);
+	else
+		assert(s_wbursts == 0);
+
+	always @(*)
+	if (!o_write_fault && S_AXI_AWREADY)
+		assert(!M_AXI_AWVALID);
+
+	always @(*)
+	if (M_AXI_ARESETN && (f_axi_awr_nbursts == 0))
+	begin
+		assert(o_write_fault || !M_AXI_AWVALID);
+		assert(!S_AXI_BVALID);
+		assert(s_wbursts == 0);
+	end else if (M_AXI_ARESETN && s_wbursts == 0)
+		assert(f_axi_wr_pending > 0);
+
+	always @(*)
+	if (S_AXI_WREADY)
+		assert(waddr_valid);
+	else if (f_axi_wr_pending > 0)
+	begin
+		if (!o_write_fault)
+			assert(M_AXI_WVALID && r_wvalid);
+	end
+
+	always @(*)
+	if (!OPT_SELF_RESET)
+		assert(waddr_valid == !S_AXI_AWREADY);
+	else begin
+		// ...
+		assert(waddr_valid == (f_axi_awr_nbursts > 0));
+	end
+
+	always @(*)
+	if (S_AXI_ARESETN && !o_write_fault && f_axi_wr_pending && !S_AXI_WREADY)
+		assert(M_AXI_WVALID);
+
+	always @(*)
+	if (S_AXI_ARESETN && !o_write_fault && m_wempty)
+	begin
+		assert(M_AXI_AWVALID || !M_AXI_WVALID);
+		assert(M_AXI_AWVALID || f_axi_wr_pending == 0);
+	end
+
+	always @(*)
+	if (S_AXI_ARESETN && M_AXI_AWVALID)
+	begin
+		if (!o_write_fault && !M_AXI_AWVALID)
+			assert(f_axi_wr_pending + (M_AXI_WVALID ? 1:0) + (r_wvalid ? 1:0) == m_wpending);
+		else if (!o_write_fault)
+		begin
+			assert(f_axi_wr_pending == M_AXI_AWLEN + 1 - (M_AXI_WVALID ? 1:0) - (r_wvalid ? 1:0));
+			assert(m_wpending == 0);
+		end
+	end
+
+	always @(*)
+		assert(m_wpending <= 9'h100);
+
+	always @(*)
+	if (M_AXI_ARESETN && (!o_write_fault)&&(f_axi_awr_nbursts == 0))
+		assert(!M_AXI_AWVALID);
+
+	always @(*)
+	if (S_AXI_ARESETN && !o_write_fault)
+	begin
+		if (f_axi_awr_nbursts == 0)
+		begin
+			assert(!M_AXI_AWVALID);
+			assert(!M_AXI_WVALID);
+		end
+
+		if (!M_AXI_AWVALID)
+			assert(f_axi_wr_pending 
+					+(M_AXI_WVALID ? 1:0)
+					+ (r_wvalid ? 1:0)
+				== m_wpending);
+		if (f_axi_awr_nbursts == (S_AXI_BVALID ? 1:0))
+		begin
+			assert(!M_AXI_AWVALID);
+			assert(!M_AXI_WVALID);
+		end
+
+		if (S_AXI_BVALID)
+			assert(f_axi_awr_nbursts == 1);
+
+		if (M_AXI_AWVALID)
+			assert(m_wpending == 0);
+
+		if (S_AXI_AWREADY)
+			assert(!M_AXI_AWVALID);
+	end
+
+	always @(*)
+		assert(!r_awvalid);
+
+	always @(*)
+		assert(m_wempty == (m_wpending == 0));
+	always @(*)
+		assert(m_wlastctr == (m_wpending == 1));
+
+	//
+	// Verify the contents of the skid buffers
+	//
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (write_timer > OPT_TIMEOUT)
+		assert(o_write_fault || write_timeout);
+
+	always @(*)
+	if (!OPT_SELF_RESET)
+		assert(waddr_valid == !S_AXI_AWREADY);
+	else if (waddr_valid)
+		assert(!S_AXI_AWREADY);
+
+	always @(*)
+	if (!o_write_fault && M_AXI_ARESETN)
+		assert(waddr_valid == !S_AXI_AWREADY);
+
+	always @(*)
+	if (f_axi_wr_pending == 0)
+		assert(!S_AXI_WREADY);
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read induction properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	//
+
+	always @(*)
+		assert(f_axi_rd_nbursts <= 1);
+	always @(*)
+		assert(raddr_valid == (f_axi_rd_nbursts>0));
+	always @(*)
+	if (f_axi_rdid_nbursts > 0)
+		assert(rfifo_id == f_axi_rd_checkid);
+	else if (f_axi_rd_nbursts > 0)
+		assert(rfifo_id != f_axi_rd_checkid);
+
+	always @(*)
+	if (f_axi_rd_nbursts > 0)
+		assert(raddr_valid);
+
+	always @(*)
+	if (raddr_valid)
+		assert(!S_AXI_ARREADY);
+
+	always @(*)
+	if (!OPT_SELF_RESET)
+		assert(raddr_valid == !S_AXI_ARREADY);
+	else begin
+		// ...
+		assert(raddr_valid == (f_axi_rd_nbursts > 0));
+	end
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (f_axi_rd_outstanding == 0)
+		assert(!raddr_valid || OPT_SELF_RESET);
+
+	always @(*)
+	if (!o_read_fault && S_AXI_ARREADY)
+		assert(!M_AXI_ARVALID);
+
+	// Our "FIFO" counter
+	always @(*)
+		assert(rfifo_counter == f_axi_rd_outstanding);
+
+	always @(*)
+	begin
+		assert(rfifo_empty       == (rfifo_counter == 0));
+		assert(rfifo_last        == (rfifo_counter == 1));
+		assert(rfifo_penultimate == (rfifo_counter == 2));
+	end
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (r_arvalid)
+		assert(skid_arvalid);
+
+	always @(*)
+	if (read_timer > OPT_TIMEOUT)
+		assert(read_timeout);
+
+
+	always @(posedge S_AXI_ACLK)
+	if (OPT_SELF_RESET && (!f_past_valid || !$past(M_AXI_ARESETN)))
+	begin
+		assume(!M_AXI_BVALID);
+		assume(!M_AXI_RVALID);
+	end
+
+	always @(*)
+	if (!o_read_fault && M_AXI_ARESETN)
+		assert(raddr_valid == !S_AXI_ARREADY);
+
+	always @(*)
+	if (f_axi_rd_nbursts > 0)
+		assert(raddr_valid);
+
+	always @(*)
+	if (S_AXI_ARESETN && OPT_SELF_RESET)
+	begin
+		if (!M_AXI_ARESETN)
+			assert(o_read_fault || o_write_fault /* ... */ );
+	end
+	// }}}
+
+
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Good interface check
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate if (F_OPT_FAULTLESS)
+	begin
+		//
+		// ...
+		//
+
+		faxi_master	#(
+			// {{{
+			.C_AXI_ID_WIDTH(C_S_AXI_ID_WIDTH),
+			.C_AXI_DATA_WIDTH(C_S_AXI_DATA_WIDTH),
+			.C_AXI_ADDR_WIDTH(C_S_AXI_ADDR_WIDTH))
+			// ...
+			// }}}
+		f_master(
+		.i_clk(S_AXI_ACLK),
+		.i_axi_reset_n(M_AXI_ARESETN),
+		// {{{
+		//
+		// Address write channel
+		//
+		.i_axi_awid(M_AXI_AWID),
+		.i_axi_awaddr(M_AXI_AWADDR),
+		.i_axi_awlen(M_AXI_AWLEN),
+		.i_axi_awsize(M_AXI_AWSIZE),
+		.i_axi_awburst(M_AXI_AWBURST),
+		.i_axi_awlock(M_AXI_AWLOCK),
+		.i_axi_awcache(M_AXI_AWCACHE),
+		.i_axi_awprot(M_AXI_AWPROT),
+		.i_axi_awqos(M_AXI_AWQOS),
+		.i_axi_awvalid(M_AXI_AWVALID),
+		.i_axi_awready(M_AXI_AWREADY),
+	//
+	//
+		//
+		// Write Data Channel
+		//
+		// Write Data
+		.i_axi_wdata(M_AXI_WDATA),
+		.i_axi_wstrb(M_AXI_WSTRB),
+		.i_axi_wlast(M_AXI_WLAST),
+		.i_axi_wvalid(M_AXI_WVALID),
+		.i_axi_wready(M_AXI_WREADY),
+	//
+	//
+		// Response ID tag. This signal is the ID tag of the
+		// write response.
+		.i_axi_bid(M_AXI_BID),
+		.i_axi_bresp(M_AXI_BRESP),
+		.i_axi_bvalid(M_AXI_BVALID),
+		.i_axi_bready(M_AXI_BREADY),
+	//
+	//
+		//
+		// Read address channel
+		//
+		.i_axi_arid(M_AXI_ARID),
+		.i_axi_araddr(M_AXI_ARADDR),
+		.i_axi_arlen(M_AXI_ARLEN),
+		.i_axi_arsize(M_AXI_ARSIZE),
+		.i_axi_arburst(M_AXI_ARBURST),
+		.i_axi_arlock(M_AXI_ARLOCK),
+		.i_axi_arcache(M_AXI_ARCACHE),
+		.i_axi_arprot(M_AXI_ARPROT),
+		.i_axi_arqos(M_AXI_ARQOS),
+		.i_axi_arvalid(M_AXI_ARVALID),
+		.i_axi_arready(M_AXI_ARREADY),
+	//
+	//
+		//
+		// Read data return channel
+		//
+		.i_axi_rid(M_AXI_RID),
+		.i_axi_rdata(M_AXI_RDATA),
+		.i_axi_rresp(M_AXI_RRESP),
+		.i_axi_rlast(M_AXI_RLAST),
+		.i_axi_rvalid(M_AXI_RVALID),
+		.i_axi_rready(M_AXI_RREADY),
+		//
+		// Formal outputs
+		//
+		.f_axi_awr_nbursts(fm_axi_awr_nbursts),
+		.f_axi_wr_pending(fm_axi_wr_pending),
+		.f_axi_rd_nbursts(fm_axi_rd_nbursts),
+		.f_axi_rd_outstanding(fm_axi_rd_outstanding)
+		//
+		// ...
+		//
+		// }}}
+		);
+
+		// {{{
+		always @(*)
+		if (OPT_SELF_RESET)
+			assert(!o_write_fault || !M_AXI_ARESETN);
+		else
+			assert(!o_write_fault);
+
+		always @(*)
+		if (OPT_SELF_RESET)
+			assert(!o_read_fault || !M_AXI_ARESETN);
+		else
+			assert(!o_read_fault);
+
+		always @(*)
+		if (OPT_SELF_RESET)
+			assert(!read_timeout || !M_AXI_ARESETN);
+		else
+			assert(!read_timeout);
+
+		always @(*)
+		if (OPT_SELF_RESET)
+			assert(!write_timeout || !M_AXI_ARESETN);
+		else
+			assert(!write_timeout);
+
+		always @(*)
+		if (S_AXI_AWREADY)
+			assert(!M_AXI_AWVALID);
+
+		//
+		// ...
+		//
+
+		always @(*)
+		if (M_AXI_ARESETN && f_axi_rd_nbursts > 0)
+			assert(f_axi_rd_nbursts == fm_axi_rd_nbursts
+				+ (M_AXI_ARVALID ? 1 : 0)
+				+ (r_rvalid&&m_rlast ? 1 : 0)
+				+ (S_AXI_RVALID&&S_AXI_RLAST ? 1 : 0));
+
+		always @(*)
+		if (M_AXI_ARESETN && f_axi_rd_outstanding > 0)
+			assert(f_axi_rd_outstanding == fm_axi_rd_outstanding
+				+ (M_AXI_ARVALID ? M_AXI_ARLEN+1 : 0)
+				+ (r_rvalid ? 1 : 0)
+				+ (S_AXI_RVALID ? 1 : 0));
+
+		//
+		// ...
+		//
+		always @(*)
+		if (M_AXI_RVALID)
+			assert(!M_AXI_ARVALID);
+
+		always @(*)
+		if (S_AXI_ARESETN)
+			assert(m_wpending == fm_axi_wr_pending);
+
+		always @(*)
+		if (S_AXI_ARESETN && fm_axi_awr_nbursts > 0)
+		begin
+			assert(fm_axi_awr_nbursts== f_axi_awr_nbursts);
+			assert(fm_axi_awr_nbursts == 1);
+			//
+			// ...
+			//
+		end
+
+		//
+		// ...
+		//
+
+	end endgenerate
+
+	//
+	// ...
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Never path check
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	(* anyconst *) reg [C_S_AXI_ADDR_WIDTH-1:0]	fc_never_write_addr,
+							fc_never_read_addr;
+	(* anyconst *) reg [C_S_AXI_DATA_WIDTH + C_S_AXI_DATA_WIDTH/8-1:0]
+							fc_never_write_data;
+	(* anyconst *) reg [C_S_AXI_DATA_WIDTH-1:0]	fc_never_read_data;
+
+	// Write address
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARESETN && S_AXI_AWVALID)
+		assume(S_AXI_AWADDR != fc_never_write_addr);
+
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARESETN && !o_write_fault && M_AXI_ARESETN && M_AXI_AWVALID)
+		assert(M_AXI_AWADDR != fc_never_write_addr);
+	// }}}
+
+	// Write data
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARESETN && S_AXI_WVALID)
+		assume({ S_AXI_WDATA, S_AXI_WSTRB } != fc_never_write_data);
+
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARESETN && !o_write_fault && M_AXI_ARESETN && M_AXI_WVALID)
+		assert({ M_AXI_WDATA, M_AXI_WSTRB } != fc_never_write_data);
+	// }}}
+
+	// Read address
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARESETN && S_AXI_ARVALID)
+		assume(S_AXI_ARADDR != fc_never_read_addr);
+
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARESETN && r_arvalid)
+		assume(r_araddr != fc_never_read_addr);
+
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARESETN && !o_read_fault && M_AXI_ARESETN && M_AXI_ARVALID)
+		assert(M_AXI_ARADDR != fc_never_read_addr);
+	// }}}
+
+	// Read data
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARESETN && M_AXI_ARESETN && M_AXI_RVALID)
+		assume(M_AXI_RDATA != fc_never_read_data);
+
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARESETN && S_AXI_RVALID && S_AXI_RRESP != SLAVE_ERROR)
+		assert(S_AXI_RDATA != fc_never_read_data);
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	// We'll use these to determine the best performance this core
+	// can achieve
+	//
+	reg	[4:0]	f_dbl_rd_count, f_dbl_wr_count;
+
+	initial	f_dbl_wr_count = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || o_write_fault)
+		f_dbl_wr_count = 0;
+	else if (S_AXI_AWVALID && S_AXI_AWREADY && S_AXI_AWLEN == 3)
+	begin
+		if (!(&f_dbl_wr_count))
+			f_dbl_wr_count <= f_dbl_wr_count + 1;
+	end
+
+	always @(*)
+		cover(!S_AXI_ARESETN && (f_dbl_wr_count > 3)
+			&& (!o_write_fault)
+			&&(!S_AXI_AWVALID && !S_AXI_WVALID
+					&& !S_AXI_BVALID)
+			&& (f_axi_awr_nbursts == 0)
+			&& (f_axi_wr_pending == 0));
+
+	always @(*)
+		cover(!S_AXI_ARESETN && (f_dbl_wr_count > 1)
+			&& (!o_write_fault)
+			);
+
+	always @(*)
+		cover(S_AXI_AWVALID && S_AXI_AWREADY);
+
+	always @(*)
+		cover(S_AXI_AWVALID && S_AXI_AWREADY && S_AXI_AWLEN == 3);
+
+	initial	f_dbl_rd_count = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || o_read_fault)
+		f_dbl_rd_count = 0;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY && S_AXI_ARLEN == 3)
+	begin
+		if (!(&f_dbl_rd_count))
+			f_dbl_rd_count <= f_dbl_rd_count + 1;
+	end
+
+	always @(*)
+		cover(!S_AXI_ARESETN && (f_dbl_rd_count > 3)
+			&& (f_axi_rd_nbursts == 0)
+			&& !S_AXI_ARVALID && !S_AXI_RVALID);
+	// }}}
+`endif
+// }}}
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axisgdma.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axisgdma.v
new file mode 100644
index 0000000..87601fe
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axisgdma.v
@@ -0,0 +1,1087 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axisgdma.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Scripts an AXI DMA via in-memory tables: reads from the tables,
+//		commands the DMA.
+//
+// Registers:
+//
+//	0. Control
+//		8b	KEY
+//			3'b PROT
+//			4'b QOS
+//		1b	Abort: Either aborting or aborted
+//		1b	Err: Ended on an error
+//		1b	Busy
+//		1b	Interrupt Enable
+//		1b	Interrupt Set
+//		1b	Start
+//	1. Reserved
+//	2-3. First table entry address
+//		(Current) table entry address on read, if in progress
+// (Optional)
+//	4-5. Current read address
+//	6-7. Current write address
+//	1.   Remaining amount to be written (this entry)
+//
+// Table entries (must be 32-bit aligned):
+//	If (address_width > 30)
+//		64b: { 2'bflags, 62'b SOURCE ADDRESS (bytes) }
+//			00: Continue after this to next
+//			01: Skip this address
+//			10: Jump to new address
+//			11: Last item in chain
+//		64b: { int_en, 1'b0,  DESTINATION ADDRESS (bytes) }
+//		32b LENGTH (in bytes)
+//	else
+//		32b: { 2'bflags, 30'b SOURCE ADDRESS (bytes) }
+//		32b: { int_en, 1'b0, 30'b DESTINATION ADDRESS (bytes) }
+//		32b LENGTH (in bytes)
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// `define			AXI3
+// }}}
+module	axisgdma #(
+		// {{{
+		parameter	C_AXI_ID_WIDTH = 1,
+		parameter	C_AXI_ADDR_WIDTH = 32,
+		parameter	C_AXI_DATA_WIDTH = 64,
+		//
+		localparam	C_AXIL_ADDR_WIDTH = 4,
+		localparam	C_AXIL_DATA_WIDTH = 32,
+		//
+		// OPT_UNALIGNED turns on support for unaligned addresses,
+		// whether source, destination, or length parameters.
+		parameter [0:0]	OPT_UNALIGNED = 1'b1,
+		//
+		// OPT_WRAPMEM controls what happens if the transfer runs off
+		// of the end of memory.  If set, the transfer will continue
+		// again from the beginning of memory.  If clear, the transfer
+		// will be aborted with an error if either read or write
+		// address ever get this far.
+		parameter [0:0]	OPT_WRAPMEM = 1'b1,
+		//
+		// LGMAXBURST controls the size of the maximum burst produced
+		// by this core.  Specifically, its the log (based 2) of that
+		// maximum size.  Hence, for AXI4, this size must be 8
+		// (i.e. 2^8 or 256 beats) or less.  For AXI3, the size must
+		// be 4 or less.  Tests have verified performance for
+		// LGMAXBURST as low as 2.  While I expect it to fail at
+		// LGMAXBURST=0, I haven't verified at what value this burst
+		// parameter is too small.
+`ifdef	AXI3
+		parameter	LGMAXBURST=4,	// 16 beats max
+`else
+		parameter	LGMAXBURST=8,	// 256 beats
+`endif
+		// The number of beats in this maximum burst size is
+		// automatically determined from LGMAXBURST, and so its
+		// forced to be a power of two this way.
+		localparam	MAXBURST=(1<<LGMAXBURST),
+		//
+		// LGFIFO: This is the (log-based-2) size of the internal FIFO.
+		// Hence if LGFIFO=8, the internal FIFO will have 256 elements
+		// (words) in it.  High throughput transfers are accomplished
+		// by first storing data into a FIFO, then once a full burst
+		// size is available bursting that data over the bus.  In
+		// order to be able to keep receiving data while bursting it
+		// out, the FIFO size must be at least twice the size of the
+		// maximum burst size.  Larger sizes are possible as well.
+		parameter	LGFIFO = LGMAXBURST+1,	// 512 element FIFO
+		//
+		// LGLEN: specifies the number of bits in the transfer length
+		// register.  If a transfer cannot be specified in LGLEN bits,
+		// it won't happen.  LGLEN must be less than or equal to the
+		// address width.
+		parameter	LGLEN = C_AXI_ADDR_WIDTH,
+		//
+		// AXI uses ID's to transfer information.  This core rather
+		// ignores them.  Instead, it uses a constant ID for all
+		// transfers.  The following two parameters control that ID.
+		parameter	[C_AXI_ID_WIDTH-1:0]	DMA_READ_ID = 0,
+		parameter	[C_AXI_ID_WIDTH-1:0]	DMA_WRITE_ID = 0,
+		parameter	[C_AXI_ID_WIDTH-1:0] PF_READ_ID = DMA_READ_ID+1,
+		//
+		// The "ABORT_KEY" is a byte that, if written to the control
+		// word while the core is running, will cause the data transfer
+		// to be aborted.
+		parameter	[7:0]			ABORT_KEY  = 8'h6d,
+		//
+		// OPT_LOWPOWER
+		parameter	[0:0]			OPT_LOWPOWER = 1'b0,
+		//
+		localparam	ADDRLSB= $clog2(C_AXI_DATA_WIDTH)-3,
+		localparam	AXILLSB= $clog2(C_AXIL_DATA_WIDTH)-3,
+		localparam	LGLENW= LGLEN-ADDRLSB
+		// }}}
+	) (
+		// {{{
+		input	wire	S_AXI_ACLK,
+		input	wire	S_AXI_ARESETN,
+		//
+		// The AXI4-lite control interface
+		input	wire				S_AXIL_AWVALID,
+		output	wire				S_AXIL_AWREADY,
+		input	wire [C_AXIL_ADDR_WIDTH-1:0]	S_AXIL_AWADDR,
+		input	wire 	[2:0]			S_AXIL_AWPROT,
+		//
+		input	wire				S_AXIL_WVALID,
+		output	wire				S_AXIL_WREADY,
+		input	wire [C_AXIL_DATA_WIDTH-1:0]	S_AXIL_WDATA,
+		input	wire [C_AXIL_DATA_WIDTH/8-1:0]	S_AXIL_WSTRB,
+		//
+		output	reg				S_AXIL_BVALID,
+		input	wire				S_AXIL_BREADY,
+		output	reg	[1:0]			S_AXIL_BRESP,
+		//
+		input	wire				S_AXIL_ARVALID,
+		output	wire				S_AXIL_ARREADY,
+		input	wire [C_AXIL_ADDR_WIDTH-1:0]	S_AXIL_ARADDR,
+		input	wire 	[2:0]			S_AXIL_ARPROT,
+		//
+		output	reg				S_AXIL_RVALID,
+		input	wire				S_AXIL_RREADY,
+		output	reg [C_AXIL_DATA_WIDTH-1:0]	S_AXIL_RDATA,
+		output	reg	[1:0]			S_AXIL_RRESP,
+		//
+		//
+		// The AXI Master (DMA) interface
+		output	wire				M_AXI_AWVALID,
+		input	wire				M_AXI_AWREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_AWID,
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_AWADDR,
+`ifdef	AXI3
+		output	wire	[3:0]			M_AXI_AWLEN,
+`else
+		output	wire	[7:0]			M_AXI_AWLEN,
+`endif
+		output	wire	[2:0]			M_AXI_AWSIZE,
+		output	wire	[1:0]			M_AXI_AWBURST,
+		output	wire				M_AXI_AWLOCK,
+		output	wire	[3:0]			M_AXI_AWCACHE,
+		output	wire	[2:0]			M_AXI_AWPROT,
+		output	wire	[3:0]			M_AXI_AWQOS,
+		//
+		//
+		output	wire				M_AXI_WVALID,
+		input	wire				M_AXI_WREADY,
+`ifdef	AXI3
+		output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_WID,
+`endif
+		output	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_WDATA,
+		output	wire [C_AXI_DATA_WIDTH/8-1:0]	M_AXI_WSTRB,
+		output	wire				M_AXI_WLAST,
+		//
+		//
+		input	wire				M_AXI_BVALID,
+		output	reg				M_AXI_BREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_BID,
+		input	wire	[1:0]			M_AXI_BRESP,
+		//
+		//
+		output	wire				M_AXI_ARVALID,
+		input	wire				M_AXI_ARREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_ARID,
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_ARADDR,
+`ifdef	AXI3
+		output	wire	[3:0]			M_AXI_ARLEN,
+`else
+		output	wire	[7:0]			M_AXI_ARLEN,
+`endif
+		output	wire	[2:0]			M_AXI_ARSIZE,
+		output	wire	[1:0]			M_AXI_ARBURST,
+		output	wire				M_AXI_ARLOCK,
+		output	wire	[3:0]			M_AXI_ARCACHE,
+		output	wire	[2:0]			M_AXI_ARPROT,
+		output	wire	[3:0]			M_AXI_ARQOS,
+		//
+		input	wire				M_AXI_RVALID,
+		output	reg				M_AXI_RREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_RID,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_RDATA,
+		input	wire				M_AXI_RLAST,
+		input	wire	[1:0]			M_AXI_RRESP,
+		//
+		output	reg				o_int
+		// }}}
+	);
+
+	// Local parameter definitions
+	// {{{
+	localparam	[1:0]	CTRL_ADDR   = 2'b00,
+				UNUSED_ADDR = 2'b01,
+				TBLLO_ADDR  = 2'b10,
+				TBLHI_ADDR  = 2'b11;
+	localparam		CTRL_START_BIT = 0,
+				CTRL_BUSY_BIT  = 0,
+				CTRL_INT_BIT   = 1,
+				CTRL_INTEN_BIT = 2,
+				CTRL_ABORT_BIT = 3,
+				CTRL_ERR_BIT   = 4,
+				CTRL_INTERIM_BIT= 5;
+	localparam	[1:0]	AXI_INCR = 2'b01, AXI_OKAY = 2'b00;
+
+`ifdef	AXI3
+	localparam	LENWIDTH = 4;
+`else
+	localparam	LENWIDTH = 8;
+`endif
+
+	// DMA device internal addresses
+	// {{{
+	localparam [4:0]	DMA_CONTROL= 5'b00000;
+	// }}}
+
+	localparam [C_AXI_ADDR_WIDTH-1:0] TBL_SIZE
+				= (C_AXI_ADDR_WIDTH < 30) ? (4*5) : (4*7);
+
+	// }}}
+
+	// Register/net declarations
+	// {{{
+	reg				axil_write_ready, axil_read_ready;
+	reg	[2*C_AXIL_DATA_WIDTH-1:0] wide_tbl, new_widetbl;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	tbl_addr, r_tbl_addr;
+	reg				r_int_enable, r_int, r_err, r_abort;
+	wire				w_int, fsm_err;
+
+	reg	[3:0]		r_qos;
+	reg	[2:0]		r_prot;
+	reg			r_start;
+	wire			r_done, r_busy;
+
+	wire				awskd_valid;
+	wire	[C_AXIL_ADDR_WIDTH-AXILLSB-1:0]	awskd_addr;
+	wire				wskd_valid;
+	wire	[C_AXIL_DATA_WIDTH-1:0]	wskd_data;
+	wire [C_AXIL_DATA_WIDTH/8-1:0]	wskd_strb;
+
+	wire				arskd_valid;
+	wire	[C_AXIL_ADDR_WIDTH-AXILLSB-1:0]	arskd_addr;
+
+	// Prefetch interface registers
+	// {{{
+	wire				new_pc, pf_ready, pf_clear_cache;
+	wire	[C_AXI_ADDR_WIDTH-1:0]	ipc;
+	wire	[31:0]			pf_insn;
+	wire				pf_valid, pf_illegal;
+	wire				pf_axi_arvalid;
+	reg				pf_axi_arready;
+	wire	[C_AXI_ADDR_WIDTH-1:0]	pf_axi_araddr, pf_pc;
+	wire	[2:0]			pf_axi_arprot;
+	wire				pf_axi_rready_ignored;
+	wire	[C_AXI_ID_WIDTH-1:0]	pf_axi_arid;
+	wire	[7:0]			pf_axi_arlen;
+	wire	[2:0]			pf_axi_arsize;
+	wire	[1:0]			pf_axi_arburst;
+	wire	[3:0]			pf_axi_arcache;
+	wire	[2:0]			pf_axi_arprot;
+	wire	[3:0]			pf_axi_arqos;
+	// }}}
+
+	// DMA control registers/AXI-lite interface
+	// {{{
+	wire		dmac_awready_ignored;
+	reg	[4:0]	dmac_waddr;
+	//
+	reg		dmac_wvalid;
+	wire		dmac_wready;
+	reg	[31:0]	dmac_wdata;
+	reg	[3:0]	dmac_wstrb;
+	//
+	wire		dmac_bvalid;
+	wire	[1:0]	dmac_bresp;
+	//
+	wire		dmac_arready;
+	wire		dmac_rvalid;
+	wire	[31:0]	dmac_rdata;
+	wire	[1:0]	dmac_rresp;
+	// }}}
+
+	// DMA AXI nets
+	// {{{
+	wire				sdma_arvalid;
+	wire	[C_AXI_ID_WIDTH-1:0]	sdma_arid;
+	wire	[C_AXI_ADDR_WIDTH-1:0]	sdma_araddr;
+	wire	[7:0]			sdma_arlen;
+	wire	[2:0]			sdma_arsize;
+	wire	[1:0]			sdma_arburst;
+	wire	[0:0]			sdma_arlock;
+	wire	[3:0]			sdma_arcache;
+	wire	[2:0]			sdma_arprot;
+	wire	[3:0]			sdma_arqos;
+	reg				sdma_arready;
+	wire				sdma_rready_ignored;
+	wire				dma_complete;
+	// }}}
+
+	// Combined AXI nets
+	// {{{
+	reg				m_axi_arvalid;
+	reg	[C_AXI_ID_WIDTH-1:0]	m_axi_arid;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	m_axi_araddr;
+	reg	[7:0]			m_axi_arlen;
+	reg	[2:0]			m_axi_arsize;
+	reg	[1:0]			m_axi_arburst;
+	reg	[3:0]			m_axi_arcache;
+	reg	[2:0]			m_axi_arprot;
+	reg	[3:0]			m_axi_arqos;
+	// }}}
+
+	reg	pf_wins_arbitration;
+	wire	m_axi_arready;
+
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-Lite control interface
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write control logic
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// axil AW skid buffer
+	// {{{
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_ADDR_WIDTH-AXILLSB))
+	axilawskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_valid(S_AXIL_AWVALID), .o_ready(S_AXIL_AWREADY),
+		.i_data(S_AXIL_AWADDR[C_AXIL_ADDR_WIDTH-1:AXILLSB]),
+		.o_valid(awskd_valid), .i_ready(axil_write_ready),
+		.o_data(awskd_addr));
+	// }}}
+
+	// axil W skid buffer
+	// {{{
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_DATA_WIDTH+C_AXIL_DATA_WIDTH/8))
+	axilwskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_valid(S_AXIL_WVALID), .o_ready(S_AXIL_WREADY),
+		.i_data({ S_AXIL_WSTRB, S_AXIL_WDATA }),
+		.o_valid(wskd_valid), .i_ready(axil_write_ready),
+		.o_data({ wskd_strb, wskd_data }));
+	// }}}
+
+	// axil_write_ready
+	// {{{
+	always  @(*)
+	begin
+		axil_write_ready = !S_AXIL_BVALID || S_AXIL_BREADY;;
+		if (!awskd_valid || !wskd_valid)
+			axil_write_ready = 0;
+	end
+	// }}}
+
+	// S_AXIL_BVALID
+	// {{{
+	initial	S_AXIL_BVALID = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		S_AXIL_BVALID <= 1'b0;
+	else if (!S_AXIL_BVALID || S_AXIL_BREADY)
+		S_AXIL_BVALID <= axil_write_ready;
+	// }}}
+
+	// S_AXIL_BRESP
+	// {{{
+	always @(*)
+		S_AXIL_BRESP = AXI_OKAY;
+	// }}}
+
+	// r_start
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		r_start <= 1'b0;
+	else begin
+		r_start <= !r_busy && axil_write_ready && wskd_strb[0]
+				&& wskd_data[CTRL_START_BIT]
+				&& (awskd_addr == CTRL_ADDR);
+		if (r_err && !wskd_data[CTRL_ERR_BIT])
+			r_start <= 0;
+		if (r_abort && !wskd_data[CTRL_ABORT_BIT])
+			r_start <= 0;
+	end
+	// }}}
+
+	// r_err
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		r_err <= 1'b0;
+	else if (!r_busy)
+	begin
+		if (axil_write_ready)
+			r_err <= (r_err) && (!wskd_strb[0]
+						|| !wskd_data[CTRL_ERR_BIT]);
+	end else begin
+		r_err <= r_err || fsm_err;
+	end
+	// }}}
+
+	// o_int
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || !r_int_enable || !r_busy)
+		o_int <= 0;
+	else if (w_int)
+		o_int <= 1'b1;
+	// }}}
+
+	// r_int
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		r_int <= 0;
+	else if (!r_busy)
+	begin
+		if (axil_write_ready && awskd_addr == CTRL_ADDR
+			&& wskd_strb[0])
+		begin
+			if (wskd_data[CTRL_START_BIT])
+				r_int <= 0;
+			else if (wskd_data[CTRL_INT_BIT])
+				r_int <= 0;
+		end
+	end else if (w_int)
+		r_int <= 1'b1;
+	// }}}
+
+	// r_abort
+	// {{{
+	initial	r_abort = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		r_abort <= 1'b0;
+	else if (!r_busy)
+	begin
+		if (axil_write_ready && awskd_addr == CTRL_ADDR && wskd_strb[0])
+		begin
+			if(wskd_data[CTRL_START_BIT]
+				||wskd_data[CTRL_ABORT_BIT]
+				||wskd_data[CTRL_ERR_BIT])
+			r_abort <= 0;
+		end
+	end else if (!r_abort)
+		r_abort <= (axil_write_ready && awskd_addr == CTRL_ADDR)
+			&&(wskd_strb[3] && wskd_data[31:24] == ABORT_KEY);
+	// }}}
+
+	// wide_tbl, new_widetbl
+	// {{{
+	always @(*)
+	begin
+		wide_tbl = 0;
+		wide_tbl[C_AXI_ADDR_WIDTH-1:0] = r_tbl_addr;
+
+		new_widetbl = wide_tbl;
+		if (awskd_addr == TBLLO_ADDR)
+			new_widetbl[31:0] = apply_wstrb(wide_tbl[31:0],
+							wskd_data, wskd_strb);
+		if (awskd_addr == TBLHI_ADDR)
+			new_widetbl[63:32] = apply_wstrb(wide_tbl[63:32],
+					wskd_data, wskd_strb);
+	end
+	// }}}
+
+	// r_prot, r_qos, r_int_enable, r_tbl_addr
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		r_prot <= 0;
+		r_qos  <= 0;
+		r_int_enable <= 0;
+	end else if (!r_busy && axil_write_ready)
+	begin
+		case(awskd_addr)
+		CTRL_ADDR: begin
+				if (wskd_strb[2])
+				begin
+					r_prot <= wskd_data[22:20];
+					r_qos  <= wskd_data[19:16];
+				end
+			if (wskd_strb[0])
+			begin
+				r_int_enable <= wskd_data[CTRL_INTEN_BIT];
+			end end
+		TBLLO_ADDR: begin
+			r_tbl_addr <= new_widetbl[C_AXI_ADDR_WIDTH-1:0];
+			end
+		TBLHI_ADDR: if (C_AXI_ADDR_WIDTH > C_AXIL_DATA_WIDTH) begin
+			r_tbl_addr <= new_widetbl[C_AXI_ADDR_WIDTH-1:0];
+			end
+		default: begin end
+		endcase
+	end else if (r_busy)
+	begin
+		r_tbl_addr <= tbl_addr;
+	end
+	// }}}
+
+	// apply_wstrb function
+	// {{{
+	function [C_AXIL_DATA_WIDTH-1:0]	apply_wstrb;
+		input [C_AXIL_DATA_WIDTH-1:0]	prior_data;
+		input [C_AXIL_DATA_WIDTH-1:0]	new_data;
+		input [C_AXIL_DATA_WIDTH/8-1:0]	wstrb;
+
+		integer	k;
+		for(k=0; k<C_AXIL_DATA_WIDTH/8; k=k+1)
+		begin
+			apply_wstrb[k*8 +: 8] = wstrb[k] ? new_data[k*8 +: 8]
+				: prior_data[k*8 +: 8];
+		end
+	endfunction
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite control read interface
+	// {{{
+
+	// AXI-lite AR skid buffer
+	// {{{
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_ADDR_WIDTH-AXILLSB))
+	axilarskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+		.i_valid(S_AXIL_ARVALID), .o_ready(S_AXIL_ARREADY),
+		.i_data(S_AXIL_ARADDR[C_AXIL_ADDR_WIDTH-1:AXILLSB]),
+		.o_valid(arskd_valid), .i_ready(axil_read_ready),
+		.o_data(arskd_addr));
+	// }}}
+
+	// axil_read_ready
+	// {{{
+	always @(*)
+	begin
+		axil_read_ready = !S_AXIL_RVALID || S_AXIL_RREADY;
+		if (!arskd_valid)
+			axil_read_ready = 1'b0;
+	end
+	// }}}
+
+	// S_AXIL_RVALID
+	// {{{
+	initial	S_AXIL_RVALID = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		S_AXIL_RVALID <= 1'b0;
+	else if (!S_AXIL_RVALID || S_AXIL_RREADY)
+		S_AXIL_RVALID <= axil_read_ready;
+	// }}}
+
+	// S_AXIL_RDATA
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (OPT_LOWPOWER && !S_AXI_ARESETN)
+		S_AXIL_RDATA <= 0;
+	else if (!S_AXIL_RVALID || S_AXIL_RREADY)
+	begin
+		S_AXIL_RDATA <= 0;
+		case(arskd_addr)
+		CTRL_ADDR: begin
+			S_AXIL_RDATA[CTRL_ERR_BIT]     <= r_err;
+			S_AXIL_RDATA[CTRL_ABORT_BIT]   <= r_abort;
+			S_AXIL_RDATA[CTRL_INTEN_BIT]   <= r_int_enable;
+			S_AXIL_RDATA[CTRL_INT_BIT]     <= r_int;
+			S_AXIL_RDATA[CTRL_BUSY_BIT]    <= r_busy;
+			end
+		// Unused:
+		TBLLO_ADDR:
+			S_AXIL_RDATA <= wide_tbl[C_AXIL_DATA_WIDTH-1:0];
+		TBLHI_ADDR:
+			S_AXIL_RDATA <= wide_tbl[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+		default: begin end
+		endcase
+
+		if (OPT_LOWPOWER && (!axil_read_ready || !arskd_valid))
+			S_AXIL_RDATA <= 0;
+	end
+	// }}}
+
+	// S_AXIL_RRESP
+	// {{{
+	always @(*)
+		S_AXIL_RRESP = AXI_OKAY;
+	// }}}
+	// }}} // AXI-lite read
+	// }}} // AXI-lite (all)
+	////////////////////////////////////////////////////////////////////////
+	//
+	// DMA control
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// Prefix: dmac for the sub DMA control interface
+	// Prefix: sdma for the sub DMA master  interface
+	axidma #(
+		// {{{
+		.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.OPT_UNALIGNED(OPT_UNALIGNED),
+		.OPT_WRAPMEM(OPT_WRAPMEM),
+		.LGMAXBURST(LGMAXBURST),
+		.LGFIFO(LGFIFO),
+		.LGLEN(LGLEN),
+		.AXI_READ_ID(DMA_READ_ID),
+		.AXI_WRITE_ID(DMA_WRITE_ID),
+		.ABORT_KEY(ABORT_KEY)
+		// }}}
+	) subdma(
+		// {{{
+		.S_AXI_ACLK(S_AXI_ACLK),
+		.S_AXI_ARESETN(S_AXI_ARESETN),
+		//
+		// The AXI4-lite control interface
+		// {{{
+		.S_AXIL_AWVALID(dmac_wvalid), // Merge AW & W channels:DMA ok w/
+		.S_AXIL_AWREADY(dmac_awready_ignored),
+		.S_AXIL_AWADDR( dmac_waddr),
+		.S_AXIL_AWPROT( 3'h0),	// Internally ignored
+		//
+		.S_AXIL_WVALID(dmac_wvalid),
+		.S_AXIL_WREADY(dmac_wready),
+		.S_AXIL_WDATA( dmac_wdata),
+		.S_AXIL_WSTRB( dmac_wstrb),
+		//
+		.S_AXIL_BVALID(dmac_bvalid),
+		.S_AXIL_BREADY(1'b1),
+		.S_AXIL_BRESP( dmac_bresp),
+		//
+		.S_AXIL_ARVALID(!S_AXI_ARESETN),
+		.S_AXIL_ARREADY(dmac_arready),
+		.S_AXIL_ARADDR( DMA_CONTROL),
+		.S_AXIL_ARPROT( 3'h0),	// Internally ignored
+		//
+		.S_AXIL_RVALID(dmac_rvalid),
+		.S_AXIL_RREADY(1'b1),
+		.S_AXIL_RDATA( dmac_rdata),
+		.S_AXIL_RRESP( dmac_rresp),
+		// }}}
+		//
+		// The AXI Master (DMA) interface
+		// {{{
+		.M_AXI_AWVALID(M_AXI_AWVALID),
+		.M_AXI_AWREADY(M_AXI_AWREADY),
+		.M_AXI_AWID(   M_AXI_AWID),
+		.M_AXI_AWADDR( M_AXI_AWADDR),
+		.M_AXI_AWLEN(  M_AXI_AWLEN),
+		.M_AXI_AWSIZE( M_AXI_AWSIZE),
+		.M_AXI_AWBURST(M_AXI_AWBURST),
+		.M_AXI_AWLOCK( M_AXI_AWLOCK),
+		.M_AXI_AWCACHE(M_AXI_AWCACHE),
+		.M_AXI_AWPROT( M_AXI_AWPROT),
+		.M_AXI_AWQOS(  M_AXI_AWQOS),
+		//
+		//
+		.M_AXI_WVALID(M_AXI_WVALID),
+		.M_AXI_WREADY(M_AXI_WREADY),
+`ifdef	AXI3
+		.M_AXI_WID(M_AXI_WID),
+`endif
+		.M_AXI_WDATA(M_AXI_WDATA),
+		.M_AXI_WSTRB(M_AXI_WSTRB),
+		.M_AXI_WLAST(M_AXI_WLAST),
+		//
+		//
+		.M_AXI_BVALID(M_AXI_BVALID),
+		.M_AXI_BREADY(M_AXI_BREADY),
+		.M_AXI_BID(   M_AXI_BID),
+		.M_AXI_BRESP( M_AXI_BRESP),
+		// }}}
+		// AXI master read interface
+		// {{{
+		// The read channel needs to be arbitrated
+		.M_AXI_ARVALID(sdma_arvalid),
+		.M_AXI_ARREADY(sdma_arready),
+		.M_AXI_ARID(sdma_arid),
+		.M_AXI_ARADDR(sdma_araddr),
+		.M_AXI_ARLEN(sdma_arlen),
+		.M_AXI_ARSIZE(sdma_arsize),
+		.M_AXI_ARBURST(sdma_arburst),
+		.M_AXI_ARLOCK(sdma_arlock),
+		.M_AXI_ARCACHE(sdma_arcache),
+		.M_AXI_ARPROT(sdma_arprot),
+		.M_AXI_ARQOS(sdma_arqos),
+		//
+		.M_AXI_RVALID(M_AXI_RVALID && M_AXI_RID == DMA_READ_ID),
+		.M_AXI_RREADY(sdma_rready_ignored),	// Known to be one
+		.M_AXI_RID(  DMA_READ_ID),
+		.M_AXI_RDATA(M_AXI_RDATA),
+		.M_AXI_RLAST(M_AXI_RLAST),
+		.M_AXI_RRESP(M_AXI_RRESP),
+		// }}}
+		.o_int(dma_complete)
+		// }}}
+	);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-Lite prefetch
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// The AXI_lite fetch submodule
+	// {{{
+	axilfetch #(
+		// {{{
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.FETCH_LIMIT(2)
+		// }}}
+	) pf (
+		// {{{
+		.S_AXI_ACLK(S_AXI_ACLK),
+		.S_AXI_ARESETN(S_AXI_ARESETN),
+		//
+		// "CPU" interface
+		// {{{
+		.i_cpu_reset(!S_AXI_ARESETN),
+		.i_new_pc(new_pc),
+		.i_clear_cache(pf_clear_cache),
+		.i_ready(pf_ready),
+		.i_pc(ipc),
+		.o_insn(pf_insn),
+		.o_valid(pf_valid),
+		.o_pc(pf_pc),
+		.o_illegal(pf_illegal),
+		// }}}
+		// AXI-lite interface
+		// {{{
+		.M_AXI_ARVALID(pf_axi_arvalid),
+		.M_AXI_ARREADY(pf_axi_arready),
+		.M_AXI_ARADDR( pf_axi_araddr),
+		.M_AXI_ARPROT( pf_axi_arprot),
+		//
+		.M_AXI_RVALID( M_AXI_RVALID && M_AXI_RID == PF_READ_ID),
+		.M_AXI_RREADY( pf_axi_rready_ignored), // Always 1'b1
+		.M_AXI_RDATA(  M_AXI_RDATA),
+		.M_AXI_RRESP(  M_AXI_RRESP)
+		// }}}
+		// }}}
+	);
+	// }}}
+
+	assign	pf_axi_arid    = PF_READ_ID;
+	assign	pf_axi_arlen   = 8'h0; // Only read singletons
+	assign	pf_axi_arsize  = ADDRLSB[2:0];
+	assign	pf_axi_arburst = 2'b01;
+	assign	pf_axi_arcache = 4'b0011;
+	assign	pf_axi_arprot  = 3'b100;
+	assign	pf_axi_arqos   = 4'h0;
+
+	always @(*)
+		M_AXI_RREADY = 1'b1;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// PF vs DMA arbiter
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	// pf_wins_arbitration
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!m_axi_arvalid || m_axi_arready)
+	begin
+		if (pf_axi_arvalid && !sdma_arvalid)
+			pf_wins_arbitration <= 1'b1;
+		else
+			pf_wins_arbitration <= 1'b0;
+	end
+	// }}}
+
+	// m_axi_*
+	// {{{
+	always @(*)
+	begin
+		if (pf_wins_arbitration)
+		begin
+			m_axi_arvalid = pf_axi_arvalid;
+			m_axi_arid    = pf_axi_arid;
+			m_axi_araddr  = pf_axi_araddr;
+			m_axi_arlen   = pf_axi_arlen;
+			m_axi_arsize  = pf_axi_arsize;
+			m_axi_arburst = pf_axi_arburst;
+			m_axi_arcache = pf_axi_arcache;
+			m_axi_arprot  = pf_axi_arprot;
+			m_axi_arqos   = pf_axi_arqos;
+		end else begin
+			m_axi_arvalid = sdma_arvalid;
+			m_axi_arid    = sdma_arid;
+			m_axi_araddr  = sdma_araddr;
+			m_axi_arlen   = sdma_arlen;
+			m_axi_arsize  = sdma_arsize;
+			m_axi_arburst = sdma_arburst;
+			m_axi_arcache = sdma_arcache;
+			m_axi_arprot  = sdma_arprot;
+			m_axi_arqos   = sdma_arqos;
+		end
+	end
+	// }}}
+
+	// *_arready
+	// {{{
+	always @(*)
+	begin
+		sdma_arready = m_axi_arready && !pf_wins_arbitration;
+		pf_axi_arready = m_axi_arready && pf_wins_arbitration;
+	end
+	// }}}
+
+	// Outgoing AR skid buffer
+	// {{{
+	skidbuffer #(
+		// {{{
+		.OPT_LOWPOWER(OPT_LOWPOWER),
+		.OPT_OUTREG(1'b1),
+		.DW(C_AXI_ID_WIDTH + C_AXI_ADDR_WIDTH + 8 + 3 + 2 + 4  +3 + 4)
+		// }}}
+	) marskd(
+		// {{{
+		S_AXI_ACLK, !S_AXI_ARESETN, m_axi_arvalid, m_axi_arready,
+		{ m_axi_arid, m_axi_araddr, m_axi_arlen, m_axi_arsize,
+			m_axi_arburst, m_axi_arcache,
+			m_axi_arprot, m_axi_arqos },
+		M_AXI_ARVALID, M_AXI_ARREADY,
+		{ M_AXI_ARID, M_AXI_ARADDR, M_AXI_ARLEN, M_AXI_ARSIZE,
+			M_AXI_ARBURST, M_AXI_ARCACHE,
+			M_AXI_ARPROT, M_AXI_ARQOS }
+		// }}}
+	);
+
+`ifdef	AXI3
+	assign	M_AXI_ARLOCK = 2'b00;	// We don't use lock anyway
+`else
+	assign	M_AXI_ARLOCK = 1'b0;
+`endif
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// FSM Control states
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	axisgfsm #(
+		// {{{
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.ABORT_KEY(ABORT_KEY)
+		// }}}
+	) fsm (
+		// {{{
+		.S_AXI_ACLK(S_AXI_ACLK),
+		.S_AXI_ARESETN(S_AXI_ARESETN),
+		// Control interface
+		// {{{
+		.i_start(r_start),
+		.i_abort(r_abort),
+		.i_tbl_addr(r_tbl_addr),
+		.i_qos(r_qos),
+		.i_prot(r_prot),
+		.o_done(r_done),
+		.o_busy(r_busy),
+		.o_int(w_int),
+		.o_err(fsm_err),
+		.o_tbl_addr(tbl_addr),
+		// }}}
+		// Prefetch interface
+		// {{{
+		.o_new_pc(new_pc),
+		.o_pf_clear_cache(pf_clear_cache),
+		.o_pf_ready(pf_ready),
+		.o_pf_pc(ipc),
+		.i_pf_valid(pf_valid),
+		.i_pf_insn(pf_insn),
+		.i_pf_pc(pf_pc),
+		.i_pf_illegal(pf_illegal),
+		// }}}
+		// DMA AXI-lite control interface
+		// {{{
+		.o_dmac_wvalid(dmac_wvalid),
+		.i_dmac_wready(dmac_wready),
+		.o_dmac_waddr(dmac_waddr),
+		.o_dmac_wdata(dmac_wdata),
+		.o_dmac_wstrb(dmac_wstrb),
+		.i_dmac_rdata(dmac_rdata),
+		.i_dma_complete(dma_complete)
+		// }}}
+
+		// }}}
+	);
+
+	// }}}
+
+	// Make Verilator happy
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, dmac_awready_ignored, dmac_bvalid,
+			dmac_bresp, dmac_rvalid, dmac_rresp,
+			S_AXIL_AWADDR[AXILLSB-1:0], S_AXIL_AWPROT,
+			S_AXIL_ARADDR[AXILLSB-1:0], S_AXIL_ARPROT,
+			M_AXI_RREADY, r_done,
+			new_widetbl[63:C_AXI_ADDR_WIDTH],
+			sdma_arlock, sdma_rready_ignored,
+			pf_axi_rready_ignored, dmac_arready };
+	// Verilator lint_on  UNUSED
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties (neither written, nor tested)
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The full formal verification of this core has not been completed.
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	reg	f_past_valid;
+
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The control interface
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	faxil_slave #(
+		.C_AXI_DATA_WIDTH(C_AXIL_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXIL_ADDR_WIDTH)
+		//
+		// ...
+		//
+		)
+	faxil(
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXIL_AWVALID),
+		.i_axi_awready(S_AXIL_AWREADY),
+		.i_axi_awaddr(S_AXIL_AWADDR),
+		.i_axi_awprot(S_AXIL_AWPROT),
+		//
+		.i_axi_wvalid(S_AXIL_WVALID),
+		.i_axi_wready(S_AXIL_WREADY),
+		.i_axi_wdata( S_AXIL_WDATA),
+		.i_axi_wstrb( S_AXIL_WSTRB),
+		//
+		.i_axi_bvalid(S_AXIL_BVALID),
+		.i_axi_bready(S_AXIL_BREADY),
+		.i_axi_bresp( S_AXIL_BRESP),
+		//
+		.i_axi_arvalid(S_AXIL_ARVALID),
+		.i_axi_arready(S_AXIL_ARREADY),
+		.i_axi_araddr( S_AXIL_ARADDR),
+		.i_axi_arprot( S_AXIL_ARPROT),
+		//
+		.i_axi_rvalid(S_AXIL_RVALID),
+		.i_axi_rready(S_AXIL_RREADY),
+		.i_axi_rdata( S_AXIL_RDATA),
+		.i_axi_rresp( S_AXIL_RRESP)
+		//
+		// ...
+		//
+		);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The main AXI data interface
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Formal contract checking
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Careless assumptions (i.e. constraints)
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// None (currently)
+
+	// }}}
+`endif
+// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axisgfsm.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axisgfsm.v
new file mode 100644
index 0000000..032ebd9
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axisgfsm.v
@@ -0,0 +1,1039 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axisgfsm.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Scripts an AXI DMA via in-memory tables: reads from the tables,
+//		commands the DMA.
+//
+// Registers:
+//
+//	0. Control
+//		8b	KEY
+//			3'b PROT
+//			4'b QOS
+//		1b	Abort: Either aborting or aborted
+//		1b	Err: Ended on an error
+//		1b	Busy
+//		1b	Interrupt Enable
+//		1b	Interrupt Set
+//		1b	Start
+//	1. Reserved
+//	2-3. First table entry address
+//		(Current) table entry address on read, if in progress
+// (Optional)
+//	4-5. Current read address
+//	6-7. Current write address
+//	1.   Remaining amount to be written (this entry)
+//
+// Table format:
+//	Table entries either consist of five 32-bit words, or three 32-bit
+//	words, depending upon the size of the address bus.
+//
+//	Address bus > 30 bits: five 32-bit words
+//	0-1:	64b: { 2'bflags, 62'b SOURCE ADDRESS (bytes) }
+//			00: Continue after this to next
+//			01: Last item in chain
+//			10: Skip this address
+//			11: Jump to new address
+//	2-3:	64b: { int_en, 1'b0,  DESTINATION ADDRESS (bytes) }
+//	4:	32b Transfer length (in bytes)
+//
+//	Address bus <= 30 bits: three 32-bit words
+//	0:	32b: { 2'bflags, 30'b SOURCE ADDRESS (bytes) }
+//	1:	32b: { int_en, 1'b0, 30'b DESTINATION ADDRESS (bytes) }
+//	2:	32b LENGTH (in bytes)
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// `define			AXI3
+// }}}
+module	axisgfsm #(
+		// {{{
+		parameter	C_AXI_ADDR_WIDTH = 30,
+		parameter	C_AXI_DATA_WIDTH = 32,
+		localparam DMAC_ADDR_WIDTH = 5,
+		localparam DMAC_DATA_WIDTH = 32,
+		//
+		// The "ABORT_KEY" is a byte that, if written to the control
+		// word while the core is running, will cause the data transfer
+		// to be aborted.
+		parameter	[7:0]			ABORT_KEY  = 8'h6d
+		// }}}
+	) (
+		// {{{
+		input	wire	S_AXI_ACLK,
+		input	wire	S_AXI_ARESETN,
+		//
+		// The control interface
+		// {{{
+		input	wire				i_start, i_abort,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]	i_tbl_addr,
+		input	wire	[3:0]			i_qos,
+		input	wire	[2:0]			i_prot,
+		output	reg				o_busy,
+		output	reg				o_done,
+		output	reg				o_int,
+		output	reg				o_err,
+		output	reg	[C_AXI_ADDR_WIDTH-1:0]	o_tbl_addr,
+		// }}}
+		//
+		// The prefetch interface
+		// {{{
+		output	reg				o_new_pc,
+		output	reg				o_pf_clear_cache,
+		output	reg				o_pf_ready,
+		output	reg	[C_AXI_ADDR_WIDTH-1:0]	o_pf_pc,
+		input	wire				i_pf_valid,
+		input	wire	[31:0]			i_pf_insn,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]	i_pf_pc,
+		input	wire				i_pf_illegal,
+		// }}}
+		//
+		// The DMA submodule's AXI4-lite control interface
+		// {{{
+		output	reg				o_dmac_wvalid,
+		input	wire				i_dmac_wready,
+		output	reg [DMAC_ADDR_WIDTH-1:0]	o_dmac_waddr,
+		output	reg [DMAC_DATA_WIDTH-1:0]	o_dmac_wdata,
+		output	reg [DMAC_DATA_WIDTH/8-1:0]	o_dmac_wstrb,
+		input	wire [DMAC_DATA_WIDTH-1:0]	i_dmac_rdata,
+		input	wire				i_dma_complete
+		// }}}
+		// }}}
+	);
+
+	// Local parameter definitions
+	// {{{
+
+	// Scatter gather state machine states
+	// {{{
+	// States:
+	// - 0. IDLE (nothing going on, waiting for a new program counter)
+	//	Enter on completion, reset, or (abort and DMA complete)
+	// - 1. READ_LOSRC -> DMA
+	// - 2. READ_HISRC -> DMA (Optional)
+	//	((Skip || JUMP) ->READ_LOSRC)
+	// - 3. READ_LODST -> DMA
+	// - 4. READ_HIDST -> DMA (Optional)
+	// - 5. READ_LEN   -> DMA
+	// - 6. READ_FLAGS -> SETS -> START DMA
+	// - 7. Wait on DMA
+	//	(Set interrupt if INT complete)
+	//	(If last, go to idle, else jump to #1)
+	//	(Set LAST on abort)
+	//
+	localparam [2:0]	SG_IDLE    = 3'h0,
+				SG_SRCHALF = 3'h1,
+				SG_SRCADDR = 3'h2,
+				SG_DSTHALF = 3'h3,
+				SG_DSTADDR = 3'h4,
+				SG_LENGTH  = 3'h5,
+				SG_CONTROL = 3'h6,
+				SG_WAIT    = 3'h7;
+	// }}}
+
+	// DMA device internal addresses
+	// {{{
+	localparam [4:0]	DMA_CONTROL= 5'b00000,
+				DMA_UNUSED = 5'b00100,
+				DMA_SRCLO  = 5'b01000,
+				DMA_SRCHI  = 5'b01100,
+				DMA_DSTLO  = 5'b10000,
+				DMA_DSTHI  = 5'b10100,
+				DMA_LENLO  = 5'b11000,
+				DMA_LENHI  = 5'b11100;
+	// }}}
+
+	localparam [C_AXI_ADDR_WIDTH-1:0] TBL_SIZE
+				= (C_AXI_ADDR_WIDTH <= 30) ? (4*3) : (4*5);
+
+	// }}}
+
+	// Register/net declarations
+	// {{{
+	reg		tbl_last, tbl_int_enable;
+	reg	[2:0]	sgstate;
+	reg		dma_err, dma_abort, dma_done, dma_busy;
+	reg	[59:0]	r_pf_pc;
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// FSM Control states
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// o_pf_ready
+	// {{{
+	always @(*)
+	begin
+		case(sgstate)
+		SG_IDLE:	o_pf_ready = 1'b0;
+		SG_SRCHALF:	o_pf_ready = (!o_dmac_wvalid || i_dmac_wready);
+		SG_SRCADDR:	o_pf_ready = (!o_dmac_wvalid || i_dmac_wready);
+		SG_DSTHALF:	o_pf_ready = (!o_dmac_wvalid || i_dmac_wready);
+		SG_DSTADDR:	o_pf_ready = (!o_dmac_wvalid || i_dmac_wready);
+		SG_LENGTH:	o_pf_ready = (!o_dmac_wvalid || i_dmac_wready);
+		SG_CONTROL:	o_pf_ready = 1'b0;
+		SG_WAIT:	o_pf_ready = 1'b0;
+		endcase
+
+		if (!o_busy || o_pf_clear_cache || o_new_pc)
+			o_pf_ready = 0;
+	end
+	// }}}
+
+	// w_int
+	// {{{
+	always @(*)
+	begin
+		o_int = 1'b0;
+
+		if (sgstate == SG_WAIT && i_dma_complete
+					&& (tbl_last || tbl_int_enable))
+			o_int = 1'b1;
+		if (i_pf_valid && o_pf_ready && i_pf_illegal)
+			o_int = 1'b1;
+	end
+	// }}}
+
+	// Returns from the DMA controller (one clock later)
+	// {{{
+	always @(*)
+	begin
+		dma_err   = i_dmac_rdata[4];
+		dma_abort = i_dmac_rdata[3];
+		dma_done  = i_dmac_rdata[1];
+		dma_busy  = i_dmac_rdata[0];
+	end
+	// }}}
+
+	// The GIANT FSM itself
+	// new_pc, pf_clear_cache, dmac_wvalid, dmac_waddr, dmac_wdata,
+	// dmac_wstrb, ipc,
+	// {{{
+	initial	r_pf_pc  = 0;
+	initial	sgstate  = SG_IDLE;
+	initial	o_new_pc = 1'b0;
+	initial	o_busy   = 1'b0;
+	initial	o_done   = 1'b0;
+	initial	o_err    = 1'b0;
+	initial	o_dmac_wvalid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	begin
+		// Auto-cleared values
+		// {{{
+		o_new_pc <= 1'b0;
+		o_pf_clear_cache <= 1'b0;
+		if (i_dmac_wready)
+			o_dmac_wvalid <= 1'b0;
+		if (!o_dmac_wvalid || i_dmac_wready)
+			o_dmac_wstrb <= 4'hf;
+		o_done <= 1'b0;
+		o_err  <= 1'b0;
+		// }}}
+
+		case(sgstate)
+		SG_IDLE: // IDLE -- waiting for start
+			// {{{
+			begin
+			r_pf_pc[C_AXI_ADDR_WIDTH-1:0] <= i_tbl_addr;
+			if (i_start)
+			begin
+				o_new_pc <= 1'b1;
+				if (C_AXI_ADDR_WIDTH > 30)
+					sgstate <= SG_SRCHALF;
+				else
+					sgstate <= SG_SRCADDR;
+				o_busy <= 1'b1;
+			end else begin
+				o_new_pc <= 1'b0;
+				o_pf_clear_cache <= 1'b1;
+				o_busy <= 1'b0;
+			end end
+			// }}}
+		SG_SRCHALF: // Get the first source address
+			// {{{
+			if (i_pf_valid && (!o_dmac_wvalid || i_dmac_wready))
+			begin
+			o_dmac_wvalid <= 1'b1;
+			o_dmac_waddr  <= DMA_SRCLO;
+			o_dmac_wdata  <= i_pf_insn;
+			sgstate <= SG_SRCADDR;
+			// r_pf_pc[31:0] <= i_pf_insn;
+			o_tbl_addr <= i_pf_pc;
+			end
+			// }}}
+		SG_SRCADDR: // Second half of the source address
+			// {{{
+			if (i_pf_valid && o_pf_ready)
+			begin
+			o_dmac_wvalid <= i_pf_valid && !i_pf_insn[31];
+			o_dmac_waddr  <= (C_AXI_ADDR_WIDTH<=30)
+						? DMA_SRCLO : DMA_SRCHI;
+			o_dmac_wdata  <= i_pf_insn;
+			// r_pf_pc[31:0] <= i_pf_insn;
+			if (C_AXI_ADDR_WIDTH <= 30)
+			begin
+				sgstate <= SG_DSTADDR;
+				o_tbl_addr <= i_pf_pc;
+				// // r_pf_pc[30-1:0] <= i_pf_insn[30-1:0];
+			end else begin
+				sgstate <= SG_DSTHALF;
+				// r_pf_pc[60-1:30] <= i_pf_insn[30-1:0];
+			end
+
+			tbl_last <= 1'b0;
+			case(i_pf_insn[31:30])
+			2'b00: // Other items still to follow
+				tbl_last <= 1'b0;
+			2'b01: // Last item in the chain
+				tbl_last <= 1'b1;
+			2'b10: begin // Skip
+				tbl_last <= 1'b0;
+				if (C_AXI_ADDR_WIDTH > 30)
+					sgstate <= SG_SRCHALF;
+				else
+					sgstate <= SG_SRCADDR;
+				o_new_pc <= 1'b1;
+				r_pf_pc[C_AXI_ADDR_WIDTH-1:0]
+						<= r_pf_pc[C_AXI_ADDR_WIDTH-1:0] + TBL_SIZE;
+				end
+			2'b11: begin // Jump
+				o_new_pc <= 1'b1;
+				// ipc <= // already set from above
+				if (C_AXI_ADDR_WIDTH > 30)
+					sgstate <= SG_SRCHALF;
+				else
+					sgstate <= SG_SRCADDR;
+				r_pf_pc[C_AXI_ADDR_WIDTH-1:0] <= i_pf_insn[C_AXI_ADDR_WIDTH-1:0];
+				end
+			endcase
+			end
+			// }}}
+		SG_DSTHALF: // Get the first half of the destination address
+			// {{{
+			if (i_pf_valid && (!o_dmac_wvalid || i_dmac_wready))
+			begin
+			o_dmac_wvalid<= 1'b1;
+			o_dmac_waddr <= DMA_DSTLO;
+			o_dmac_wdata <= i_pf_insn;
+			sgstate    <= SG_DSTADDR;
+			end
+			// }}}
+		SG_DSTADDR: // Second half of the destination address
+			// {{{
+			if (i_pf_valid && (!o_dmac_wvalid || i_dmac_wready))
+			begin
+			o_dmac_wvalid <= 1'b1;
+			o_dmac_waddr  <= (C_AXI_ADDR_WIDTH<=30)
+						? DMA_DSTLO : DMA_DSTHI;
+			o_dmac_wdata <= { 2'b0, i_pf_insn[29:0] };
+			sgstate    <= SG_LENGTH;
+			tbl_int_enable <= i_pf_insn[31];
+			end
+			// }}}
+		SG_LENGTH: // The length word
+			// {{{
+			if (i_pf_valid && (!o_dmac_wvalid || i_dmac_wready))
+			begin
+			o_dmac_wvalid <= 1'b1;
+			o_dmac_waddr  <= DMA_LENLO;
+			o_dmac_wdata <= i_pf_insn;
+			sgstate    <= SG_CONTROL;
+			if (i_pf_insn <= 0)
+			begin
+				if (tbl_last)
+				begin
+					sgstate    <= SG_IDLE;
+					o_new_pc   <= 1'b0;
+				end else begin
+					sgstate    <= SG_SRCADDR;
+					o_new_pc   <= 1'b1;
+				end
+			end
+			end
+			// }}}
+		SG_CONTROL: // The control word to get us started
+			// {{{
+			if (!o_dmac_wvalid || i_dmac_wready)
+			begin
+			o_dmac_wvalid <= 1'b1;
+			o_dmac_waddr  <= DMA_CONTROL;
+			o_dmac_wdata <= { 9'h0, i_prot, i_qos,
+					11'h0,
+					1'h1, // Clear any errors
+					1'b1, // Clr abort flag
+					1'b1, // Set int enable, int
+					1'b1, // Clr any prior interrupt
+					1'b1 };
+			sgstate    <= SG_WAIT;
+			o_tbl_addr <= o_tbl_addr + TBL_SIZE;
+			end
+			// }}}
+		SG_WAIT: // Wait for the DMA transfer to complete
+			// {{{
+			if (i_dma_complete && !o_dmac_wvalid)
+			begin
+				// o_int <= int_enable;
+				if (tbl_last || (dma_err && !o_busy)
+							|| i_pf_illegal)
+				begin
+					o_pf_clear_cache <= 1'b1;
+					sgstate <= SG_IDLE;
+					o_busy <= 1'b0;
+					o_done <= 1'b1;
+					o_err  <= dma_err || dma_abort;
+					if (!i_pf_illegal)
+						// Halt at the beginning
+						// of the TBL
+						r_pf_pc[C_AXI_ADDR_WIDTH-1:0] <= o_tbl_addr;
+					else
+						r_pf_pc[C_AXI_ADDR_WIDTH-1:0] <= i_pf_pc;
+				end else if (C_AXI_ADDR_WIDTH > 30)
+					sgstate <= SG_SRCHALF;
+				else
+					sgstate <= SG_SRCADDR;
+			end
+			// }}}
+		endcase
+
+		if (i_pf_valid && i_pf_illegal
+			&& sgstate != SG_CONTROL && sgstate != SG_WAIT
+			&& !o_new_pc && !o_pf_clear_cache)
+		begin
+			// {{{
+			sgstate <= SG_IDLE;
+			o_pf_clear_cache <= 1'b1;
+			o_done <= 1'b1;
+			o_busy <= 1'b0;
+			o_err  <= 1'b1;
+			// }}}
+		end
+
+		if (i_abort && (!o_dmac_wvalid || i_dmac_wready))
+		begin
+			// {{{
+			o_dmac_wstrb <= 4'h8;
+			o_dmac_wdata[31:24] <= ABORT_KEY;
+			o_dmac_wvalid <= !dma_abort && (sgstate == SG_WAIT);
+			// }}}
+			if (!dma_busy)
+				sgstate <= SG_IDLE;
+		end
+
+		if (!S_AXI_ARESETN)
+		begin
+			// {{{
+			sgstate <= SG_IDLE;
+			o_pf_clear_cache <= 1'b1;
+			o_new_pc <= 1'b0;
+			o_dmac_wvalid <= 1'b0;
+			r_pf_pc <= 0;
+			o_busy <= 1'b0;
+			o_done <= 1'b0;
+			o_err  <= 1'b0;
+			// }}}
+		end
+
+		r_pf_pc[60-1:C_AXI_ADDR_WIDTH] <= 0;
+	end
+
+	always @(*)
+		o_pf_pc = { r_pf_pc[C_AXI_ADDR_WIDTH-1:2], 2'b00 };
+	// }}}
+
+	// }}}
+
+	// Make Verilator happy
+	// {{{
+	// Verilatar lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, dma_done, i_dmac_rdata[31:5],
+				i_dmac_rdata[2],
+				r_pf_pc[59:C_AXI_ADDR_WIDTH] };
+	// Verilatar lint_on  UNUSED
+	// }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	////////////////////////////////////////////////////////////////////////
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	localparam	F_LGDEPTH = 4;
+	reg	f_past_valid;
+	(* anyseq *) reg [TBL_SIZE*8-1:0] f_tblentry;
+	reg	[C_AXI_ADDR_WIDTH-1 :0]	f_tbladdr, f_pc;
+	(* anyconst *) reg		f_never_abort;
+	// (* anyconst *) reg [C_AXI_ADDR_WIDTH-1:0]	f_skip_addr;
+	reg				f_tbl_last, f_tbl_skip, f_tbl_jump,
+					f_tbl_int_enable;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	f_tbl_src;
+	reg				f_dma_arvalid, f_dma_arready,
+					f_dma_awready;
+
+
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+
+	always @(*)
+	if (!f_past_valid)
+		assume(!S_AXI_ARESETN);
+
+	always @(*)
+	if (i_start)
+	begin
+		assume(!i_abort);
+		assume(i_tbl_addr[1:0] == 2'b00);
+	end
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Prefetch interface property checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// Prefetch properties
+
+	assume property (@(posedge S_AXI_ACLK)
+		S_AXI_ARESETN && i_pf_valid && !o_pf_ready
+			&& !o_pf_clear_cache && !o_new_pc
+		|=> i_pf_valid && $stable({
+				i_pf_insn, i_pf_pc, i_pf_illegal }));
+
+	always @(*)
+	if (o_new_pc)
+		assert(o_pf_pc[1:0] == 2'b00);
+
+	always @(posedge S_AXI_ACLK)
+	if (o_new_pc)
+		f_pc <= o_pf_pc;
+	else if (i_pf_valid && o_pf_ready)
+		f_pc <= f_pc + 4;
+
+	always @(*)
+	if (i_pf_valid)
+		assume(i_pf_pc == f_pc);
+
+	always @(*)
+	if (S_AXI_ARESETN && !o_new_pc && !o_pf_clear_cache)
+		assert(f_pc[1:0] == 2'b00);
+
+	always @(posedge S_AXI_ACLK)
+	if (!f_past_valid || $past(!S_AXI_ARESETN || o_new_pc
+				|| o_pf_clear_cache))
+		assume(!i_pf_illegal);
+	else if (!$rose(i_pf_valid))
+		assume(!$rose(i_pf_illegal));
+	else
+		assume($stable(i_pf_illegal));
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite interface property checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	[F_LGDEPTH-1:0]	fdma_rd_outstanding, fdma_wr_outstanding,
+				fdma_awr_outstanding;
+	reg			f_dma_bvalid;
+
+	faxil_master #(
+		.C_AXI_DATA_WIDTH(32),
+		.C_AXI_ADDR_WIDTH(DMAC_ADDR_WIDTH),
+		.F_OPT_BRESP(1'b1),
+		.F_OPT_RRESP(1'b0),
+		.F_OPT_NO_RESET(1'b1),
+		.F_LGDEPTH(F_LGDEPTH)
+	) faxi(
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awready(i_dmac_wready),
+		.i_axi_awaddr(o_dmac_waddr),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot( 3'h0),
+		.i_axi_awvalid(o_dmac_wvalid),
+		//
+		.i_axi_wready(i_dmac_wready),
+		.i_axi_wdata( o_dmac_wdata),
+		.i_axi_wstrb( o_dmac_wstrb),
+		.i_axi_wvalid(o_dmac_wvalid),
+		//
+		.i_axi_bready(1'b1),
+		.i_axi_bresp( 2'b00),
+		.i_axi_bvalid(f_dma_bvalid),
+		//
+		.i_axi_arready(f_dma_arready),
+		.i_axi_araddr(DMA_CONTROL),
+		.i_axi_arcache(4'h0),
+		.i_axi_arprot(3'h0),
+		.i_axi_arvalid(f_dma_arvalid),
+		//
+		.i_axi_rresp(2'b00),
+		.i_axi_rvalid(f_dma_arvalid),
+		.i_axi_rdata(i_dmac_rdata),
+		.i_axi_rready(1'b1),
+		//
+		.f_axi_rd_outstanding(fdma_rd_outstanding),
+		.f_axi_wr_outstanding(fdma_wr_outstanding),
+		.f_axi_awr_outstanding(fdma_awr_outstanding)
+	);
+
+	initial	f_dma_arvalid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_dma_arvalid = 1'b0;
+	else
+		f_dma_arvalid <= 1'b1;
+
+	always @(*)
+		f_dma_arready = 1'b1;
+
+	assert property (@(posedge S_AXI_ACLK)
+		!S_AXI_ARESETN
+		|=> sgstate == SG_IDLE && !o_dmac_wvalid);
+
+
+	assert property (@(posedge S_AXI_ACLK)
+		S_AXI_ARESETN && o_dmac_wvalid && !i_dmac_wready
+		|=> o_dmac_wvalid && $stable({
+			o_dmac_waddr, o_dmac_wdata, o_dmac_wstrb }));
+
+	assert property (@(posedge S_AXI_ACLK)
+		fdma_wr_outstanding == fdma_awr_outstanding);
+
+	assert property (@(posedge S_AXI_ACLK)
+		fdma_wr_outstanding == (f_dma_bvalid ? 1:0));
+
+	initial	f_dma_bvalid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_dma_bvalid <= 0;
+	else if (o_dmac_wvalid && i_dmac_wready)
+		f_dma_bvalid <= 1;
+	else
+		f_dma_bvalid <= 0;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// DMA busy and read interface properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+			reg	f_dma_busy;
+	(* anyseq *)	reg	f_dma_complete;
+
+	initial	f_dma_busy = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_dma_busy <= 0;
+	else if (o_dmac_wvalid && i_dmac_wready && o_dmac_waddr == 0
+			&& o_dmac_wstrb[0] && o_dmac_wdata[0])
+		f_dma_busy <= 1'b1;
+	else if (f_dma_busy)
+		f_dma_busy <= !f_dma_complete;
+
+	assume property (@(posedge S_AXI_ACLK)
+		##1 dma_busy == $past(f_dma_busy));
+	assume property (@(posedge S_AXI_ACLK)
+		!f_dma_busy |-> !f_dma_complete);
+
+	assume property (@(posedge S_AXI_ACLK)
+		##1 i_dma_complete == $past(f_dma_complete));
+
+//	assume property (@(posedge S_AXI_ACLK)
+//		dma_busy |=> dma_busy [*0:$]
+//		##1 dma_busy && i_dma_complete
+//		##1 !dma_busy);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// State machine checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	always @(*)
+		f_tbl_src = f_tblentry[C_AXI_ADDR_WIDTH-1:0];
+
+	always @(*)
+	if (o_new_pc)
+	begin
+		if (C_AXI_ADDR_WIDTH <= 30)
+			assert(sgstate == SG_SRCADDR);
+		else
+			assert(sgstate == SG_SRCHALF);
+	end
+
+	generate if (C_AXI_ADDR_WIDTH > 30)
+	begin
+		always @(*)
+		begin
+			f_tbl_last = (f_tblentry[63:62] == 2'b01);
+			f_tbl_skip = (f_tblentry[63:62] == 2'b10);
+			f_tbl_jump = (f_tblentry[63:62] == 2'b11);
+			f_tbl_int_enable = f_tblentry[127];
+		end
+	end else begin
+		always @(*)
+		begin
+			f_tbl_last = (f_tblentry[31:30] == 2'b01);
+			f_tbl_skip = (f_tblentry[31:30] == 2'b10);
+			f_tbl_jump = (f_tblentry[31:30] == 2'b11);
+			f_tbl_int_enable = f_tblentry[63];
+		end
+	end endgenerate
+
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARESETN
+		&& (sgstate != SG_IDLE)
+			&&(sgstate != SG_SRCADDR || $stable(sgstate)))
+		assume($stable(f_tblentry));
+
+	always @(posedge S_AXI_ACLK)
+	if (o_new_pc)
+		f_tbladdr <= o_pf_pc;
+
+	assert property (@(posedge S_AXI_ACLK)
+		disable iff (!S_AXI_ARESETN)
+		sgstate == SG_IDLE && !i_start
+		|=> sgstate == SG_IDLE && o_pf_clear_cache);
+
+	generate if (C_AXI_ADDR_WIDTH <= 30)
+	begin : SMALL_ADDRESS_SPACE
+		// {{{
+		reg	[5:0]	f_dma_seq;
+
+		always @(*)
+		begin
+			assert(sgstate != SG_SRCHALF);
+			assert(sgstate != SG_DSTHALF);
+		end
+
+		always @(*)
+		if (i_pf_valid)
+		case(sgstate)
+		// SG_IDLE:	begin end
+		// SG_SRCHALF:	begin end
+		// SG_DSTHALF:	begin end
+		// SG_LENGTH:	begin end
+		// SG_CONTROL:	begin end
+		// SG_WAIT:	begin end
+		SG_SRCADDR: assume(i_pf_insn == f_tblentry[31:0]
+				&&(i_pf_pc == f_tbladdr));
+		SG_DSTADDR: assume(i_pf_insn == f_tblentry[63:32]
+				&&(i_pf_pc == f_tbladdr + 4));
+		SG_LENGTH: assume(i_pf_insn == f_tblentry[95:64]
+				&&(i_pf_pc == f_tbladdr + 8));
+		endcase
+
+		assert property (@(posedge S_AXI_ACLK)
+			disable iff (!S_AXI_ARESETN)
+			sgstate == SG_IDLE && i_start
+			|=> o_new_pc && !o_pf_clear_cache
+				&& sgstate == SG_SRCADDR
+				&& r_pf_pc[C_AXI_ADDR_WIDTH-1:0]
+					== $past(i_tbl_addr));
+
+		initial	f_dma_seq = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN || i_abort)
+			f_dma_seq <= 0;
+		else begin
+
+			// SG_SRCADDR, or entering SG_SRCADDR
+			// {{{
+			if ((f_dma_seq == 0)&&(i_start))
+				f_dma_seq <= 1;
+
+			if (f_dma_seq[0] || o_new_pc)
+			begin
+				assert(sgstate == SG_SRCADDR);
+				assert(!o_dmac_wvalid);
+				assert(!dma_busy);
+				f_dma_seq <= 1;
+				if (i_pf_valid && o_pf_ready)
+				begin
+					f_dma_seq <= 2;
+
+					if (f_tbl_jump || f_tbl_skip)
+						f_dma_seq <= 1;
+				end
+
+				if (!o_new_pc)
+				begin
+					assert(o_pf_pc == f_tbladdr);
+					assert(f_pc == o_pf_pc);
+				end
+
+				if ($past(sgstate == SG_SRCADDR
+					&& i_pf_valid && o_pf_ready))
+				begin
+					// Jump or skip
+
+					assert(o_new_pc);
+					// Check the jump address
+					// if ($past(i_pf_insn[31:30] == 2'b11))
+					if ($past(f_tbl_jump))
+						assert(o_pf_pc == { $past(i_pf_insn[C_AXI_ADDR_WIDTH-1:2]), 2'b00 });
+					else // Skip
+						assert(o_pf_pc == $past(f_tbladdr + TBL_SIZE));
+				end
+			end
+			// }}}
+
+			// SG_DSTADDR
+			// {{{
+			if (f_dma_seq[1])
+			begin
+				assert(sgstate == SG_DSTADDR);
+				assert(tbl_last == f_tbl_last);
+				assert(o_tbl_addr == f_tbladdr);
+				if ($rose(f_dma_seq[1]))
+					assert(o_dmac_wvalid);
+				assert(o_dmac_waddr == DMA_SRCLO);
+				assert(o_dmac_wdata == f_tblentry[31:0]);
+				assert(&o_dmac_wstrb);
+				assert(!dma_busy);
+				assert(o_pf_pc == f_tbladdr);
+				// assert(f_pc == o_pf_pc + 4);
+				f_dma_seq <= 2;
+				if (i_pf_valid && o_pf_ready)
+					f_dma_seq <= 4;
+			end
+			// }}}
+
+			// SG_LENGTH
+			// {{{
+			if (f_dma_seq[2])
+			begin
+				assert(sgstate == SG_LENGTH);
+				assert(tbl_last == f_tbl_last);
+				assert(tbl_int_enable == f_tbl_int_enable);
+				assert(o_tbl_addr == f_tbladdr);
+				if ($rose(f_dma_seq[2]))
+					assert(o_dmac_wvalid);
+				assert(o_dmac_waddr == DMA_DSTLO);
+				assert(o_dmac_wdata == { 2'b00, f_tblentry[61:32] });
+				assert(&o_dmac_wstrb);
+				assert(!dma_busy);
+				assert(o_pf_pc == f_tbladdr);
+				// assert(f_pc == o_pf_pc + 8);
+				f_dma_seq <= 4;
+				if (i_pf_valid && o_pf_ready)
+					f_dma_seq <= 8;
+			end
+			// }}}
+
+			// SG_CONTROL
+			// {{{
+			if (f_dma_seq[3])
+			begin
+				assert(sgstate == SG_CONTROL);
+				assert(tbl_last == f_tbl_last);
+				assert(o_tbl_addr == f_tbladdr);
+				assert(o_dmac_wvalid);
+				assert(o_dmac_waddr == DMA_LENLO);
+				assert(o_dmac_wdata == f_tblentry[95:64]);
+				assert(&o_dmac_wstrb);
+				assert(!dma_busy);
+				assert(o_pf_pc == f_tbladdr);
+				// assert(f_pc == o_pf_pc);
+				f_dma_seq <= 8;
+				if (i_dmac_wready)
+					f_dma_seq <= 16;
+			end
+			// }}}
+
+			// SG_WAIT && o_dmac_wvalid
+			// {{{
+			if (f_dma_seq[4])
+			begin
+				assert(sgstate == SG_WAIT);
+				assert(tbl_last == f_tbl_last);
+				assert(o_tbl_addr == f_tbladdr + TBL_SIZE);
+				assert(o_dmac_wvalid);
+				assert(o_dmac_waddr == DMA_CONTROL);
+				assert(o_dmac_wdata[15:0] == 16'h1f);
+				assert(&o_dmac_wstrb);
+				assert(!dma_busy);
+				assert(o_pf_pc == f_tbladdr);
+				// assert(f_pc == o_pf_pc);
+				f_dma_seq <= 16;
+				if (o_dmac_wvalid && i_dmac_wready)
+					f_dma_seq <= 32;
+			end
+			// }}}
+
+			// SG_WAIT && !o_dmac_wvalid
+			// {{{
+			if (f_dma_seq[5])
+			begin
+				assert(sgstate == SG_WAIT);
+				assert(!o_dmac_wvalid);
+				assert(tbl_last == f_tbl_last);
+				assert(o_tbl_addr == f_tbladdr + TBL_SIZE);
+				assert(!o_dmac_wvalid);
+				assert(o_dmac_waddr == DMA_CONTROL);
+				// assert(o_dmac_wdata == f_tblentry[95:64]);
+				assert(&o_dmac_wstrb);
+				f_dma_seq <= 32;
+				assert(o_pf_pc == f_tbladdr);
+				// assert(f_pc == o_pf_pc);
+				if (i_dma_complete)
+					f_dma_seq <= 0;
+			end
+			// }}}
+
+			// pf_illegal
+			// {{{
+			if (f_dma_seq[2:0] && i_pf_illegal)
+				f_dma_seq <= 0;
+			// }}}
+
+			// i_abort
+			// if (f_dma_seq[2:0] && i_abort
+			//		&& (!o_dmac_wvalid || i_dmac_wready))
+			//	f_dma_seq <= 0;
+		end
+
+		always @(*)
+		if (f_dma_seq == 0)
+		begin
+			assert(sgstate == SG_IDLE);
+			assert(!o_new_pc);
+			assert(!o_dmac_wvalid);
+		end
+
+		always @(posedge S_AXI_ACLK)
+		if (!f_past_valid || $past(!S_AXI_ARESETN))
+		begin end
+		else if (sgstate == 0)
+		begin
+			assert(o_pf_clear_cache);
+			assert(!dma_busy);
+		end
+
+		cover property (@(posedge S_AXI_ACLK)
+			f_dma_seq[5]);
+
+		cover property (@(posedge S_AXI_ACLK)
+			disable iff (!S_AXI_ARESETN || i_abort || i_pf_illegal
+				|| dma_err)
+			f_dma_seq[0] ##1 1[*0:$] ##1 f_dma_seq[5]
+			##1 f_dma_seq == 0);	// !!!
+
+		cover property (@(posedge S_AXI_ACLK)
+			f_dma_seq[5] && !tbl_last && f_dma_busy && dma_busy);
+
+		cover property (@(posedge S_AXI_ACLK)
+			f_dma_seq[5] && tbl_last && f_dma_busy && dma_busy);
+
+		cover property (@(posedge S_AXI_ACLK)
+			f_dma_seq[5] ##2 f_dma_seq[0]);	// !!!
+
+		cover property (@(posedge S_AXI_ACLK)
+			f_dma_seq[5] && tbl_last && i_dma_complete);	// !!!
+
+		cover property (@(posedge S_AXI_ACLK)
+			f_dma_seq[5] && i_dma_complete);	// !!!
+		// }}}
+	end else begin : BIG_ADDR
+	end endgenerate
+
+	always @(*)
+		assert(o_busy == (sgstate != SG_IDLE));
+
+	always @(*)
+	if (o_busy)
+	begin
+		assert(!o_done);
+		assert(!o_err);
+	end
+
+	assert property (@(posedge S_AXI_ACLK)
+		S_AXI_ARESETN && o_busy ##1 !o_busy |-> o_done);
+
+//	assert property (@(posedge S_AXI_ACLK)
+//		!o_done |-> !o_int);
+
+	assert property (@(posedge S_AXI_ACLK)
+		!o_done && !o_busy |-> !o_err);
+
+	always @(*)
+	if (o_pf_ready)
+		assert(!o_dmac_wvalid || i_dmac_wready);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Careless assumptions (i.e. constraints)
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	always @(*)
+		assume(!i_abort);
+
+	always @(*)
+	if (sgstate == SG_SRCHALF)
+		assume(!i_abort);
+	// }}}
+`endif
+// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axisrandom.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axisrandom.v
new file mode 100644
index 0000000..089a4cd
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axisrandom.v
@@ -0,0 +1,136 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axisrandom
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	An AXI-stream based pseudorandom noise generator
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+//
+`default_nettype none
+//
+module	axisrandom #(
+		// {{{
+		localparam	C_AXIS_DATA_WIDTH = 32
+		// }}}
+	) (
+		// {{{
+		input	wire					S_AXI_ACLK,
+		input	wire					S_AXI_ARESETN,
+		//
+		input	reg					M_AXIS_TVALID,
+		output	wire					M_AXIS_TREADY,
+		input	reg	[C_AXIS_DATA_WIDTH-1:0]		M_AXIS_TDATA
+		// }}}
+	);
+
+	localparam	INITIAL_FILL = { 1'b1, {(C_AXIS_DATA_WIDTH-1){1'b0}} };
+	localparam	LGPOLY = 31;
+	localparam [LGPOLY-1:0]			CORE_POLY = { 31'h00_00_20_01 };
+	localparam [C_AXIS_DATA_WIDTH-1:0]	POLY
+				= { CORE_POLY, {(C_AXIS_DATA_WIDTH-31){1'b0}} };
+
+	// M_AXIS_TVALID
+	// {{{
+	initial	M_AXIS_TVALID = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		M_AXIS_TVALID <= 1'b0;
+	else
+		M_AXIS_TVALID <= 1'b1;
+	// }}}
+
+	// M_AXIS_TDATA
+	// {{{
+	//
+	// Note--this setup is *FAR* from cryptographically random.
+	//
+	initial	M_AXIS_TDATA = INITIAL_FILL;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		M_AXIS_TDATA <= INITIAL_FILL;
+	else if (M_AXIS_TREADY)
+	begin
+		M_AXIS_TDATA <= M_AXIS_TDATA >> 1;
+		M_AXIS_TDATA[C_AXIS_DATA_WIDTH-1] <= ^(M_AXIS_TDATA & POLY);
+	end
+	// }}}
+
+	// Verilator lint_off UNUSED
+	// {{{
+	wire	unused;
+	assign	unused = &{ 1'b0 };
+	// Verilator lint_on  UNUSED
+	// }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties used in verfiying this core
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	reg	f_past_valid;
+
+	initial	f_past_valid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1'b1;
+
+	always @(*)
+	if (!f_past_valid)
+		assume(!S_AXI_ARESETN);
+
+	// Make certain this polynomial will never degenerate, and so that
+	// this random number stream will go on for ever--eventually repeating
+	// after 2^LGPOLY-1 (hopefully) elements.
+	always @(*)
+		assert(M_AXIS_TDATA[C_AXIS_DATA_WIDTH-1
+				:C_AXIS_DATA_WIDTH-LGPOLY] != 0);
+
+	// AXI stream has only one significant property
+	// {{{
+	// Here we'll modify it slightly for our purposes
+	always @(posedge S_AXI_ACLK)
+	if (!f_past_valid || $past(!S_AXI_ARESETN))
+		assert(!M_AXIS_TVALID);
+	else begin
+		assert(M_AXIS_TVALID);
+		if ($past(M_AXIS_TVALID && !M_AXIS_TREADY))
+			// Normally I'd assesrt M_AXIS_TVALID here, not above,
+			// but this core *ALWAYS* produces data
+			assert($stable(M_AXIS_TDATA));
+		else if ($past(M_AXIS_TVALID))
+			// Insist that the data always changes otherwise
+			assert($changed(M_AXIS_TDATA));
+	end
+	// }}}
+`endif
+// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axissafety.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axissafety.v
new file mode 100644
index 0000000..929e75b
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axissafety.v
@@ -0,0 +1,677 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axissafety.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	A firewall for the AXI-stream protocol.  Only handles TVALID,
+//		TREADY, TDATA, TLAST and TUSER signals.
+//
+//	This module is designed to be a "bump in the stream" of the stream
+//	protocol--a bump that can be used to detect AXI stream errors.
+//	Specifically, this firewall can detect one of three errors:
+//
+//	1. CHANGE	The stream is stalled and something changes.  This
+//			could easily be caused by a stream overflow.
+//	2. PACKET LENGTH	If OPT_PACKET_LENGTH != 0, then all stream
+//			packets are assumed to be OPT_PACKET_LENGTH in length.
+//			Packets that are not OPT_PACKET_LENGTH in length will
+//			generate a fault.
+//
+//			This core cannot handle dynamic packet lengths, but
+//			should do just fine with detecting errors in fixed
+//			length packets--such as an FFT might use.
+//	3. TOO MANY STALLS
+//		If OPT_MAX_STALL != 0, and the master stalls an input more than
+//		OPT_MAX_STALL cycles, then a fault will be declared.
+//
+//	4. (Sorry--I haven't implemented a video firewall.  Video images
+//		having TUSER set to start of frame will not be guaranteed
+//		video stream compliant, since TUSER might still be set to the
+//		wrong number.)
+//
+//	If a fault is detected, o_fault will be set true.  This is designed so
+//	that you can trigger an ILA off of a protocol error, and then see what
+//	caused the fault.
+//
+//	If OPT_SELF_RESET is set, then o_fault will be self clearing.  Once
+//	a fault is detected, the current packet will be flushed, and the
+//	firewall will become idle (holding TREADY high) until S_AXIS_TVALID
+//	and S_AXIS_TLAST--marking the end of a broken packet.  This will
+//	resynchronize the core, following which packets may pass through again.
+//
+//	If you aren't using TLAST, set it to one.
+//
+//	If you aren't using TUSER, set the width to 1 and the input to a
+//	constant zero.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+`default_nettype none
+//
+// }}}
+module	axissafety #(
+		// {{{
+`ifdef	FORMAL
+		parameter [0:0]	F_OPT_FAULTLESS = 0,
+`endif
+		parameter	C_AXIS_DATA_WIDTH = 8,
+		parameter	C_AXIS_USER_WIDTH = 1,
+		parameter	OPT_MAX_STALL = 0,
+		parameter	OPT_PACKET_LENGTH = 0,
+		parameter [0:0]	OPT_SELF_RESET = 0,
+		localparam	LGPKTLEN = $clog2(OPT_PACKET_LENGTH+1)
+		// }}}
+	) (
+		// {{{
+		output	reg				o_fault,
+		input	wire				S_AXI_ACLK,
+		input	wire				S_AXI_ARESETN,
+		// AXI-stream slave (incoming) port
+		// {{{
+		input	wire				S_AXIS_TVALID,
+		output	wire				S_AXIS_TREADY,
+		input	wire	[C_AXIS_DATA_WIDTH-1:0]	S_AXIS_TDATA,
+		input	wire				S_AXIS_TLAST, // = 1,
+		input	wire	[C_AXIS_USER_WIDTH-1:0]	S_AXIS_TUSER, // = 0,
+		// }}}
+		// AXI-stream master (outgoing) port
+		// {{{
+		output	reg				M_AXIS_TVALID,
+		input	wire				M_AXIS_TREADY,
+		output	reg	[C_AXIS_DATA_WIDTH-1:0]	M_AXIS_TDATA,
+		output	reg				M_AXIS_TLAST,
+		output	reg	[C_AXIS_USER_WIDTH-1:0]	M_AXIS_TUSER
+		// }}}
+		// }}}
+	);
+
+	// Parameter/register declarations
+	// {{{
+	localparam	LGSTALLCOUNT = $clog2(OPT_MAX_STALL+1);
+	reg	skdr_valid, skd_valid, skd_ready;
+
+	reg	[C_AXIS_DATA_WIDTH+1+C_AXIS_USER_WIDTH-1:0]	idata,skdr_data;
+	reg	[C_AXIS_DATA_WIDTH-1:0]	skd_data;
+	reg	[C_AXIS_USER_WIDTH-1:0]	skd_user;
+	reg				skd_last;
+
+	reg	r_stalled;
+	reg	packet_fault, change_fault, stall_fault;
+	reg	[C_AXIS_DATA_WIDTH+1+C_AXIS_USER_WIDTH-1:0]	past_data;
+
+	reg	[LGSTALLCOUNT-1:0]	stall_count;
+	reg	[LGPKTLEN-1:0]		s_packet_counter;
+	reg	[LGPKTLEN-1:0]		m_packet_count;
+
+	reg				m_end_of_packet, m_idle;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Implement a skid buffer with no assumptions
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(*)
+		idata = { S_AXIS_TUSER, S_AXIS_TLAST, S_AXIS_TDATA };
+
+	initial	skdr_valid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		skdr_valid <= 0;
+	else if (S_AXIS_TVALID && S_AXIS_TREADY && (skd_valid && !skd_ready))
+		skdr_valid <= 1;
+	else if (skd_ready)
+		skdr_valid <= 0;
+
+	initial	skdr_data = 0;	// Allow data to be optimized away if always clr
+	always @(posedge S_AXI_ACLK)
+	if (S_AXIS_TVALID && S_AXIS_TREADY)
+		skdr_data <= idata;
+
+	always @(*)
+	if (S_AXIS_TREADY)
+		{ skd_user, skd_last, skd_data } = idata;
+	else
+		{ skd_user, skd_last, skd_data } = skdr_data;
+
+	always @(*)
+		skd_valid = S_AXIS_TVALID || skdr_valid;
+
+	assign	S_AXIS_TREADY = !skdr_valid;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Fault detection
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// r_stalled
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		r_stalled <= 0;
+	else
+		r_stalled <= (S_AXIS_TVALID && !S_AXIS_TREADY);
+	// }}}
+
+	// past_data
+	// {{{
+	always @(posedge S_AXI_ACLK)
+		past_data <= idata;
+	// }}}
+
+	always @(*)
+		change_fault = (r_stalled && (past_data != idata));
+
+	// packet_fault
+	// {{{
+	generate if (OPT_PACKET_LENGTH != 0)
+	begin : S_PACKET_COUNT
+		// {{{
+
+		// s_packet_counter
+		// {{{
+		initial	s_packet_counter = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			s_packet_counter <= 0;
+		else if (o_fault)
+			s_packet_counter <= 0;
+		else if (S_AXIS_TVALID && S_AXIS_TREADY)
+		begin
+			s_packet_counter <= s_packet_counter + 1;
+			if (S_AXIS_TLAST)
+				s_packet_counter <= 0;
+		end
+		// }}}
+
+		// packet_fault
+		// {{{
+		always @(*)
+		begin
+			packet_fault = (S_AXIS_TLAST
+				!= (s_packet_counter == OPT_PACKET_LENGTH-1));
+			if (!S_AXIS_TVALID)
+				packet_fault = 0;
+		end
+		// }}}
+		// }}}
+	end else begin
+		// {{{
+		always @(*)
+			packet_fault = 1'b0;
+		always @(*)
+			s_packet_counter = 0;
+
+		// Verilator lint_off UNUSED
+		wire	unused_pkt_counter;
+		assign	unused_pkt_counter = &{ 1'b0, s_packet_counter };
+		// Verilator lint_on  UNUSED
+		// }}}
+	end endgenerate
+	// }}}
+
+	// stall_fault
+	// {{{
+	generate if (OPT_MAX_STALL != 0)
+	begin : S_STALL_COUNT
+		// {{{
+
+		initial	stall_count = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			stall_count <= 0;
+		else if (!S_AXIS_TVALID || S_AXIS_TREADY)
+			stall_count <= 0;
+		else
+			stall_count <= stall_count + 1;
+
+		always @(*)
+			stall_fault = (stall_count > OPT_MAX_STALL);
+		// }}}
+	end else begin
+		// {{{
+		always @(*)
+			stall_fault = 0;
+
+		always @(*)
+			stall_count = 0;
+		// }}}
+	end endgenerate
+	// }}}
+
+	// o_fault
+	// {{{
+	initial	o_fault = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		o_fault   <= 0;
+	else if (!o_fault)
+		o_fault <= change_fault || stall_fault || packet_fault;
+	else if (OPT_SELF_RESET)
+	begin
+		if (skd_last && skd_ready && m_idle)
+			o_fault <= 1'b0;
+	end
+	// }}}
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The outgoing AXI-stream port
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// skd_ready
+	// {{{
+	always @(*)
+	if (!o_fault && !change_fault && !stall_fault && !packet_fault)
+		skd_ready = !M_AXIS_TVALID || M_AXIS_TREADY;
+	else if (!o_fault)
+		skd_ready = 1'b0;
+	else
+		skd_ready = 1'b1;
+	// }}}
+
+	// m_end_of_packet, m_packet_count
+	// {{{
+	generate if (OPT_PACKET_LENGTH != 0)
+	begin
+		// {{{
+		initial	m_packet_count = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			m_packet_count <= 0;
+		else if (M_AXIS_TVALID && M_AXIS_TREADY)
+		begin
+			m_packet_count <= m_packet_count + 1;
+			if (M_AXIS_TLAST)
+				m_packet_count <= 0;
+		end
+
+		// initial	m_end_of_packet = 0;
+		// always @(posedge S_AXI_ACLK)
+		// if (!S_AXI_ARESETN)
+		//	m_end_of_packet <= 0;
+		// else if (M_AXIS_TVALID && M_AXIS_TREADY)
+		//	m_end_of_packet <= (m_packet_count >= (OPT_PACKET_LENGTH-3));
+		always @(*)
+		begin
+			m_end_of_packet = (m_packet_count == (OPT_PACKET_LENGTH-1));
+			if (M_AXIS_TVALID)
+				m_end_of_packet = (m_packet_count == (OPT_PACKET_LENGTH-2));
+		end
+		// }}}
+	end else begin
+		// {{{
+		always @(*)
+			m_end_of_packet = 1'b1;
+		always @(*)
+			m_packet_count = 0;
+		// Verilator lint_off UNUSED
+		wire	unused_mpkt_counter;
+		assign	unused_mpkt_counter = &{ 1'b0, m_packet_count };
+		// Verilator lint_on  UNUSED
+		// }}}
+	end endgenerate
+
+	initial	m_idle = 1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		m_idle <= 1;
+	else if (!M_AXIS_TVALID || M_AXIS_TREADY)
+	begin
+		if (M_AXIS_TVALID && M_AXIS_TLAST)
+			m_idle <= o_fault || (!skd_valid || !skd_ready);
+		else if (m_idle && !o_fault)
+			m_idle <= (!skd_valid || !skd_ready);
+	end
+	// }}}
+
+	// M_AXIS_TVALID
+	// {{{
+	initial	M_AXIS_TVALID = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		M_AXIS_TVALID <= 1'b0;
+	else if (!M_AXIS_TVALID || M_AXIS_TREADY)
+	begin
+		M_AXIS_TVALID <= 1'b0;
+		if (!o_fault && skd_ready)
+			M_AXIS_TVALID <= skd_valid;
+		else if (o_fault)
+		begin
+			if (m_idle)
+				M_AXIS_TVALID <= 1'b0;
+			else if (!M_AXIS_TVALID || M_AXIS_TLAST)
+				M_AXIS_TVALID <= 1'b0;
+			else
+				M_AXIS_TVALID <= 1'b1;
+		end
+	end
+	// }}}
+
+	// M_AXIS_TUSER, M_AXIS_TLAST, M_AXIS_TDATA
+	// {{{
+	initial	{ M_AXIS_TUSER, M_AXIS_TLAST, M_AXIS_TDATA } <= 0;
+	always @(posedge S_AXI_ACLK)
+	begin
+		if (!M_AXIS_TVALID || M_AXIS_TREADY)
+		begin
+			if (o_fault || change_fault || packet_fault)
+			begin
+				{ M_AXIS_TUSER, M_AXIS_TLAST, M_AXIS_TDATA } <= 0;
+				// if (!M_AXIS_TLAST)
+				//	M_AXIS_TLAST <= m_end_of_packet;
+			end else
+				{ M_AXIS_TUSER, M_AXIS_TLAST, M_AXIS_TDATA }
+					<= { skd_user, skd_last, skd_data };
+
+			if (OPT_PACKET_LENGTH != 0)
+				M_AXIS_TLAST <= m_end_of_packet;
+			else if (o_fault && !m_idle)
+				M_AXIS_TLAST <= 1'b1;
+		end
+
+		if (!S_AXI_ARESETN)
+			M_AXIS_TLAST <= 0;
+	end
+	// }}}
+	// }}}
+
+	// Make Verilator happy
+	// {{{
+	// Verilator lint_off UNUSED
+	wire	unused = &{ 1'b0 };
+	// Verilator lint_on  UNUSED
+	// }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	reg	f_past_valid;
+	reg	[LGPKTLEN-1:0]		fm_packet_counter;
+	reg	[LGSTALLCOUNT-1:0]	fm_stall_count;
+
+	initial	f_past_valid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1'b1;
+
+	always @(*)
+	if (!f_past_valid)
+		assume(!S_AXI_ARESETN);
+
+	// Stability
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!f_past_valid || !$past(S_AXI_ARESETN))
+		assert(!M_AXIS_TVALID);
+	else if ($past(M_AXIS_TVALID && !M_AXIS_TREADY))
+	begin
+		assert(M_AXIS_TVALID);
+		assert($stable(M_AXIS_TDATA));
+		assert($stable(M_AXIS_TLAST));
+		assert($stable(M_AXIS_TUSER));
+	end
+	// }}}
+
+	// Packet counter, assertions on the output
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		fm_packet_counter <= 0;
+	else if (M_AXIS_TVALID && M_AXIS_TREADY)
+	begin
+		fm_packet_counter <= fm_packet_counter + 1;
+		if (M_AXIS_TLAST)
+			fm_packet_counter <= 0;
+	end
+
+	always @(*)
+	if (S_AXI_ARESETN && OPT_PACKET_LENGTH != 0)
+	begin
+		assert(fm_packet_counter < OPT_PACKET_LENGTH);
+		assert(M_AXIS_TLAST == (fm_packet_counter == OPT_PACKET_LENGTH-1));
+
+		assert(m_packet_count == fm_packet_counter);
+		if (!o_fault)
+		begin
+			if (skdr_valid && skd_last)
+			begin
+				assert(s_packet_counter == 0);
+				assert(m_packet_count == OPT_PACKET_LENGTH-2);
+			end else if (M_AXIS_TVALID && M_AXIS_TLAST)
+			begin
+				assert(s_packet_counter == (skdr_valid ? 1:0));
+				assert(m_packet_count == OPT_PACKET_LENGTH-1);
+			end else
+				assert(s_packet_counter == m_packet_count
+					+ (skdr_valid ? 1:0)
+					+ (M_AXIS_TVALID ? 1:0));
+		end
+	end
+
+	always @(*)
+	if (S_AXI_ARESETN && !o_fault && OPT_PACKET_LENGTH > 0)
+		assert(s_packet_counter < OPT_PACKET_LENGTH);
+
+	always @(*)
+	if (S_AXI_ARESETN && OPT_PACKET_LENGTH > 0)
+		assert(m_idle == (m_packet_count == 0 && !M_AXIS_TVALID));
+	// }}}
+
+	// Input stall counting
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		fm_stall_count <= 0;
+	else if (!S_AXIS_TVALID || S_AXIS_TREADY)
+		fm_stall_count <= 0;
+
+	always @(*)
+	if (S_AXI_ARESETN && OPT_MAX_STALL > 0)
+		assert(fm_stall_count < OPT_MAX_STALL);
+	// }}}
+	
+	generate if (F_OPT_FAULTLESS)
+	begin
+		// {{{
+		// Stall and stability properties
+		// {{{
+		always @(posedge S_AXI_ACLK)
+		if (!f_past_valid || !$past(S_AXI_ARESETN))
+			assume(!S_AXIS_TVALID);
+		else if ($past(S_AXIS_TVALID && !S_AXIS_TREADY))
+		begin
+			assume(S_AXIS_TVALID);
+			assume($stable(S_AXIS_TDATA));
+			assume($stable(S_AXIS_TLAST));
+			assume($stable(S_AXIS_TUSER));
+		end
+		// }}}
+
+		// f_packet_counter
+		// {{{
+		generate if (OPT_PACKET_LENGTH != 0)
+		begin
+			// {{{
+			reg	[LGPKTLEN-1:0]	fs_packet_counter;
+
+			always @(posedge S_AXI_ACLK)
+			if (!S_AXI_ARESETN)
+				fs_packet_counter <= 0;
+			else if (S_AXIS_TVALID && S_AXIS_TREADY)
+			begin
+				fs_packet_counter <= fs_packet_counter + 1;
+				if (S_AXIS_TLAST)
+					fs_packet_counter <= 0;
+			end
+
+			always @(*)
+			if (S_AXI_ARESETN)
+			begin
+				assert(s_packet_counter == fs_packet_counter);
+				if (skdr_valid && skd_last)
+					assert(s_packet_counter == 0);
+				else if (M_AXIS_TVALID && M_AXIS_TLAST)
+					assert(s_packet_counter == (skdr_valid ? 1:0));
+				else // if (!M_AXIS_TVALID && !M_AXIS_TLAST)
+					assert(s_packet_counter
+						== fm_packet_counter
+						+ (skdr_valid ? 1:0)
+						+ (M_AXIS_TVALID ? 1:0));
+			end
+
+			always @(*)
+			if (S_AXI_ARESETN && S_AXIS_TVALID)
+				assume(S_AXIS_TLAST == (fs_packet_counter == OPT_PACKET_LENGTH-1));
+			// }}}
+		end endgenerate
+		// }}}
+
+		// f_stall_count
+		// {{{
+		generate if (OPT_MAX_STALL != 0)
+		begin
+		// {{{
+			reg	[LGSTALLCOUNT-1:0]	f_stall_count;
+
+			initial	stall_count = 0;
+			always @(posedge S_AXI_ACLK)
+			if (!S_AXI_ARESETN)
+				f_stall_count <= 0;
+			else if (!S_AXIS_TVALID || S_AXIS_TREADY)
+				f_stall_count <= 0;
+			else
+				f_stall_count <= f_stall_count + 1;
+
+			always @(*)
+			if (S_AXI_ARESETN)
+				assert(stall_count == f_stall_count);
+
+			always @(*)
+				assume(f_stall_count <= OPT_MAX_STALL);
+		// }}}
+		end endgenerate
+		// }}}
+
+		always @(*)
+			assert(!o_fault);
+		// }}}
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+
+	generate if (F_OPT_FAULTLESS)
+	begin
+	end else begin
+
+		reg	cvr_stall_fault, cvr_packet_fault, cvr_change_fault,
+			cvr_last;
+
+		initial	cvr_last = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			cvr_last <= 1'b0;
+		else if (o_fault && $stable(o_fault)
+				&& $rose(M_AXIS_TVALID && M_AXIS_TLAST))
+			cvr_last <= 1'b1;
+
+		initial	cvr_change_fault = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			cvr_change_fault <= 1'b0;
+		else if (!o_fault && change_fault && !packet_fault && !stall_fault)
+			cvr_change_fault <= 1'b1;
+		else if (!o_fault)
+			cvr_change_fault <= 1'b0;
+
+		if (OPT_PACKET_LENGTH > 0)
+		begin
+			initial	cvr_packet_fault = 0;
+			always @(posedge S_AXI_ACLK)
+			if (!S_AXI_ARESETN)
+				cvr_packet_fault <= 1'b0;
+			else if (!o_fault && !change_fault && packet_fault && !stall_fault)
+				cvr_packet_fault <= 1'b1;
+			else if (!o_fault)
+				cvr_packet_fault <= 1'b0;
+
+			always @(posedge S_AXI_ACLK)
+			if (S_AXI_ARESETN && $past(S_AXI_ARESETN))
+			begin
+				cover($fell(o_fault) && cvr_packet_fault);
+				cover($fell(o_fault) && cvr_packet_fault && cvr_last);
+			end
+		end
+
+		if (OPT_MAX_STALL > 0)
+		begin
+			initial	cvr_stall_fault = 0;
+			always @(posedge S_AXI_ACLK)
+			if (!S_AXI_ARESETN)
+				cvr_stall_fault <= 1'b0;
+			else if (!o_fault && !change_fault && !packet_fault && stall_fault)
+				cvr_stall_fault <= 1'b1;
+			else if (!o_fault)
+				cvr_stall_fault <= 1'b0;
+
+			always @(posedge S_AXI_ACLK)
+			if (S_AXI_ARESETN && $past(S_AXI_ARESETN))
+			begin
+				cover($fell(o_fault) && cvr_stall_fault);
+				cover($fell(o_fault) && cvr_stall_fault && cvr_last);
+			end
+		end
+
+		always @(posedge S_AXI_ACLK)
+		if (S_AXI_ARESETN && $past(S_AXI_ARESETN))
+		begin
+			cover($fell(o_fault));
+			cover($fell(o_fault) && cvr_change_fault);
+			cover($fell(o_fault) && cvr_change_fault && cvr_last);
+		end
+
+	end endgenerate
+	// }}}
+`endif
+// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axisswitch.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axisswitch.v
new file mode 100644
index 0000000..02229f1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axisswitch.v
@@ -0,0 +1,616 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axisswitch.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Switch from among several AXI streams based upon an AXI-lite
+//		controlled index.  All streams must have the same width.
+//	The switch will use TLAST to guarantee that it will not change
+//	mid-packet.  If TLAST is unused for a particular input, simply set it
+//	to 1'b1.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+//
+`default_nettype none
+//
+module	axisswitch #(
+		// {{{
+		//
+		// Size of the AXI-lite bus.  These are fixed, since 1) AXI-lite
+		// is fixed at a width of 32-bits by Xilinx def'n, and 2) since
+		// we only ever have a single configuration words.
+		parameter	C_AXI_ADDR_WIDTH = 2,
+		localparam	C_AXI_DATA_WIDTH = 32,
+		//
+		parameter	NUM_STREAMS = 4,
+		parameter	C_AXIS_DATA_WIDTH = 32,
+		parameter [0:0]	OPT_LOWPOWER = 0,
+		//
+		localparam	LGNS = $clog2(NUM_STREAMS),
+		localparam	ADDRLSB = $clog2(C_AXI_DATA_WIDTH)-3
+		// }}}
+	) (
+		// {{{
+		input	wire					S_AXI_ACLK,
+		input	wire					S_AXI_ARESETN,
+		// AXI-Lite control
+		// {{{
+		input	wire					S_AXI_AWVALID,
+		output	wire					S_AXI_AWREADY,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]		S_AXI_AWADDR,
+		input	wire	[2:0]				S_AXI_AWPROT,
+		//
+		input	wire					S_AXI_WVALID,
+		output	wire					S_AXI_WREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]		S_AXI_WDATA,
+		input	wire	[C_AXI_DATA_WIDTH/8-1:0]	S_AXI_WSTRB,
+		//
+		output	wire					S_AXI_BVALID,
+		input	wire					S_AXI_BREADY,
+		output	wire	[1:0]				S_AXI_BRESP,
+		//
+		input	wire					S_AXI_ARVALID,
+		output	wire					S_AXI_ARREADY,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]		S_AXI_ARADDR,
+		input	wire	[2:0]				S_AXI_ARPROT,
+		//
+		output	wire					S_AXI_RVALID,
+		input	wire					S_AXI_RREADY,
+		output	wire	[C_AXI_DATA_WIDTH-1:0]		S_AXI_RDATA,
+		output	wire	[1:0]				S_AXI_RRESP,
+		// }}}
+		// AXI stream inputs to be switched
+		// {{{
+		input	wire	[NUM_STREAMS-1:0]		S_AXIS_TVALID,
+		output	wire	[NUM_STREAMS-1:0]		S_AXIS_TREADY,
+		input wire [NUM_STREAMS*C_AXIS_DATA_WIDTH-1:0]	S_AXIS_TDATA,
+		input	wire	[NUM_STREAMS-1:0]		S_AXIS_TLAST,
+		// }}}
+		// AXI stream output result
+		// {{{
+		output	reg					M_AXIS_TVALID,
+		input	wire					M_AXIS_TREADY,
+		output	reg	[C_AXIS_DATA_WIDTH-1:0]		M_AXIS_TDATA,
+		output	reg					M_AXIS_TLAST
+		// }}}
+		// }}}
+	);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Register/wire signal declarations
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	wire	i_reset = !S_AXI_ARESETN;
+
+	wire				axil_write_ready;
+	wire	[0:0]			awskd_addr;	// UNUSED
+	//
+	wire	[C_AXI_DATA_WIDTH-1:0]	wskd_data;
+	wire [C_AXI_DATA_WIDTH/8-1:0]	wskd_strb;
+	reg				axil_bvalid;
+	//
+	wire				axil_read_ready;
+	wire	[0:0]			arskd_addr;	// UNUSED
+	reg	[C_AXI_DATA_WIDTH-1:0]	axil_read_data;
+	reg				axil_read_valid;
+
+	reg	[LGNS-1:0]		r_index;
+	wire	[31:0]			wskd_index;
+
+	genvar	gk;
+	reg	[NUM_STREAMS-1:0]	skd_switch_ready;
+	reg	[LGNS-1:0]		switch_index;
+	wire	[C_AXIS_DATA_WIDTH-1:0]	skd_data	[0:NUM_STREAMS-1];
+	wire	[NUM_STREAMS-1:0]	skd_valid, skd_last;
+	reg				mid_packet, r_mid_packet;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite signaling
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// Write signaling
+	//
+	// {{{
+
+	wire	awskd_valid, wskd_valid;
+
+	skidbuffer #(.OPT_OUTREG(0),
+			.OPT_LOWPOWER(OPT_LOWPOWER), .DW(1))
+	axilawskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXI_AWVALID), .o_ready(S_AXI_AWREADY),
+		.i_data(1'b0),
+		.o_valid(awskd_valid), .i_ready(axil_write_ready),
+		.o_data(awskd_addr));
+
+	skidbuffer #(.OPT_OUTREG(0),
+			.OPT_LOWPOWER(OPT_LOWPOWER),
+			.DW(C_AXI_DATA_WIDTH+C_AXI_DATA_WIDTH/8))
+	axilwskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXI_WVALID), .o_ready(S_AXI_WREADY),
+		.i_data({ S_AXI_WDATA, S_AXI_WSTRB }),
+		.o_valid(wskd_valid), .i_ready(axil_write_ready),
+		.o_data({ wskd_data, wskd_strb }));
+
+	assign	axil_write_ready = awskd_valid && wskd_valid
+			&& (!S_AXI_BVALID || S_AXI_BREADY);
+
+	initial	axil_bvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		axil_bvalid <= 0;
+	else if (axil_write_ready)
+		axil_bvalid <= 1;
+	else if (S_AXI_BREADY)
+		axil_bvalid <= 0;
+
+	assign	S_AXI_BVALID = axil_bvalid;
+	assign	S_AXI_BRESP = 2'b00;
+	// }}}
+
+	//
+	// Read signaling
+	//
+	// {{{
+
+	wire	arskd_valid;
+
+	skidbuffer #(.OPT_OUTREG(0),
+			.OPT_LOWPOWER(OPT_LOWPOWER),
+			.DW(1))
+	axilarskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXI_ARVALID), .o_ready(S_AXI_ARREADY),
+		.i_data(1'b0),
+		.o_valid(arskd_valid), .i_ready(axil_read_ready),
+		.o_data(arskd_addr));
+
+	assign	axil_read_ready = arskd_valid
+				&& (!axil_read_valid || S_AXI_RREADY);
+
+	initial	axil_read_valid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		axil_read_valid <= 1'b0;
+	else if (axil_read_ready)
+		axil_read_valid <= 1'b1;
+	else if (S_AXI_RREADY)
+		axil_read_valid <= 1'b0;
+
+	assign	S_AXI_RVALID = axil_read_valid;
+	assign	S_AXI_RDATA  = axil_read_data;
+	assign	S_AXI_RRESP = 2'b00;
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite register logic
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// apply_wstrb(old_data, new_data, write_strobes)
+	// r_index, (wskd_index)
+	// {{{
+	assign	wskd_index = apply_wstrb(
+		{ {(C_AXI_DATA_WIDTH-LGNS){1'b0}}, r_index },
+		wskd_data, wskd_strb);
+
+	// r_index
+	initial	r_index = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		r_index <= 0;
+	else if (axil_write_ready)
+		r_index <= wskd_index[LGNS-1:0];
+	// }}}
+
+	// axil_read_data
+	// {{{
+	initial	axil_read_data = 0;
+	always @(posedge S_AXI_ACLK)
+	if (OPT_LOWPOWER && !S_AXI_ARESETN)
+		axil_read_data <= 0;
+	else if (!S_AXI_RVALID || S_AXI_RREADY)
+	begin
+		axil_read_data <= 0;
+		axil_read_data[LGNS-1:0] <= r_index;
+
+		if (OPT_LOWPOWER && !axil_read_ready)
+			axil_read_data <= 0;
+	end
+	// }}}
+
+	// function apply_wstrb
+	// {{{
+	function [C_AXI_DATA_WIDTH-1:0]	apply_wstrb;
+		input	[C_AXI_DATA_WIDTH-1:0]		prior_data;
+		input	[C_AXI_DATA_WIDTH-1:0]		new_data;
+		input	[C_AXI_DATA_WIDTH/8-1:0]	wstrb;
+
+		integer	k;
+		for(k=0; k<C_AXI_DATA_WIDTH/8; k=k+1)
+		begin
+			apply_wstrb[k*8 +: 8]
+				= wstrb[k] ? new_data[k*8 +: 8] : prior_data[k*8 +: 8];
+		end
+	endfunction
+	// }}}
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The actual AXI switch
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// Place a skidbuffer on every incoming stream input
+	// {{{
+	generate for(gk=0; gk<NUM_STREAMS; gk=gk+1)
+	begin
+		skidbuffer #(.OPT_OUTREG(0),
+				.OPT_LOWPOWER(OPT_LOWPOWER),
+				.DW(C_AXIS_DATA_WIDTH+1))
+		skdswitch(//
+			.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+			.i_valid(S_AXIS_TVALID[gk]),.o_ready(S_AXIS_TREADY[gk]),
+			.i_data({ S_AXIS_TDATA[gk*C_AXIS_DATA_WIDTH
+				+: C_AXIS_DATA_WIDTH], S_AXIS_TLAST[gk] }),
+			.o_valid(skd_valid[gk]), .i_ready(skd_switch_ready[gk]),
+			.o_data({ skd_data[gk], skd_last[gk] }));
+
+		
+	end endgenerate
+	// }}}
+
+	// skd_switch_ready
+	// {{{
+	always @(*)
+	begin
+		skd_switch_ready = (1<<switch_index);
+		if (M_AXIS_TVALID && !M_AXIS_TREADY)
+			skd_switch_ready = 0;
+		if (!mid_packet && r_index != switch_index)
+			skd_switch_ready = 0;
+	end
+	// }}}
+
+	// mid_packet -- are we currently within a packet or not
+	// {{{
+	initial	r_mid_packet = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		r_mid_packet <= 0;
+	else if (M_AXIS_TVALID)
+		r_mid_packet <= !M_AXIS_TLAST;
+
+	always @(*)
+	if (M_AXIS_TVALID)
+		mid_packet = !M_AXIS_TLAST;
+	else
+		mid_packet = r_mid_packet;
+	// }}}
+
+	// switch_index -- the current index of the skidbuffer switch
+	// {{{
+	initial	switch_index = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		switch_index <= 0;
+	else if (!mid_packet)
+		switch_index <= r_index;
+	// }}}
+
+	// M_AXIS_TVALID
+	// {{{
+	initial	M_AXIS_TVALID = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		M_AXIS_TVALID <= 1'b0;
+	else if (!M_AXIS_TVALID || M_AXIS_TREADY)
+		M_AXIS_TVALID <= |(skd_valid & skd_switch_ready);
+	// }}}
+
+	// M_AXIS_TDATA, M_AXIS_TLAST
+	// {{{
+	initial	M_AXIS_TDATA = 0;
+	initial	M_AXIS_TLAST = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN && OPT_LOWPOWER)
+	begin
+		M_AXIS_TDATA <= 0;
+		M_AXIS_TLAST <= 0;
+	end else if (!M_AXIS_TVALID || M_AXIS_TREADY)
+	begin
+		M_AXIS_TDATA <= skd_data[switch_index];
+		M_AXIS_TLAST <= skd_last[switch_index];
+
+		if (OPT_LOWPOWER && (skd_valid | skd_switch_ready) == 0)
+		begin
+			M_AXIS_TDATA <= 0;
+			M_AXIS_TLAST <= 0;
+		end
+	end
+	// }}}
+	
+	// }}}
+
+	// Make Verilator happy
+	// {{{
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, S_AXI_AWPROT, S_AXI_ARPROT,
+			S_AXI_ARADDR[ADDRLSB-1:0], awskd_addr, arskd_addr,
+			S_AXI_AWADDR[ADDRLSB-1:0], wskd_index };
+	// Verilator lint_on  UNUSED
+	// }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties used in verfiying this core
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	reg	f_past_valid;
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The AXI-lite control interface
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	localparam	F_AXIL_LGDEPTH = 4;
+	wire	[F_AXIL_LGDEPTH-1:0]	faxil_rd_outstanding,
+					faxil_wr_outstanding,
+					faxil_awr_outstanding;
+
+	faxil_slave #(
+		// {{{
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.F_LGDEPTH(F_AXIL_LGDEPTH),
+		.F_AXI_MAXWAIT(2),
+		.F_AXI_MAXDELAY(2),
+		.F_AXI_MAXRSTALL(3),
+		.F_OPT_COVER_BURST(4)
+		// }}}
+	) faxil(
+		// {{{
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXI_AWVALID),
+		.i_axi_awready(S_AXI_AWREADY),
+		.i_axi_awaddr( S_AXI_AWADDR),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot( S_AXI_AWPROT),
+		//
+		.i_axi_wvalid(S_AXI_WVALID),
+		.i_axi_wready(S_AXI_WREADY),
+		.i_axi_wdata( S_AXI_WDATA),
+		.i_axi_wstrb( S_AXI_WSTRB),
+		//
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+		.i_axi_bresp( S_AXI_BRESP),
+		//
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+		.i_axi_araddr( S_AXI_ARADDR),
+		.i_axi_arcache(4'h0),
+		.i_axi_arprot( S_AXI_ARPROT),
+		//
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rready(S_AXI_RREADY),
+		.i_axi_rdata( S_AXI_RDATA),
+		.i_axi_rresp( S_AXI_RRESP),
+		//
+		.f_axi_rd_outstanding(faxil_rd_outstanding),
+		.f_axi_wr_outstanding(faxil_wr_outstanding),
+		.f_axi_awr_outstanding(faxil_awr_outstanding)
+		// }}}
+		);
+
+	always @(*)
+	begin
+		assert(faxil_awr_outstanding== (S_AXI_BVALID ? 1:0)
+			+(S_AXI_AWREADY ? 0:1));
+		assert(faxil_wr_outstanding == (S_AXI_BVALID ? 1:0)
+			+(S_AXI_WREADY ? 0:1));
+
+		assert(faxil_rd_outstanding == (S_AXI_RVALID ? 1:0)
+			+(S_AXI_ARREADY ? 0:1));
+	end
+
+	always @(*)
+		assert(S_AXI_RDATA[C_AXI_DATA_WIDTH-1:LGNS] == 0);
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $past(S_AXI_ARESETN
+			&& axil_read_ready))
+	begin
+		assert(S_AXI_RVALID);
+		assert(S_AXI_RDATA[LGNS-1:0] == $past(r_index));
+	end
+
+	//
+	// Check that our low-power only logic works by verifying that anytime
+	// S_AXI_RVALID is inactive, then the outgoing data is also zero.
+	//
+	always @(*)
+	if (OPT_LOWPOWER && !S_AXI_RVALID)
+		assert(S_AXI_RDATA == 0);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI Stream properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// Stream properties are captured by the skid buffers, and so don't
+	// need to be repeated here.
+
+	always @(posedge S_AXI_ACLK)
+	if (!f_past_valid || $past(!S_AXI_ARESETN))
+		assert(!M_AXIS_TVALID);
+	else if ($past(M_AXIS_TVALID && !M_AXIS_TREADY))
+	begin
+		assert(M_AXIS_TVALID);
+		assert($stable(M_AXIS_TDATA));
+		assert($stable(M_AXIS_TLAST));
+	end
+
+	always @(*)
+	if (OPT_LOWPOWER && !M_AXIS_TVALID)
+	begin
+		assert(M_AXIS_TDATA == 0);
+		assert(M_AXIS_TLAST == 0);
+	end
+
+	(* anyconst *) reg [LGNS-1:0]		f_const_index;
+	(* anyconst *) reg [C_AXIS_DATA_WIDTH-1:0] f_never_data;
+		reg	[LGNS-1:0]		f_this_index;
+		reg	[3:0]			f_count, f_recount;
+		reg		f_accepts, f_delivers;
+
+	always @(*)
+		assume(f_const_index < NUM_STREAMS);
+
+	// f_this_index
+	// {{{
+	initial	f_this_index = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_this_index <= 1'b0;
+	else if (!M_AXIS_TVALID || M_AXIS_TREADY)
+		f_this_index <= switch_index;
+
+	always @(*)
+		assert(f_this_index < NUM_STREAMS);
+
+	always @(*)
+		assert(switch_index < NUM_STREAMS);
+	// }}}
+
+	// f_count
+	// {{{
+	always @(*)
+	begin
+		f_accepts = S_AXIS_TVALID[f_const_index]
+					&& S_AXIS_TREADY[f_const_index];
+		f_delivers = M_AXIS_TVALID && M_AXIS_TREADY
+					&& f_this_index == f_const_index;
+	end
+
+	initial	f_count = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_count <= 0;
+	else case( { f_accepts, f_delivers })
+	2'b01: f_count <= f_count - 1;
+	2'b10: f_count <= f_count + 1;
+	default: begin end
+	endcase
+	// }}}
+
+	// f_count induction
+	// {{{
+	always @(*)
+	begin
+		f_recount = 0;
+		if (!S_AXIS_TREADY[f_const_index])
+			f_recount = 1;
+		if (M_AXIS_TVALID && f_this_index == f_const_index)
+			f_recount = f_recount + 1;
+
+		assert(f_recount == f_count);
+	end
+	// }}}
+
+	// f_this_index induction
+	always @(*)
+	if (M_AXIS_TVALID && !M_AXIS_TLAST)
+		assert(f_this_index == switch_index);
+
+	// assume != f_never_data
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (S_AXIS_TVALID[f_const_index])
+		assume({ S_AXIS_TDATA[f_const_index * C_AXIS_DATA_WIDTH +: C_AXIS_DATA_WIDTH], S_AXIS_TLAST[f_const_index] } != f_never_data);
+	// }}}
+
+	// Never data induction
+	// {{{
+	always @(*)
+	begin
+		if (skd_valid[f_const_index])
+			assert({ skd_data[f_const_index], skd_last[f_const_index] } != f_never_data);
+		if (M_AXIS_TVALID && f_this_index == f_const_index)
+			assert({ M_AXIS_TDATA, M_AXIS_TLAST } != f_never_data);
+	end
+	// }}}
+
+	
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// While there are already cover properties in the formal property
+	// set above, you'll probably still want to cover something
+	// application specific here
+
+	// }}}
+`endif
+	// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axivcamera.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axivcamera.v
new file mode 100644
index 0000000..0b042b5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axivcamera.v
@@ -0,0 +1,1231 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axivcamera
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Reads a video frame from a source and writes the result to
+// {{{
+//		memory.
+// }}}
+// Registers:
+// {{{
+//   0:	FBUF_CONTROL and status
+//	bit 0: START(1)/STOP(0)
+//		Command the core to start by writing a '1' to this bit.  It
+//		will then remain busy/active until either you tell it to halt,
+//		or an error occurrs.
+//	bit 1: BUSY
+//	bit 2: ERR
+//		If the core receives a bus error, it assumes it has been
+//		inappropriately set up, sets this error bit and then halts.
+//		It will not start again until this bit is cleared.  Only a
+//		write to the control register with the ERR bit set will clear
+//		it.  (Don't do this unless you know what caused it to halt ...)
+//	bit 3: DIRTY
+//		If you update core parameters while it is running, the busy
+//		bit will be set.  This bit is an indication that the current
+//		configuration doesn't necessarily match the one you are reading
+//		out.  To clear DIRTY, deactivate the core, wait for it to be
+//		no longer busy, and then start it again.  This will also start
+//		it under the new configuration so the two match.
+//	bits 15-8: FRAMES
+//		Indicates the number of frames you want to copy.  Set this to
+//		0 to continuously copy, or a finite number to grab only that
+//		many frames.
+//
+//		As a feature, this isn't perhaps the most useful, since every
+//		frame will be written to the same location.  A more useful
+//		approach would be to increase the desired number of lines to
+//		(NLINES * NFRAMES), and then to either leave this number at zero
+//		or set it to one.
+//
+//   2:	FBUF_LINESTEP
+//		Controls the distance from one line to the next.  This is the
+//		value added to the address of the beginning of the line to get
+//		to the beginning of the next line.  This should nominally be
+//		equal to the number of bytes per line, although it doesn't
+//		need to be.
+//
+//		Any attempt to set this value to zero will simply copy the
+//		number of data bytes per line (rounded down to the neareset
+//		word) into this value.  This is a recommended approach to
+//		setting this value.
+//
+//   4:	FBUF_LINEBYTES
+//		This is the number of data bytes necessary to capture all of
+//		the video data in a line.  This value must be more than zero
+//		in order to activate the core.
+//
+//		At present, this core can only handle a number of bytes aligned
+//		with the word size of the bus.  To convert from bytes to words,
+//		round any fractional part upwards (i.e. ceil()).  The core
+//		will naturally round down internally.
+//
+//   6:	FBUF_NUMLINES
+//		The number of lines of active video data in a frame.  This
+//		number must be greater than zero in order to activate and
+//		operate the core.
+//
+//   8:	FBUF_ADDRESS
+//		The is the first address of video data in memory.  Each frame
+//		will start reading from this address.
+//
+//  12:	(reserved for the upper FBUF_ADDRESS)
+//
+// KNOWN ISSUES:
+//
+//	Does not support interlacing (yet).  (Interlacing is not on my "todo"
+//	  list, so it might take a while to get said support if you need it.)
+//
+//	Does not support unaligned addressing.  The frame buffer address, and
+//	  the line step, must all be word aligned.  While nothing is stopping
+//	  me from supporting unaligned addressing, it was such a pain to do the
+//	  last time that I might just hold off until I have a paying customer
+//	  who wants it.
+//
+//	Line bytes that include a fraction of a word are rounded down and not
+//	  up.
+//
+// }}}
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+// }}}
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+module	axivcamera #(
+		// {{{
+		parameter	C_AXI_ADDR_WIDTH = 32,
+		parameter	C_AXI_DATA_WIDTH = 32,
+		parameter	C_AXI_ID_WIDTH = 1,
+		//
+		// We support five 32-bit AXI-lite registers, requiring 5-bits
+		// of AXI-lite addressing
+		localparam	C_AXIL_ADDR_WIDTH = 4,
+		localparam	C_AXIL_DATA_WIDTH = 32,
+		//
+		// The bottom ADDRLSB bits of any AXI address are subword bits
+		localparam	ADDRLSB = $clog2(C_AXI_DATA_WIDTH)-3,
+		localparam	AXILLSB = $clog2(C_AXIL_DATA_WIDTH)-3,
+		//
+		// OPT_LGMAXBURST
+		parameter	OPT_LGMAXBURST = 8,
+		//
+		parameter [0:0]	DEF_ACTIVE_ON_RESET = 0,
+		parameter [15:0] DEF_LINES_PER_FRAME = 1024,
+		parameter [16-ADDRLSB-1:0] DEF_WORDS_PER_LINE  = (1280 * 32)/C_AXI_DATA_WIDTH,
+		//
+		// DEF_FRAMEADDR: the default AXI address of the frame buffer
+		// containing video memory.  Unless OPT_UNALIGNED is set, this
+		// should be aligned so that DEF_FRAMEADDR[ADDRLSB-1:0] == 0.
+		parameter [C_AXI_ADDR_WIDTH-1:0] DEF_FRAMEADDR = 0,
+		//
+		// The (log-based two of  the) size of the FIFO in words.
+		// I like to set this to the size of two AXI bursts, so that
+		// while one is being read out the second can be read in.  Can
+		// also be set larger if desired.
+		parameter	OPT_LGFIFO = OPT_LGMAXBURST+1,
+		localparam	LGFIFO = (OPT_LGFIFO < OPT_LGMAXBURST+1)
+						? OPT_LGMAXBURST+1 : OPT_LGFIFO,
+		//
+		// AXI_ID is the ID we will use for all of our AXI transactions
+		parameter	AXI_ID = 0,
+		//
+		// OPT_IGNORE_HLAST
+		parameter [0:0]	OPT_IGNORE_HLAST = 0,
+		//
+		// OPT_TUSER_IS_SOF.  Xilinx and I chose different encodings.
+		// I encode TLAST == VLAST, and TUSER == HLAST (optional).
+		// Xilinx likes TLAST == HLAST and TUSER == SOF (start of frame)
+		// Set OPT_TUSER_IS_SOF to use Xilinx's encoding
+		parameter [0:0]	OPT_TUSER_IS_SOF = 0
+		// }}}
+	) (
+		// {{{
+		input	wire					S_AXI_ACLK,
+		input	wire					S_AXI_ARESETN,
+		//
+		// The incoming video stream data/pixel interface
+		// {{{
+		input	wire					S_AXIS_TVALID,
+		output	wire					S_AXIS_TREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]		S_AXIS_TDATA,
+		input	wire	/* VLAST */			S_AXIS_TLAST,
+		input	wire	/* HLAST */			S_AXIS_TUSER,
+		// }}}
+		//
+		// The control interface
+		// {{{
+		input	wire					S_AXIL_AWVALID,
+		output	wire					S_AXIL_AWREADY,
+		input	wire	[C_AXIL_ADDR_WIDTH-1:0]		S_AXIL_AWADDR,
+		input	wire	[2:0]				S_AXIL_AWPROT,
+		//
+		input	wire					S_AXIL_WVALID,
+		output	wire					S_AXIL_WREADY,
+		input	wire	[C_AXIL_DATA_WIDTH-1:0]		S_AXIL_WDATA,
+		input	wire	[C_AXIL_DATA_WIDTH/8-1:0]	S_AXIL_WSTRB,
+		//
+		output	wire					S_AXIL_BVALID,
+		input	wire					S_AXIL_BREADY,
+		output	wire	[1:0]				S_AXIL_BRESP,
+		//
+		input	wire					S_AXIL_ARVALID,
+		output	wire					S_AXIL_ARREADY,
+		input	wire	[C_AXIL_ADDR_WIDTH-1:0]		S_AXIL_ARADDR,
+		input	wire	[2:0]				S_AXIL_ARPROT,
+		//
+		output	wire					S_AXIL_RVALID,
+		input	wire					S_AXIL_RREADY,
+		output	wire	[C_AXIL_DATA_WIDTH-1:0]		S_AXIL_RDATA,
+		output	wire	[1:0]				S_AXIL_RRESP,
+		// }}}
+		//
+
+		//
+		// The AXI (full) write-only interface
+		// {{{
+		output	wire				M_AXI_AWVALID,
+		input	wire				M_AXI_AWREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_AWID,
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_AWADDR,
+		output	wire	[7:0]			M_AXI_AWLEN,
+		output	wire	[2:0]			M_AXI_AWSIZE,
+		output	wire	[1:0]			M_AXI_AWBURST,
+		output	wire				M_AXI_AWLOCK,
+		output	wire	[3:0]			M_AXI_AWCACHE,
+		output	wire	[2:0]			M_AXI_AWPROT,
+		output	wire	[3:0]			M_AXI_AWQOS,
+		//
+		output	wire				M_AXI_WVALID,
+		input	wire				M_AXI_WREADY,
+		output	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_WDATA,
+		output	wire [C_AXI_DATA_WIDTH/8-1:0]	M_AXI_WSTRB,
+		output	wire				M_AXI_WLAST,
+		//
+		input	wire				M_AXI_BVALID,
+		output	wire				M_AXI_BREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_BID,
+		input	wire	[1:0]			M_AXI_BRESP
+		// }}}
+		// }}}
+	);
+
+	// Core logic implementation
+	// {{{
+	// Local parameter declarations
+	// {{{
+	localparam [1:0]	FBUF_CONTROL	= 2'b00,
+				FBUF_FRAMEINFO	= 2'b01,
+				FBUF_ADDRLO	= 2'b10,
+				FBUF_ADDRHI	= 2'b11;
+
+	localparam		CBIT_ACTIVE	= 0,
+				CBIT_BUSY	= 1,
+				CBIT_ERR	= 2,
+				// CBIT_DIRTY	= 3,
+				CBIT_LOST_SYNC  = 4;
+
+	localparam	TMPLGMAXBURST=(LGFIFO-1 > OPT_LGMAXBURST)
+					? OPT_LGMAXBURST : LGFIFO-1;
+
+	localparam	LGMAXBURST = (TMPLGMAXBURST+ADDRLSB > 12)
+				? (12-ADDRLSB) : TMPLGMAXBURST;
+
+	localparam [ADDRLSB-1:0] LSBZEROS = 0;
+	// }}}
+
+	wire	i_clk   =  S_AXI_ACLK;
+	wire	i_reset = !S_AXI_ARESETN;
+
+	// Signal declarations
+	// {{{
+	reg				soft_reset, r_err, r_stopped, lost_sync;
+	reg				cfg_active, cfg_zero_length,
+					cfg_continuous;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	cfg_frame_addr;
+	reg	[15:0]			cfg_frame_lines, cfg_line_step;
+	reg	[16-ADDRLSB-1:0]	cfg_line_words;
+
+	// FIFO signals
+	wire				reset_fifo, write_to_fifo,
+					read_from_fifo;
+	wire	[C_AXI_DATA_WIDTH-1:0]	write_data, fifo_data;
+	wire	[LGFIFO:0]		fifo_fill;
+	wire				fifo_full, fifo_empty,
+					fifo_vlast, fifo_hlast;
+
+	wire				awskd_valid, axil_write_ready;
+	wire	[C_AXIL_ADDR_WIDTH-AXILLSB-1:0]	awskd_addr;
+	//
+	wire				wskd_valid;
+	wire	[C_AXIL_DATA_WIDTH-1:0]	wskd_data;
+	wire [C_AXIL_DATA_WIDTH/8-1:0]	wskd_strb;
+	reg				axil_bvalid;
+	//
+	wire				arskd_valid, axil_read_ready;
+	wire	[C_AXIL_ADDR_WIDTH-AXILLSB-1:0]	arskd_addr;
+	reg	[C_AXIL_DATA_WIDTH-1:0]	axil_read_data;
+	reg				axil_read_valid;
+	reg	[C_AXIL_DATA_WIDTH-1:0]	w_status_word;
+	reg	[2*C_AXIL_DATA_WIDTH-1:0]	wide_address, new_wideaddr;
+	wire	[C_AXIL_DATA_WIDTH-1:0]	new_cmdaddrlo, new_cmdaddrhi;
+	reg	[C_AXIL_DATA_WIDTH-1:0]	wide_config;
+	wire	[C_AXIL_DATA_WIDTH-1:0]	new_config;
+
+	reg	axi_awvalid, axi_wvalid, axi_wlast,
+					phantom_start, start_burst,
+					aw_none_outstanding;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	axi_awaddr;
+	reg	[7:0]			axi_awlen, next_awlen;
+	reg	[8:0]			wr_pending;
+	reg	[15:0]			aw_bursts_outstanding;
+	//
+	// reg				vlast;
+	// reg	[15:0]			r_frame_lines, r_line_step;
+	reg	[16-ADDRLSB-1:0]	next_line_words;
+
+	reg				req_hlast, req_vlast, req_newline;
+	reg	[15:0]			req_nlines;
+	reg	[7:0]			req_nframes;
+	reg	[16-ADDRLSB-1:0]	req_line_words;
+	reg	[C_AXI_ADDR_WIDTH:0]	req_addr, req_line_addr, next_line_addr;
+	//
+	reg				wr_hlast, wr_vlast;
+	reg	[15:0]			wr_lines;
+	reg	[16-ADDRLSB-1:0]	wr_line_beats;
+	// wire				no_fifo__available;
+	//
+	reg	[LGMAXBURST-1:0]	till_boundary;
+	reg	[LGFIFO:0]		fifo_data_available;
+	reg				fifo_bursts_available;
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite signaling
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// This is mostly the skidbuffer logic, and handling of the VALID
+	// and READY signals for the AXI-lite control logic in the next
+	// section.
+	// {{{
+
+	//
+	// Write signaling
+	//
+	// {{{
+
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_ADDR_WIDTH-AXILLSB))
+	axilawskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_AWVALID), .o_ready(S_AXIL_AWREADY),
+		.i_data(S_AXIL_AWADDR[C_AXIL_ADDR_WIDTH-1:AXILLSB]),
+		.o_valid(awskd_valid), .i_ready(axil_write_ready),
+		.o_data(awskd_addr));
+
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_DATA_WIDTH+C_AXIL_DATA_WIDTH/8))
+	axilwskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_WVALID), .o_ready(S_AXIL_WREADY),
+		.i_data({ S_AXIL_WDATA, S_AXIL_WSTRB }),
+		.o_valid(wskd_valid), .i_ready(axil_write_ready),
+		.o_data({ wskd_data, wskd_strb }));
+
+	assign	axil_write_ready = awskd_valid && wskd_valid
+			&& (!S_AXIL_BVALID || S_AXIL_BREADY);
+
+	initial	axil_bvalid = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		axil_bvalid <= 0;
+	else if (axil_write_ready)
+		axil_bvalid <= 1;
+	else if (S_AXIL_BREADY)
+		axil_bvalid <= 0;
+
+	assign	S_AXIL_BVALID = axil_bvalid;
+	assign	S_AXIL_BRESP = 2'b00;
+	// }}}
+
+	//
+	// Read signaling
+	//
+	// {{{
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_ADDR_WIDTH-AXILLSB))
+	axilarskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_ARVALID), .o_ready(S_AXIL_ARREADY),
+		.i_data(S_AXIL_ARADDR[C_AXIL_ADDR_WIDTH-1:AXILLSB]),
+		.o_valid(arskd_valid), .i_ready(axil_read_ready),
+		.o_data(arskd_addr));
+
+	assign	axil_read_ready = arskd_valid
+				&& (!axil_read_valid || S_AXIL_RREADY);
+
+	initial	axil_read_valid = 1'b0;
+	always @(posedge i_clk)
+	if (i_reset)
+		axil_read_valid <= 1'b0;
+	else if (axil_read_ready)
+		axil_read_valid <= 1'b1;
+	else if (S_AXIL_RREADY)
+		axil_read_valid <= 1'b0;
+
+	assign	S_AXIL_RVALID = axil_read_valid;
+	assign	S_AXIL_RDATA  = axil_read_data;
+	assign	S_AXIL_RRESP = 2'b00;
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite controlled logic
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// soft_reset,  r_err
+	// {{{
+	initial	soft_reset = 1;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		soft_reset <= 1;
+		r_err  <= 0;
+	end else if (r_stopped)
+	begin
+
+		if (axil_write_ready && awskd_addr == FBUF_CONTROL
+				&& wskd_strb[0] && wskd_data[CBIT_ERR])
+		begin
+			r_err <= cfg_zero_length;
+			soft_reset <= 0;
+		end
+
+		if (!r_err)
+			soft_reset <= 0;
+
+	end else // if (!soft_reset)
+	begin
+		// Halt on any bus error.  We'll require user intervention
+		// to start back up again
+		if ((M_AXI_BVALID && M_AXI_BREADY && M_AXI_BRESP[1])
+			||(req_addr[C_AXI_ADDR_WIDTH]))
+		begin
+			soft_reset <= 1;
+			r_err  <= 1;
+		end
+
+		// Halt on any user request
+		if (!cfg_active)
+			soft_reset <= 1;
+	end
+	// }}}
+
+	// wide_* and new_* write setup registers
+	// {{{
+	always @(*)
+	begin
+		wide_address = 0;
+		wide_address[C_AXI_ADDR_WIDTH-1:0] = cfg_frame_addr;
+		wide_address[ADDRLSB-1:0] = 0;
+
+		wide_config  = { cfg_frame_lines, cfg_line_words,
+					{(ADDRLSB){1'b0}} };
+	end
+
+	assign	new_cmdaddrlo = apply_wstrb(
+			wide_address[C_AXIL_DATA_WIDTH-1:0],
+			wskd_data, wskd_strb);
+
+	generate if (C_AXI_ADDR_WIDTH > 32)
+	begin
+
+		assign	new_cmdaddrhi = apply_wstrb(
+			wide_address[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH],
+			wskd_data, wskd_strb);
+
+	end else begin
+
+		assign	new_cmdaddrhi = 0;
+
+	end endgenerate
+
+
+	wire	[C_AXIL_DATA_WIDTH-1:0]	new_control;
+	assign	new_control = apply_wstrb(w_status_word, wskd_data, wskd_strb);
+	assign	new_config  = apply_wstrb(wide_config, wskd_data, wskd_strb);
+
+	always @(*)
+	begin
+		new_wideaddr = wide_address;
+
+		if (awskd_addr == FBUF_ADDRLO)
+			new_wideaddr[C_AXIL_DATA_WIDTH-1:0] = new_cmdaddrlo;
+		if (awskd_addr == FBUF_ADDRHI)
+			new_wideaddr[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH] = new_cmdaddrhi;
+		new_wideaddr[ADDRLSB-1:0] = 0;
+		new_wideaddr[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH] = 0;
+	end
+	// }}}
+
+	// Configuration registers (Write)
+	// {{{
+	initial	cfg_active      = 0;
+	initial	cfg_continuous  = 0;
+	initial	cfg_frame_addr  = DEF_FRAMEADDR;
+	initial	cfg_frame_addr[ADDRLSB-1:0] = 0;
+	initial	cfg_line_words = DEF_WORDS_PER_LINE;
+	initial	cfg_frame_lines = DEF_LINES_PER_FRAME;
+	initial	cfg_zero_length = (DEF_WORDS_PER_LINE == 0)
+				||(DEF_LINES_PER_FRAME == 0);
+	initial	cfg_line_step	= { DEF_WORDS_PER_LINE, {(ADDRLSB){1'b0}} };
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		cfg_active	<= DEF_ACTIVE_ON_RESET;
+		cfg_frame_addr	<= DEF_FRAMEADDR;
+		cfg_line_words	<= DEF_WORDS_PER_LINE;
+		cfg_line_step	<= { DEF_WORDS_PER_LINE, {(ADDRLSB){1'b0}} };
+		cfg_frame_lines	<= DEF_LINES_PER_FRAME;
+		cfg_zero_length <= (DEF_WORDS_PER_LINE==0)
+			||(DEF_LINES_PER_FRAME == 0);
+		req_nframes     <= 0;
+		cfg_continuous  <= 0;
+	end else begin
+		if (phantom_start && req_vlast && req_hlast && req_nframes > 0)
+			req_nframes <= req_nframes - 1;
+
+		if (axil_write_ready)
+		case(awskd_addr)
+		FBUF_CONTROL: begin
+			if (wskd_strb[0])
+				cfg_active <= (cfg_active || r_stopped)
+					&& wskd_data[CBIT_ACTIVE]
+					&& (!r_err || wskd_data[CBIT_ERR])
+					&& (!cfg_zero_length);
+
+			if (!cfg_active && r_stopped && wskd_strb[1])
+			begin
+				req_nframes    <= wskd_data[15:8];
+				cfg_continuous <= (wskd_data[15:8] == 0);
+			end
+
+			if (!cfg_active && r_stopped)
+			begin
+				if (new_control[31:16] == 0)
+				begin
+					cfg_line_step <= 0;
+					cfg_line_step[16-1:ADDRLSB] <= cfg_line_words;
+				end else
+					cfg_line_step <= new_control[31:16];
+			end end
+		FBUF_FRAMEINFO:
+			if (!cfg_active && r_stopped)
+			begin
+			{ cfg_frame_lines, cfg_line_words }
+				<= new_config[C_AXIL_DATA_WIDTH-1:ADDRLSB];
+			cfg_zero_length <= (new_config[31:16] == 0)
+					||(new_config[15:ADDRLSB] == 0);
+			end
+		FBUF_ADDRLO, FBUF_ADDRHI: if (!cfg_active && r_stopped)
+			cfg_frame_addr <= new_wideaddr[C_AXI_ADDR_WIDTH-1:0];
+		default: begin end
+		endcase
+
+		if (M_AXI_BREADY && M_AXI_BVALID && M_AXI_BRESP[1])
+			cfg_active <= 0;
+		if (req_addr[C_AXI_ADDR_WIDTH])
+			cfg_active <= 0;
+		if (phantom_start && req_vlast && req_hlast && req_nframes <= 1
+				&& !cfg_continuous)
+			cfg_active <= 0;
+
+		cfg_line_step[ADDRLSB-1:0] <= 0;
+		cfg_frame_addr[ADDRLSB-1:0] <= 0;
+	end
+	// }}}
+
+	// AXI-Lite read register data
+	// {{{
+	always @(*)
+	begin
+		w_status_word = 0;
+		w_status_word[31:16]		= cfg_line_step;
+		w_status_word[15:8]		= req_nframes;
+		w_status_word[CBIT_LOST_SYNC]	= lost_sync;
+		// w_status_word[CBIT_DIRTY]	= cfg_dirty;
+		w_status_word[CBIT_ERR]		= r_err;
+		w_status_word[CBIT_BUSY]	= !soft_reset;
+		w_status_word[CBIT_ACTIVE]	= cfg_active || (!soft_reset || !r_stopped);
+	end
+
+	always @(posedge i_clk)
+	if (!axil_read_valid || S_AXIL_RREADY)
+	begin
+		axil_read_data <= 0;
+		case(arskd_addr)
+		FBUF_CONTROL:	axil_read_data <= w_status_word;
+		FBUF_FRAMEINFO:	axil_read_data <= { cfg_frame_lines,
+					cfg_line_words, {(ADDRLSB){1'b0}} };
+		FBUF_ADDRLO:	axil_read_data <= wide_address[C_AXIL_DATA_WIDTH-1:0];
+		FBUF_ADDRHI:	axil_read_data <= wide_address[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+		default		axil_read_data <= 0;
+		endcase
+	end
+	// }}}
+
+	// apply_wstrb function for applying wstrbs to register words
+	// {{{
+	function [C_AXIL_DATA_WIDTH-1:0]	apply_wstrb;
+		input	[C_AXIL_DATA_WIDTH-1:0]		prior_data;
+		input	[C_AXIL_DATA_WIDTH-1:0]		new_data;
+		input	[C_AXIL_DATA_WIDTH/8-1:0]	wstrb;
+
+		integer	k;
+		for(k=0; k<C_AXIL_DATA_WIDTH/8; k=k+1)
+		begin
+			apply_wstrb[k*8 +: 8]
+				= wstrb[k] ? new_data[k*8 +: 8] : prior_data[k*8 +: 8];
+		end
+	endfunction
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The data FIFO section
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	reg	S_AXIS_SOF, S_AXIS_HLAST, S_AXIS_VLAST;
+	generate if (OPT_TUSER_IS_SOF)
+	begin : XILINX_SOF_LOCK
+		reg	[15:0]	axis_line;
+		reg		axis_last_line;
+
+		always @(*)
+			S_AXIS_HLAST = S_AXIS_TLAST;
+
+		always @(*)
+			S_AXIS_SOF = S_AXIS_TUSER;
+
+		//  Generate S_AXIS_VLAST from S_AXIS_SOF
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			axis_line <= 0;
+		else if (S_AXIS_TVALID && S_AXIS_TREADY)
+		begin
+			if (S_AXIS_SOF)
+				axis_line <= 0;
+			else if (S_AXIS_HLAST)
+				axis_line <= axis_line + 1;
+		end
+
+		always @(posedge S_AXI_ACLK)
+			axis_last_line <= (axis_line+1 >= cfg_frame_lines);
+
+		always @(*)
+			S_AXIS_VLAST = axis_last_line && S_AXIS_HLAST;
+
+	end else begin : VLAST_LOCK
+
+		always @(*)
+			S_AXIS_VLAST = S_AXIS_TLAST;
+
+		always @(*)
+			S_AXIS_HLAST = S_AXIS_TUSER;
+
+		/*
+		initial	S_AXIS_SOF = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			S_AXIS_SOF <= 1'b0;
+		else if (S_AXIS_TVALID && S_AXIS_TREADY)
+			S_AXIS_SOF <= S_AXIS_VLAST;
+		*/
+		always @(*)
+			S_AXIS_SOF = 1'b0;
+
+		// Verilator lint_off UNUSED
+		wire	unused_sof;
+		assign	unused_sof = &{ 1'b0, S_AXIS_SOF };
+		// Verilator lint_on  UNUSED
+	end endgenerate
+
+	// Read/write signaling, lost_sync detection
+	// {{{
+	assign	reset_fifo = (!cfg_active || r_stopped || lost_sync);
+
+	assign	write_to_fifo  = S_AXIS_TVALID && !lost_sync && !fifo_full;
+	assign	write_data = S_AXIS_TDATA;
+	assign	read_from_fifo = (M_AXI_WVALID && M_AXI_WREADY);
+	assign	S_AXIS_TREADY  = 1'b1;
+
+	initial	lost_sync = 1;
+	always @(posedge S_AXI_ACLK)
+	begin
+		if (!S_AXI_ARESETN || !cfg_active || r_stopped)
+			lost_sync <= 0;
+		else if (M_AXI_WVALID && M_AXI_WREADY
+				&&((!OPT_IGNORE_HLAST&&(wr_hlast != fifo_hlast))
+				|| (!wr_hlast && fifo_vlast)
+				|| (wr_vlast && wr_hlast && !fifo_vlast)))
+			// Here is where we might possibly notice we've lost sync
+			lost_sync <= 1;
+
+		// lost_sync <= 1'b0;
+	end
+	// }}}
+
+	generate if (LGFIFO > 0)
+	begin : GEN_SPACE_AVAILBLE
+		// Here's where  we'll put the actual outgoing FIFO
+		// {{{
+		reg	[LGFIFO:0]	next_data_available;
+		always @(*)
+		begin
+			next_data_available = fifo_data_available;
+			// Verilator lint_off WIDTH
+			if (phantom_start)
+				next_data_available = fifo_data_available - (M_AXI_AWLEN + 1);
+			// Verilator lint_on  WIDTH
+			if (write_to_fifo)
+				next_data_available = next_data_available + 1;
+		end
+
+		initial	fifo_data_available = 0;
+		initial	fifo_bursts_available = 0;
+		always @(posedge i_clk)
+		if (reset_fifo)
+		begin
+			fifo_data_available <= 0;
+			fifo_bursts_available <= 0;
+		end else if (phantom_start || write_to_fifo)
+		begin
+			fifo_data_available   <=  next_data_available;
+			fifo_bursts_available <= |next_data_available[LGFIFO:LGMAXBURST];
+		end
+
+		sfifo #(.BW(C_AXI_DATA_WIDTH+2), .LGFLEN(LGFIFO))
+		sfifo(i_clk, reset_fifo,
+			write_to_fifo, { S_AXIS_VLAST,
+				(!OPT_IGNORE_HLAST && S_AXIS_HLAST),write_data},
+				fifo_full, fifo_fill,
+			read_from_fifo, { fifo_vlast, fifo_hlast,
+				fifo_data }, fifo_empty);
+		// }}}
+	end else begin : NO_FIFO
+		// {{{
+		//
+		// This isn't verified or tested.  I'm not sure I'd expect this
+		// to work at all.
+		assign	fifo_full  = M_AXI_WVALID && !M_AXI_WREADY;
+		assign	fifo_fill  = 0;
+		assign	fifo_empty = !S_AXIS_TVALID;
+		assign	fifo_vlast = S_AXIS_VLAST;
+		assign	fifo_hlast = (!OPT_IGNORE_HLAST && S_AXIS_HLAST);
+
+		assign	fifo_data = write_data;
+		// }}}
+	end endgenerate
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Outoing frame address counting
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	w_frame_needs_alignment, frame_needs_alignment,
+		line_needs_alignment,
+		line_multiple_bursts, req_needs_alignment, req_multiple_bursts;
+
+	// frame_needs_alignment
+	// {{{
+	always @(*)
+	begin
+		w_frame_needs_alignment = 0;
+		if (|cfg_line_words[15-ADDRLSB:LGMAXBURST])
+			w_frame_needs_alignment = 1;
+		if (~cfg_frame_addr[ADDRLSB +: LGMAXBURST]
+				< cfg_line_words[LGMAXBURST-1:0])
+			w_frame_needs_alignment = 1;
+		if (cfg_frame_addr[ADDRLSB +: LGMAXBURST] == 0)
+			w_frame_needs_alignment = 0;
+	end
+
+	always @(posedge i_clk)
+	if (!cfg_active && r_stopped)
+		frame_needs_alignment <= w_frame_needs_alignment;
+	// }}}
+
+	// line_needs_alignment
+	// {{{
+	always @(posedge i_clk)
+	if (r_stopped)
+		line_multiple_bursts <= (cfg_line_words >= (1<<LGMAXBURST));
+
+	always @(*)
+	if (!cfg_active || req_vlast)
+		next_line_addr = { 1'b0, cfg_frame_addr };
+	else
+		next_line_addr = req_line_addr+ { {(C_AXI_ADDR_WIDTH-16){1'b0}}, cfg_line_step };
+
+	always @(posedge i_clk)
+	if (req_newline)
+	begin
+		line_needs_alignment <= 0;
+		if (|next_line_addr[ADDRLSB +: LGMAXBURST])
+		begin
+			if (|cfg_line_words[15-ADDRLSB:LGMAXBURST])
+				line_needs_alignment <= 1;
+			if (~next_line_addr[ADDRLSB +: LGMAXBURST]
+					< cfg_line_words[LGMAXBURST-1:0])
+				line_needs_alignment <= 1;
+		end
+	end
+	// }}}
+
+	// req_addr, req_line_addr, req_line_words
+	// {{{
+	always @(*)
+		// Verilator lint_off WIDTH
+		next_line_words = req_line_words - (M_AXI_AWLEN+1);
+		// Verilator lint_on  WIDTH
+
+	initial	req_addr = 0;
+	initial	req_line_addr = 0;
+	always @(posedge  i_clk)
+	if (i_reset || r_stopped)
+	begin
+		req_addr       <= { 1'b0, cfg_frame_addr };
+		req_line_addr  <= { 1'b0, cfg_frame_addr };
+		req_line_words <= cfg_line_words;
+		req_newline    <= 1;
+		req_multiple_bursts <= (cfg_line_words >= (1<<LGMAXBURST));
+		req_needs_alignment <= w_frame_needs_alignment;
+	end else if (phantom_start)
+	begin
+		req_newline <= req_hlast;
+		req_needs_alignment <= 0;
+		if (req_hlast && req_vlast)
+		begin
+			req_addr       <= { 1'b0, cfg_frame_addr };
+			req_line_addr  <= { 1'b0, cfg_frame_addr };
+			req_line_words <= cfg_line_words;
+			req_multiple_bursts <= line_multiple_bursts;
+
+			req_needs_alignment <= frame_needs_alignment;
+		end else if (req_hlast)
+		begin
+			// verilator lint_off WIDTH
+			req_addr <= req_line_addr + cfg_line_step;
+			req_line_addr  <= req_line_addr + cfg_line_step;
+			// verilator lint_on WIDTH
+			req_line_words <= cfg_line_words;
+			req_needs_alignment <= line_needs_alignment;
+			req_multiple_bursts <= line_multiple_bursts;
+		end else begin
+			req_addr <= req_addr + (1<<(LGMAXBURST+ADDRLSB));
+			req_line_words <= next_line_words;
+			req_multiple_bursts <= |next_line_words[15-ADDRLSB:LGMAXBURST];
+
+			req_addr[LGMAXBURST+ADDRLSB-1:0] <= 0;
+		end
+	end else
+		req_newline <= 0;
+	// }}}
+
+	// req_nlines, req_vlast
+	// {{{
+	always @(posedge  i_clk)
+	if (i_reset || r_stopped)
+	begin
+		req_nlines <= cfg_frame_lines-1;
+		req_vlast <= (cfg_frame_lines <= 1);
+	end else if (phantom_start && req_hlast)
+	begin
+		if (req_vlast)
+		begin
+			req_nlines <= cfg_frame_lines-1;
+			req_vlast <= (cfg_frame_lines <= 1);
+		end else begin
+			req_nlines <= req_nlines - 1;
+			req_vlast <= (req_nlines <= 1);
+		end
+	end
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Outgoing sync counting
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// wr_line_beats, wr_hlast
+	// {{{
+	always @(posedge i_clk)
+	if (i_reset || r_stopped)
+	begin
+		wr_line_beats <= cfg_line_words-1;
+		wr_hlast <= (cfg_line_words == 1);
+	end else if (M_AXI_WVALID && M_AXI_WREADY)
+	begin
+		if (wr_hlast)
+		begin
+			wr_line_beats <= cfg_line_words - 1;
+			wr_hlast <= (cfg_line_words <= 1);
+		end else begin
+			wr_line_beats <= wr_line_beats - 1;
+			wr_hlast <= (wr_line_beats <= 1);
+		end
+	end
+	// }}}
+
+	// wr_lines, wr_vlast
+	// {{{
+	always @(posedge i_clk)
+	if (i_reset || r_stopped)
+	begin
+		wr_lines <= cfg_frame_lines-1;
+		wr_vlast <= (cfg_frame_lines == 1);
+	end else if (M_AXI_WVALID && M_AXI_WREADY && wr_hlast)
+	begin
+		if (wr_vlast)
+		begin
+			wr_lines <= cfg_frame_lines - 1;
+			wr_vlast <= (cfg_frame_lines <= 1);
+		end else begin
+			wr_lines <= wr_lines - 1;
+			wr_vlast <= (wr_lines <= 1);
+		end
+	end
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The outgoing AXI (full) protocol section
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// Some counters to keep track of our state
+	// {{{
+
+	// aw_bursts_outstanding
+	// {{{
+	// Count the number of bursts outstanding--these are the number of
+	// AWVALIDs that have been accepted, but for which the BVALID
+	// has not (yet) been returned.
+	initial	aw_none_outstanding   = 1;
+	initial	aw_bursts_outstanding = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		aw_bursts_outstanding <= 0;
+		aw_none_outstanding <= 1;
+	end else case ({ phantom_start, M_AXI_BVALID && M_AXI_BREADY })
+	2'b01:	begin
+			aw_bursts_outstanding <=  aw_bursts_outstanding - 1;
+			aw_none_outstanding   <= (aw_bursts_outstanding == 1);
+		end
+	2'b10:	begin
+		aw_bursts_outstanding <= aw_bursts_outstanding + 1;
+		aw_none_outstanding <= 0;
+		end
+	default: begin end
+	endcase
+	// }}}
+
+	// r_stopped
+	// {{{
+	// Following an error or drop of cfg_active, soft_reset will go high.
+	// We then come to a stop once everything becomes inactive
+	initial	r_stopped = 1;
+	always @(posedge  i_clk)
+	if (i_reset)
+		r_stopped <= 1;
+	else if (r_stopped)
+	begin
+		// Synchronize on the last pixel of an incoming frame
+		if (cfg_active && S_AXIS_TVALID && S_AXIS_VLAST)
+			r_stopped <= soft_reset;
+	end else if ((soft_reset || lost_sync) && aw_none_outstanding
+				&& !M_AXI_AWVALID && !M_AXI_WVALID)
+		r_stopped <= 1;
+	// }}}
+
+	// }}}
+
+	//
+	// start_burst
+	// {{{
+	always @(*)
+	begin
+		start_burst = 1;
+		if (LGFIFO > 0 && !fifo_bursts_available)
+		begin
+			if (!req_multiple_bursts && fifo_data_available[7:0]
+							< req_line_words[7:0])
+				start_burst = 0;
+			if (req_multiple_bursts && !fifo_bursts_available)
+				start_burst = 0;
+		end
+
+		if (phantom_start || req_newline || lost_sync)
+			start_burst = 0;
+
+		// Can't start a new burst if the outgoing channel is still
+		// stalled.
+		if (M_AXI_AWVALID && !M_AXI_AWREADY)
+			start_burst = 0;
+		if (M_AXI_WVALID && (!M_AXI_WREADY || !M_AXI_WLAST))
+			start_burst = 0;
+
+		// Don't let our aw_bursts_outstanding counter overflow
+		if (aw_bursts_outstanding[15])
+			start_burst = 0;
+
+		// Don't wrap around memory
+		if (req_addr[C_AXI_ADDR_WIDTH])
+			start_burst = 0;
+
+		// If the user wants us to stop, then stop
+		if (soft_reset || !cfg_active || r_stopped)
+			start_burst  = 0;
+	end
+	// }}}
+
+	// AWLEN
+	// {{{
+	always @(*)
+		till_boundary = ~req_addr[ADDRLSB +: LGMAXBURST];
+
+	always @(*)
+	begin
+		if (req_needs_alignment)
+			next_awlen = till_boundary;
+		else if (req_multiple_bursts)
+			next_awlen = (1<<LGMAXBURST)-1;
+		else
+			next_awlen = req_line_words[7:0]-1;
+	end
+
+	always @(posedge i_clk)
+	if (!M_AXI_AWVALID || M_AXI_AWREADY)
+		axi_awlen <= next_awlen;
+	// }}}
+
+	// wr_pending
+	// {{{
+	initial	wr_pending = 0;
+	always @(posedge i_clk)
+	begin
+		if (M_AXI_WVALID && M_AXI_WREADY)
+			wr_pending <= wr_pending - 1;
+		if (start_burst)
+			wr_pending <= next_awlen + 1;
+
+		if (!S_AXI_ARESETN)
+			wr_pending <= 0;
+	end
+	// }}}
+
+	// req_hlast
+	// {{{
+	always @(posedge i_clk)
+	// Verilator lint_off WIDTH
+	if (r_stopped)
+		req_hlast <= (cfg_frame_addr[ADDRLSB +: LGMAXBURST]
+					+ cfg_line_words <= (1<<LGMAXBURST));
+	else if (phantom_start)
+	begin
+		if (req_hlast && req_vlast)
+			req_hlast <= (cfg_frame_addr[ADDRLSB +: LGMAXBURST]
+					+ cfg_line_words <= (1<<LGMAXBURST));
+		else if (req_hlast)
+			req_hlast <= (next_line_addr[ADDRLSB +: LGMAXBURST]
+					+ cfg_line_words <= (1<<LGMAXBURST));
+		else
+			req_hlast <= (req_line_words - (M_AXI_AWLEN+1)
+							<= (1<<LGMAXBURST));
+	// Verilator lint_on WIDTH
+	end
+	// }}}
+
+	// phantom_start
+	// {{{
+	initial	phantom_start = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		phantom_start <= 0;
+	else
+		phantom_start <= start_burst;
+	// }}}
+
+	// AWVALID
+	// {{{
+	initial	axi_awvalid = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		axi_awvalid <= 0;
+	else if (!M_AXI_AWVALID || M_AXI_AWREADY)
+		axi_awvalid <= start_burst;
+	// }}}
+
+	// ARADDR
+	// {{{
+	initial	axi_awaddr = 0;
+	always @(posedge i_clk)
+	begin
+		if (start_burst)
+			axi_awaddr <= req_addr[C_AXI_ADDR_WIDTH-1:0];
+
+		axi_awaddr[ADDRLSB-1:0] <= 0;
+	end
+	// }}}
+
+	// WVALID
+	// {{{
+	initial	axi_wvalid = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		axi_wvalid <= 0;
+	else if (!M_AXI_WVALID || M_AXI_WREADY)
+		axi_wvalid <= start_burst || (M_AXI_WVALID && !M_AXI_WLAST);
+	// }}}
+
+	// WLAST
+	// {{{
+	always @(posedge i_clk)
+	begin
+		if (M_AXI_WVALID && M_AXI_WREADY)
+			axi_wlast <= (wr_pending <= 2);
+
+		if (start_burst)
+			axi_wlast <= (next_awlen == 0);
+	end
+	// }}}
+
+
+	// Set the constant M_AXI_* signals
+	// {{{
+	assign	M_AXI_AWVALID= axi_awvalid;
+	assign	M_AXI_AWID   = AXI_ID;
+	assign	M_AXI_AWADDR = axi_awaddr;
+	assign	M_AXI_AWLEN  = axi_awlen;
+	// Verilator lint_off WIDTH
+	assign	M_AXI_AWSIZE = $clog2(C_AXI_DATA_WIDTH)-3;
+	// Verilator lint_on  WIDTH
+	assign	M_AXI_AWBURST= 2'b01;	// INCR
+	assign	M_AXI_AWLOCK = 0;
+	assign	M_AXI_AWCACHE= 0;
+	assign	M_AXI_AWPROT = 0;
+	assign	M_AXI_AWQOS  = 0;
+	//
+	assign	M_AXI_WVALID = axi_wvalid;
+	assign	M_AXI_WLAST  = axi_wlast;
+	assign	M_AXI_WDATA  = fifo_data;
+	assign	M_AXI_WSTRB  = -1;
+	//
+	assign	M_AXI_BREADY = 1;
+	// }}}
+
+	// End AXI protocol section
+	// }}}
+
+	// Verilator lint_off UNUSED
+	// {{{
+	wire	unused;
+	assign	unused = &{ 1'b0, S_AXIL_AWPROT, S_AXIL_ARPROT, M_AXI_BID,
+			M_AXI_BRESP[0], fifo_empty,
+			S_AXIL_AWADDR[AXILLSB-1:0], S_AXIL_ARADDR[AXILLSB-1:0],
+			new_wideaddr[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH],
+			new_control, new_config, fifo_fill, next_line_addr,
+			fifo_vlast, fifo_hlast
+		};
+	// Verilator lint_on  UNUSED
+	// }}}
+	// }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties
+//
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	// {{{
+
+	// The formal properties for this core are maintained elsewhere
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Contract checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// The formal proof for this core doesn't (yet) include a contract
+	// check.
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	//	Simplifying (careless) assumptions
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// If the FIFO gets reset, then we really don't care about what
+	// gets written to memory.  However, it is possible that a value
+	// on the output might get changed and so violate our protocol checker.
+	// (We don't care.)  So let's just assume it never happens, and check
+	// everything else instead.
+	always @(*)
+	if (M_AXI_WVALID)
+		assume(!lost_sync && cfg_active);
+	// }}}
+	// }}}
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axivdisplay.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axivdisplay.v
new file mode 100644
index 0000000..97ef050
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axivdisplay.v
@@ -0,0 +1,1439 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axivdisplay
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Reads from memory for the purposes of serving a video frame
+// {{{
+//		buffer.  The result of this core is an AXI stream having the
+//	word size of the memory interface in the first place.  TLAST is set
+//	based upon the end of the frame, and TUSER based upon the end of the
+//	line.  An option exists to use Xilinx's encoding instead where TLAST
+//	is the end of the line and TUSER is the first pixel word of the frame.
+//
+//	This core is in many ways similar to the AXI MM2S core, but with some
+//	key differences: The AXI MM2S core generates a single transfer.  This
+//	core generates a repeating set of transfers--one per line, repeated
+//	per frame.
+//
+//	To insure high bandwidth, data is first copied into a FIFO of twice
+//	the width of the longest burst.
+//
+// }}}
+// Registers:
+// {{{
+//   0:	FBUF_CONTROL and status
+//	bit 0: START(1)/STOP(0)
+//		Command the core to start by writing a '1' to this bit.  It
+//		will then remain busy/active until either you tell it to halt,
+//		or an error occurrs.
+//	bit 1: BUSY
+//	bit 2: ERR
+//		If the core receives a bus error, it assumes it has been
+//		inappropriately set up, sets this error bit and then halts.
+//		It will not start again until this bit is cleared.  Only a
+//		write to the control register with the ERR bit set will clear
+//		it.  (Don't do this unless you know what caused it to halt ...)
+//	bit 3: DIRTY
+//		If you update core parameters while it is running, the busy
+//		bit will be set.  This bit is an indication that the current
+//		configuration doesn't necessarily match the one you are reading
+//		out.  To clear DIRTY, deactivate the core, wait for it to be
+//		no longer busy, and then start it again.  This will also start
+//		it under the new configuration so the two match.
+//
+//   2:	FBUF_LINESTEP
+//		Controls the distance from one line to the next.  This is the
+//		value added to the address of the beginning of the line to get
+//		to the beginning of the next line.  This should nominally be
+//		equal to the number of bytes per line, although it doesn't
+//		need to be.
+//
+//		Any attempt to set this value to zero will simply copy the
+//		number of data bytes per line into this value.
+//
+//   4:	FBUF_LINEBYTES
+//		This is the number of data bytes necessary to capture all of
+//		the video data in a line.  This value must be more than zero
+//		in order to activate the core.
+//
+//		At present, this core can only handle a number of bytes aligned
+//		with the word size of the bus.
+//
+//   6:	FBUF_NUMLINES
+//		The number of lines of active video data in a frame.  This
+//		number must be greater than zero in order to activate and
+//		operate the core.
+//
+//   8:	FBUF_ADDRESS
+//		The is the first address of video data in memory.  Each frame
+//		will start reading from this address.
+//
+//  12:	(reserved for the upper FBUF_ADDRESS)
+//
+//  BUGS:
+//	1. Memory reads are currently allowed to wrap around the end of memory.
+//	I'm not (yet) sure if this is a good thing or a bad thing.  I mean, its
+//	a great thing for small dedicated memories designated for this purpose
+//	alone, but perhaps a bad thing if the memory space is shared with
+//	peripherals as well as a CPU.
+//
+//	2. I'd still like to add an option to handle  memory addresses that
+//	aren't aligned.  Until that is done, the means of interacting with the
+//	core will change from one implementation to another.
+//
+//	3. If the configuration changes mid-write, but without de-activating
+//	the core and waiting for it to come to idle, the synchronization flags
+//	might out-of-sync with the pixels.  To resolve, deactivate the core and
+//	let it come to whenever changing configuration parameters.
+// }}}
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+// }}}
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+module	axivdisplay #(
+		// {{{
+		parameter	C_AXI_ADDR_WIDTH = 32,
+		parameter	C_AXI_DATA_WIDTH = 32,
+		parameter	C_AXI_ID_WIDTH = 1,
+		//
+		// We support five 32-bit AXI-lite registers, requiring 5-bits
+		// of AXI-lite addressing
+		localparam	C_AXIL_ADDR_WIDTH = 4,
+		localparam	C_AXIL_DATA_WIDTH = 32,
+		//
+		// The bottom ADDRLSB bits of any AXI address are subword bits
+		localparam	ADDRLSB = $clog2(C_AXI_DATA_WIDTH)-3,
+		localparam	AXILLSB = $clog2(C_AXIL_DATA_WIDTH)-3,
+		//
+		// OPT_UNALIGNED: Allow unaligned accesses, address requests
+		// and sizes which may or may not match the underlying data
+		// width.  If set, the core will quietly align these requests.
+		// parameter [0:0]	OPT_UNALIGNED = 1'b0,
+		//
+		// OPT_LGMAXBURST
+		parameter	OPT_LGMAXBURST = 8,
+		//
+		parameter [0:0]	DEF_ACTIVE_ON_RESET = 0,
+		parameter [15:0] DEF_LINES_PER_FRAME = 1024,
+		parameter [16-ADDRLSB-1:0] DEF_WORDS_PER_LINE  = (1280 * 32)/C_AXI_DATA_WIDTH,
+		//
+		// DEF_FRAMEADDR: the default AXI address of the frame buffer
+		// containing video memory.  Unless OPT_UNALIGNED is set, this
+		// should be aligned so that DEF_FRAMEADDR[ADDRLSB-1:0] == 0.
+		parameter [C_AXI_ADDR_WIDTH-1:0] DEF_FRAMEADDR = 0,
+		//
+		// The (log-based two of  the) size of the FIFO in words.
+		// I like to set this to the size of two AXI bursts, so that
+		// while one is being read out the second can be read in.  Can
+		// also be set larger if desired.
+		parameter	LGFIFO = OPT_LGMAXBURST+1,
+		//
+		// AXI_ID is the ID we will use for all of our AXI transactions
+		parameter	AXI_ID = 0,
+		//
+		// OPT_TUSER_IS_SOF.  Xilinx and I chose different stream
+		// encodings.  I encode TLAST== VLAST and
+		// TUSER == (optional) HLAST.  Xilinx chose TLAST == HLAST
+		// and TUSER == SOF(start of frame).  Set OPT_TUSER_IS_SOF to
+		// use Xilinx's encoding.
+		parameter [0:0]	OPT_TUSER_IS_SOF = 0
+		// }}}
+	) (
+		// {{{
+		input	wire					S_AXI_ACLK,
+		input	wire					S_AXI_ARESETN,
+		//
+		// The video stream interface
+		// {{{
+		output	wire					M_AXIS_TVALID,
+		input	wire					M_AXIS_TREADY,
+		output	wire	[C_AXI_DATA_WIDTH-1:0]		M_AXIS_TDATA,
+		output	wire	/* VLAST or HLAST */		M_AXIS_TLAST,
+		output	wire	/* HLAST or SOF */		M_AXIS_TUSER,
+		// }}}
+		//
+		// The control interface
+		// {{{
+		input	wire					S_AXIL_AWVALID,
+		output	wire					S_AXIL_AWREADY,
+		input	wire	[C_AXIL_ADDR_WIDTH-1:0]		S_AXIL_AWADDR,
+		input	wire	[2:0]				S_AXIL_AWPROT,
+		//
+		input	wire					S_AXIL_WVALID,
+		output	wire					S_AXIL_WREADY,
+		input	wire	[C_AXIL_DATA_WIDTH-1:0]		S_AXIL_WDATA,
+		input	wire	[C_AXIL_DATA_WIDTH/8-1:0]	S_AXIL_WSTRB,
+		//
+		output	wire					S_AXIL_BVALID,
+		input	wire					S_AXIL_BREADY,
+		output	wire	[1:0]				S_AXIL_BRESP,
+		//
+		input	wire					S_AXIL_ARVALID,
+		output	wire					S_AXIL_ARREADY,
+		input	wire	[C_AXIL_ADDR_WIDTH-1:0]		S_AXIL_ARADDR,
+		input	wire	[2:0]				S_AXIL_ARPROT,
+		//
+		output	wire					S_AXIL_RVALID,
+		input	wire					S_AXIL_RREADY,
+		output	wire	[C_AXIL_DATA_WIDTH-1:0]		S_AXIL_RDATA,
+		output	wire	[1:0]				S_AXIL_RRESP,
+		// }}}
+		//
+
+		//
+		// The AXI (full) read interface
+		// {{{
+		output	wire				M_AXI_ARVALID,
+		input	wire				M_AXI_ARREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_ARID,
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_ARADDR,
+		output	wire	[7:0]			M_AXI_ARLEN,
+		output	wire	[2:0]			M_AXI_ARSIZE,
+		output	wire	[1:0]			M_AXI_ARBURST,
+		output	wire				M_AXI_ARLOCK,
+		output	wire	[3:0]			M_AXI_ARCACHE,
+		output	wire	[2:0]			M_AXI_ARPROT,
+		output	wire	[3:0]			M_AXI_ARQOS,
+		//
+		input	wire				M_AXI_RVALID,
+		output	wire				M_AXI_RREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_RDATA,
+		input	wire				M_AXI_RLAST,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_RID,
+		input	wire	[1:0]			M_AXI_RRESP
+		// }}}
+		// }}}
+	);
+
+	// Core logic implementation
+	// {{{
+	// Local parameter declarations
+	// {{{
+	localparam [1:0]	FBUF_CONTROL	= 2'b00,
+				FBUF_FRAMEINFO	= 2'b01,
+				FBUF_ADDRLO	= 2'b10,
+				FBUF_ADDRHI	= 2'b11;
+
+	localparam		CBIT_ACTIVE	= 0,
+				CBIT_BUSY	= 1,
+				CBIT_ERR	= 2,
+				CBIT_DIRTY	= 3;
+
+	localparam	TMPLGMAXBURST=(LGFIFO-1 > OPT_LGMAXBURST)
+					? OPT_LGMAXBURST : LGFIFO-1;
+
+	localparam	LGMAXBURST = (TMPLGMAXBURST+ADDRLSB > 12)
+				? (12-ADDRLSB) : TMPLGMAXBURST;
+
+	localparam [ADDRLSB-1:0] LSBZEROS = 0;
+	// }}}
+
+	wire	i_clk   =  S_AXI_ACLK;
+	wire	i_reset = !S_AXI_ARESETN;
+
+	// Signal declarations
+	// {{{
+	reg				soft_reset, r_err, r_stopped;
+	reg				cfg_active, cfg_zero_length, cfg_dirty;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	cfg_frame_addr;
+	reg	[15:0]			cfg_frame_lines, cfg_line_step;
+	reg	[16-ADDRLSB-1:0]	cfg_line_words;
+
+	// FIFO signals
+	wire				reset_fifo, write_to_fifo,
+					read_from_fifo;
+	wire	[C_AXI_DATA_WIDTH-1:0]	write_data;
+	wire	[LGFIFO:0]		fifo_fill;
+	wire				fifo_full, fifo_empty;
+
+	wire				awskd_valid, axil_write_ready;
+	wire	[C_AXIL_ADDR_WIDTH-AXILLSB-1:0]	awskd_addr;
+	//
+	wire				wskd_valid;
+	wire	[C_AXIL_DATA_WIDTH-1:0]	wskd_data;
+	wire [C_AXIL_DATA_WIDTH/8-1:0]	wskd_strb;
+	reg				axil_bvalid;
+	//
+	wire				arskd_valid, axil_read_ready;
+	wire	[C_AXIL_ADDR_WIDTH-AXILLSB-1:0]	arskd_addr;
+	reg	[C_AXIL_DATA_WIDTH-1:0]	axil_read_data;
+	reg				axil_read_valid;
+	reg	[C_AXIL_DATA_WIDTH-1:0]	w_status_word;
+	reg	[2*C_AXIL_DATA_WIDTH-1:0]	wide_address, new_wideaddr;
+	wire	[C_AXIL_DATA_WIDTH-1:0]	new_cmdaddrlo, new_cmdaddrhi;
+	reg	[C_AXIL_DATA_WIDTH-1:0]	wide_config;
+	wire	[C_AXIL_DATA_WIDTH-1:0]	new_config;
+
+	// reg				partial_burst_requested;
+	// reg	[LGMAXBURST-1:0]	addralign;
+	// reg	[LGFIFO:0]		rd_uncommitted;
+	// reg	[LGMAXBURST:0]		initial_burstlen;
+	// reg	[LGLENWA-1:0]		rd_reads_remaining;
+	// reg				rd_none_remaining,
+	//				rd_last_remaining;
+
+	// wire				realign_last_valid;
+
+	reg	axi_arvalid, lag_start, phantom_start, start_burst,
+		ar_none_outstanding;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	axi_araddr;
+	reg	[LGMAXBURST:0]		max_burst;
+	reg	[7:0]			axi_arlen;
+	reg	[15:0]			ar_bursts_outstanding;
+	//
+	wire				vlast, hlast;
+	reg	[15:0]			r_frame_lines, r_line_step;
+	reg	[16-ADDRLSB-1:0]	r_line_words;
+
+	reg				req_hlast, req_vlast;
+	reg	[15:0]			req_nlines;
+	reg	[16-ADDRLSB-1:0]	req_line_words;
+	reg	[C_AXI_ADDR_WIDTH:0]	req_addr, req_line_addr;
+	//
+	reg				rd_hlast, rd_vlast;
+	reg	[15:0]			rd_lines;
+	reg	[16-ADDRLSB-1:0]	rd_line_beats;
+	wire				no_fifo_space_available;
+	//
+	reg	[LGMAXBURST-1:0]	till_boundary;
+	reg	[LGFIFO:0]		fifo_space_available;
+
+
+`ifdef	FORMAL
+	reg	[C_AXI_ADDR_WIDTH:0]	f_rd_line_addr, f_rd_addr;
+`endif
+
+	wire	M_AXIS_VLAST, M_AXIS_HLAST;
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite signaling
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// This is mostly the skidbuffer logic, and handling of the VALID
+	// and READY signals for the AXI-lite control logic in the next
+	// section.
+	// {{{
+
+	//
+	// Write signaling
+	//
+	// {{{
+
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_ADDR_WIDTH-AXILLSB))
+	axilawskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_AWVALID), .o_ready(S_AXIL_AWREADY),
+		.i_data(S_AXIL_AWADDR[C_AXIL_ADDR_WIDTH-1:AXILLSB]),
+		.o_valid(awskd_valid), .i_ready(axil_write_ready),
+		.o_data(awskd_addr));
+
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_DATA_WIDTH+C_AXIL_DATA_WIDTH/8))
+	axilwskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_WVALID), .o_ready(S_AXIL_WREADY),
+		.i_data({ S_AXIL_WDATA, S_AXIL_WSTRB }),
+		.o_valid(wskd_valid), .i_ready(axil_write_ready),
+		.o_data({ wskd_data, wskd_strb }));
+
+	assign	axil_write_ready = awskd_valid && wskd_valid
+			&& (!S_AXIL_BVALID || S_AXIL_BREADY);
+
+	initial	axil_bvalid = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		axil_bvalid <= 0;
+	else if (axil_write_ready)
+		axil_bvalid <= 1;
+	else if (S_AXIL_BREADY)
+		axil_bvalid <= 0;
+
+	assign	S_AXIL_BVALID = axil_bvalid;
+	assign	S_AXIL_BRESP = 2'b00;
+	// }}}
+
+	//
+	// Read signaling
+	//
+	// {{{
+	skidbuffer #(.OPT_OUTREG(0), .DW(C_AXIL_ADDR_WIDTH-AXILLSB))
+	axilarskid(//
+		.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+		.i_valid(S_AXIL_ARVALID), .o_ready(S_AXIL_ARREADY),
+		.i_data(S_AXIL_ARADDR[C_AXIL_ADDR_WIDTH-1:AXILLSB]),
+		.o_valid(arskd_valid), .i_ready(axil_read_ready),
+		.o_data(arskd_addr));
+
+	assign	axil_read_ready = arskd_valid
+				&& (!axil_read_valid || S_AXIL_RREADY);
+
+	initial	axil_read_valid = 1'b0;
+	always @(posedge i_clk)
+	if (i_reset)
+		axil_read_valid <= 1'b0;
+	else if (axil_read_ready)
+		axil_read_valid <= 1'b1;
+	else if (S_AXIL_RREADY)
+		axil_read_valid <= 1'b0;
+
+	assign	S_AXIL_RVALID = axil_read_valid;
+	assign	S_AXIL_RDATA  = axil_read_data;
+	assign	S_AXIL_RRESP = 2'b00;
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite controlled logic
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	//
+	// soft_reset,  r_err
+	// {{{
+	initial	soft_reset = 1;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		soft_reset <= 1;
+		r_err  <= 0;
+	end else if (soft_reset)
+	begin
+
+		if ((axil_write_ready && awskd_addr == FBUF_CONTROL)
+				&& wskd_strb[0] && wskd_data[CBIT_ERR])
+			r_err <= cfg_zero_length;
+
+		if (cfg_active && !r_err && r_stopped)
+			soft_reset <= 0;
+
+	end else // if (!soft_reset)
+	begin
+		// Halt on any bus error.  We'll require user intervention
+		// to start back up again
+		if (M_AXI_RREADY && M_AXI_RVALID && M_AXI_RRESP[1])
+		begin
+			soft_reset <= 1;
+			r_err  <= 1;
+		end
+
+		// Halt on any user request
+		if (!cfg_active)
+			soft_reset <= 1;
+	end
+	// }}}
+
+	// wide_* and new_* write setup registers
+	// {{{
+	always @(*)
+	begin
+		wide_address = 0;
+		wide_address[C_AXI_ADDR_WIDTH-1:0] = cfg_frame_addr;
+		wide_address[ADDRLSB-1:0] = 0;
+
+		wide_config  = { cfg_frame_lines, cfg_line_words,
+					{(ADDRLSB){1'b0}} };
+	end
+
+	assign	new_cmdaddrlo = apply_wstrb(
+			wide_address[C_AXIL_DATA_WIDTH-1:0],
+			wskd_data, wskd_strb);
+
+	generate if (C_AXI_ADDR_WIDTH > 32)
+	begin
+
+		assign	new_cmdaddrhi = apply_wstrb(
+			wide_address[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH],
+			wskd_data, wskd_strb);
+
+	end else begin
+
+		assign	new_cmdaddrhi = 0;
+
+	end endgenerate
+
+
+	wire	[C_AXIL_DATA_WIDTH-1:0]	new_control;
+	assign	new_control = apply_wstrb(w_status_word, wskd_data, wskd_strb);
+	assign	new_config  = apply_wstrb(wide_config, wskd_data, wskd_strb);
+
+	always @(*)
+	begin
+		new_wideaddr = wide_address;
+
+		if (awskd_addr == FBUF_ADDRLO)
+			new_wideaddr[C_AXIL_DATA_WIDTH-1:0] = new_cmdaddrlo;
+		if (awskd_addr == FBUF_ADDRHI)
+			new_wideaddr[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH] = new_cmdaddrhi;
+		new_wideaddr[ADDRLSB-1:0] = 0;
+		new_wideaddr[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH] = 0;
+	end
+	// }}}
+
+	// Configuration registers (Write)
+	// {{{
+	initial	cfg_active      = 0;
+	initial	cfg_frame_addr  = DEF_FRAMEADDR;
+	initial	cfg_frame_addr[ADDRLSB-1:0] = 0;
+	initial	cfg_line_words = DEF_WORDS_PER_LINE;
+	initial	cfg_frame_lines = DEF_LINES_PER_FRAME;
+	initial	cfg_zero_length = (DEF_WORDS_PER_LINE == 0)
+				||(DEF_LINES_PER_FRAME == 0);
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		cfg_active	<= DEF_ACTIVE_ON_RESET;
+		cfg_frame_addr	<= DEF_FRAMEADDR;
+		cfg_line_words	<= DEF_WORDS_PER_LINE;
+		cfg_line_step	<= { DEF_WORDS_PER_LINE, {(ADDRLSB){1'b0}} };
+		cfg_frame_lines	<= DEF_LINES_PER_FRAME;
+		cfg_zero_length <= (DEF_WORDS_PER_LINE==0)
+			||(DEF_LINES_PER_FRAME == 0);
+		cfg_dirty <= 0;
+	end else begin
+		if (r_stopped)
+			cfg_dirty <= 0;
+		if (cfg_active && req_hlast && req_vlast && phantom_start)
+			cfg_dirty <= 0;
+		if (M_AXI_RREADY && M_AXI_RVALID && M_AXI_RRESP[1])
+			cfg_active <= 0;
+
+		if (axil_write_ready)
+		case(awskd_addr)
+		FBUF_CONTROL: begin
+			if (wskd_strb[0])
+				cfg_active <= wskd_data[CBIT_ACTIVE]
+					&& (!r_err || wskd_data[CBIT_ERR])
+					&& (!cfg_zero_length);
+
+			if (new_control[31:16] == 0)
+			begin
+				cfg_line_step <= 0;
+				cfg_line_step[16-1:ADDRLSB] <= cfg_line_words;
+				// Verilator lint_off WIDTH
+				cfg_dirty <= (cfg_line_step
+					!= (cfg_line_words << ADDRLSB));
+				// Verilator lint_on  WIDTH
+			end else begin
+				cfg_line_step <= new_control[31:16];
+				cfg_dirty <= (cfg_line_step != new_control[31:16]);
+			end end
+		FBUF_FRAMEINFO: begin
+			{ cfg_frame_lines, cfg_line_words }
+				<= new_config[C_AXI_DATA_WIDTH-1:ADDRLSB];
+			cfg_zero_length <= (new_config[31:16] == 0)
+					||(new_config[15:ADDRLSB] == 0);
+			if ((new_config[31:16] == 0)
+					||(new_config[15:ADDRLSB] == 0))
+				cfg_active <= 0;
+			cfg_dirty <= 1;
+			end
+		FBUF_ADDRLO, FBUF_ADDRHI: begin
+			cfg_frame_addr <= new_wideaddr[C_AXI_ADDR_WIDTH-1:0];
+			cfg_dirty <= 1;
+			end
+		default: begin end
+		endcase
+	end
+	// }}}
+
+	// AXI-Lite read register data
+	// {{{
+	always @(*)
+	begin
+		w_status_word = 0;
+		w_status_word[31:16]		= cfg_line_step;
+		w_status_word[CBIT_DIRTY]	= cfg_dirty;
+		w_status_word[CBIT_ERR]		= r_err;
+		w_status_word[CBIT_BUSY]	= !soft_reset;
+		w_status_word[CBIT_ACTIVE]	= cfg_active || (!soft_reset || !r_stopped);
+	end
+
+	always @(posedge i_clk)
+	if (!axil_read_valid || S_AXIL_RREADY)
+	begin
+		axil_read_data <= 0;
+		case(arskd_addr)
+		FBUF_CONTROL:	axil_read_data <= w_status_word;
+		FBUF_FRAMEINFO:	axil_read_data <= { cfg_frame_lines,
+					cfg_line_words, {(ADDRLSB){1'b0}} };
+		FBUF_ADDRLO:	axil_read_data <= wide_address[C_AXIL_DATA_WIDTH-1:0];
+		FBUF_ADDRHI:	axil_read_data <= wide_address[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+		default		axil_read_data <= 0;
+		endcase
+	end
+	// }}}
+
+	// apply_wstrb function for applying wstrbs to register words
+	// {{{
+	function [C_AXIL_DATA_WIDTH-1:0]	apply_wstrb;
+		input	[C_AXIL_DATA_WIDTH-1:0]		prior_data;
+		input	[C_AXIL_DATA_WIDTH-1:0]		new_data;
+		input	[C_AXIL_DATA_WIDTH/8-1:0]	wstrb;
+
+		integer	k;
+		for(k=0; k<C_AXIL_DATA_WIDTH/8; k=k+1)
+		begin
+			apply_wstrb[k*8 +: 8]
+				= wstrb[k] ? new_data[k*8 +: 8] : prior_data[k*8 +: 8];
+		end
+	endfunction
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The data FIFO section
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	// {{{
+	assign	reset_fifo = r_stopped;
+
+	assign	write_to_fifo  = M_AXI_RVALID;
+	assign	write_data = M_AXI_RDATA;
+	// assign	realign_last_valid = 0;
+	assign	vlast = rd_vlast;
+	assign	hlast = rd_hlast;
+	assign	M_AXI_RREADY  = !fifo_full;
+	// }}}
+
+	generate if (LGFIFO > 0)
+	begin : GEN_SPACE_AVAILBLE
+		// Here's where  we'll put the actual outgoing FIFO
+		// {{{
+		initial	fifo_space_available = (1<<LGFIFO);
+		always @(posedge i_clk)
+		if (reset_fifo)
+			fifo_space_available <= (1<<LGFIFO);
+		else case({phantom_start, read_from_fifo && !fifo_empty })
+		2'b00: begin end
+		// Verilator lint_off WIDTH
+		2'b10: fifo_space_available <= fifo_space_available - (M_AXI_ARLEN+1);
+		2'b11: fifo_space_available <= fifo_space_available - (M_AXI_ARLEN);
+		// Verilator lint_on  WIDTH
+		2'b01: fifo_space_available <= fifo_space_available + 1;
+		endcase
+
+		assign	M_AXIS_TVALID  = !fifo_empty;
+		assign	read_from_fifo = M_AXIS_TVALID && M_AXIS_TREADY;
+
+		sfifo #(.BW(C_AXI_DATA_WIDTH+2), .LGFLEN(LGFIFO))
+		sfifo(i_clk, reset_fifo,
+			write_to_fifo, { vlast && hlast, hlast, write_data },
+				fifo_full, fifo_fill,
+			read_from_fifo, { M_AXIS_VLAST, M_AXIS_HLAST,
+				M_AXIS_TDATA }, fifo_empty);
+
+		assign no_fifo_space_available = (fifo_space_available < (1<<LGMAXBURST));
+		// }}}
+	end else begin : NO_FIFO
+		// {{{
+		assign	fifo_full  = !M_AXIS_TREADY;
+		assign	fifo_fill  = 0;
+		assign	fifo_empty = !M_AXIS_TVALID;
+		assign	M_AXIS_TVALID = write_to_fifo;
+
+		assign	M_AXIS_VLAST = vlast && hlast;
+		assign	M_AXIS_HLAST = hlast;
+		assign	M_AXIS_TDATA = M_AXI_RDATA;
+
+		assign no_fifo_space_available = (ar_bursts_outstanding >= 3);
+		// }}}
+	end endgenerate
+	// }}}
+
+	// Switch between TLAST/TUSER encodings if necessary
+	// {{{
+	generate if (OPT_TUSER_IS_SOF)
+	begin : XILINX_ENCODING
+
+		reg	SOF;
+
+		initial	SOF = 1'b1;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN || r_stopped)
+			SOF <= 1'b1;
+		else if (M_AXIS_TVALID && M_AXIS_TREADY)
+			SOF <= M_AXIS_VLAST;
+
+		assign	M_AXIS_TLAST = M_AXIS_HLAST;
+		assign	M_AXIS_TUSER = SOF;
+
+	end else begin : VLAST_EQUALS_TLAST
+
+		assign	M_AXIS_TLAST = M_AXIS_VLAST;
+		assign	M_AXIS_TUSER = M_AXIS_HLAST;
+	end endgenerate
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Outoing frame address counting
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// {{{
+	always @(posedge  i_clk)
+	if (i_reset || r_stopped || (phantom_start && req_hlast && req_vlast))
+	begin
+		r_frame_lines <= cfg_frame_lines;
+		r_line_words  <= cfg_line_words;
+		r_line_step   <= { {(ADDRLSB){1'b0}}, cfg_line_step[15:ADDRLSB] };
+	end
+
+	initial	req_addr = 0;
+	initial	req_line_addr = 0;
+	always @(posedge  i_clk)
+	if (i_reset || r_stopped)
+	begin
+		req_addr       <= { 1'b0, cfg_frame_addr };
+		req_line_addr  <= { 1'b0, cfg_frame_addr };
+		req_line_words <= cfg_line_words;
+	end else if (phantom_start)
+	begin
+		if (req_hlast && req_vlast)
+		begin
+			req_addr       <= { 1'b0, cfg_frame_addr };
+			req_line_addr  <= { 1'b0, cfg_frame_addr };
+			req_line_words <= cfg_line_words;
+		end else if (req_hlast)
+		begin
+			// verilator lint_off WIDTH
+			req_addr <= req_line_addr
+					+ (r_line_step << M_AXI_ARSIZE);
+			req_line_addr  <= req_line_addr
+					+ (r_line_step << M_AXI_ARSIZE);
+			// verilator lint_on WIDTH
+			req_line_words <= r_line_words;
+		end else begin
+			// verilator lint_off WIDTH
+			req_addr <= req_addr + (1<<(LGMAXBURST+ADDRLSB));
+			req_line_words <= req_line_words - (M_AXI_ARLEN+1);
+			// verilator lint_on  WIDTH
+
+			req_addr[LGMAXBURST+ADDRLSB-1:0] <= 0;
+		end
+	end
+
+	always @(posedge  i_clk)
+	if (i_reset || r_stopped)
+	begin
+		req_nlines <= cfg_frame_lines-1;
+		req_vlast <= (cfg_frame_lines <= 1);
+	end else if (phantom_start && req_hlast)
+	begin
+		if (req_vlast)
+		begin
+			req_nlines <= cfg_frame_lines-1;
+			req_vlast <= (cfg_frame_lines <= 1);
+		end else begin
+			req_nlines <= req_nlines - 1;
+			req_vlast <= (req_nlines <= 1);
+		end
+	end
+`ifdef	FORMAL
+	always @(*)
+	if (!r_stopped)
+	begin
+		assert(req_vlast == (req_nlines == 0));
+		assert(req_addr >= { 1'b0, cfg_frame_addr });
+		assert(req_line_addr >= { 1'b0, cfg_frame_addr });
+		assert(req_line_addr <= req_addr);
+	end
+
+	always @(*)
+	if (cfg_active)
+	begin
+		assert(cfg_frame_lines != 0);
+		assert(cfg_line_words  != 0);
+	end
+
+	always @(*)
+	if (!r_stopped)
+	begin
+		assert(r_frame_lines != 0);
+		assert(r_line_words  != 0);
+	end
+`endif
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Incoming frame address counting
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// {{{
+	always @(posedge i_clk)
+	if (i_reset || r_stopped)
+	begin
+		rd_line_beats <= cfg_line_words-1;
+		rd_hlast <= (cfg_line_words == 1);
+	end else if (M_AXI_RVALID && M_AXI_RREADY)
+	begin
+		if (rd_hlast)
+		begin
+			rd_line_beats <= r_line_words - 1;
+			rd_hlast <= (r_line_words <= 1);
+		end else begin
+			rd_line_beats <= rd_line_beats - 1;
+			rd_hlast <= (rd_line_beats <= 1);
+		end
+	end
+
+	always @(posedge i_clk)
+	if (i_reset || r_stopped)
+	begin
+		rd_lines <= cfg_frame_lines-1;
+		rd_vlast <= (cfg_frame_lines == 1);
+	end else if (M_AXI_RVALID && M_AXI_RREADY && rd_hlast)
+	begin
+		if (vlast)
+		begin
+			rd_lines <= r_frame_lines - 1;
+			rd_vlast <= (r_frame_lines <= 1);
+		end else begin
+			rd_lines <= rd_lines - 1;
+			rd_vlast <= (rd_lines <= 1);
+		end
+	end
+
+`ifdef	FORMAL
+	always @(posedge i_clk)
+	if (i_reset || r_stopped)
+	begin
+		f_rd_addr      <= { 1'b0, cfg_frame_addr };
+		f_rd_line_addr <= { 1'b0, cfg_frame_addr };
+	end else if (M_AXI_RVALID && M_AXI_RREADY)
+	begin
+		if (rd_vlast && rd_hlast)
+		begin
+			f_rd_addr <= cfg_frame_addr;
+			f_rd_line_addr <= cfg_frame_addr;
+		end else if (rd_hlast)
+		begin
+			f_rd_addr <= f_rd_line_addr + (r_line_step << M_AXI_ARSIZE);
+			f_rd_line_addr <= f_rd_line_addr + (r_line_step << M_AXI_ARSIZE);
+		end else begin
+			f_rd_addr <= f_rd_addr + (1<<ADDRLSB);
+		end
+	end
+`endif
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The incoming AXI (full) protocol section
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// {{{
+
+	// Some counters to keep track of our state
+	// {{{
+
+	// ar_bursts_outstanding
+	// {{{
+	// Count the number of bursts outstanding--these are the number of
+	// ARVALIDs that have been accepted, but for which the RVALID && RLAST
+	// has not (yet) been returned.
+	initial	ar_none_outstanding   = 1;
+	initial	ar_bursts_outstanding = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		ar_bursts_outstanding <= 0;
+		ar_none_outstanding <= 1;
+	end else case ({ phantom_start,
+				M_AXI_RVALID && M_AXI_RREADY && M_AXI_RLAST })
+	2'b01:	begin
+			ar_bursts_outstanding <=  ar_bursts_outstanding - 1;
+			ar_none_outstanding   <= (ar_bursts_outstanding == 1);
+		end
+	2'b10:	begin
+		ar_bursts_outstanding <= ar_bursts_outstanding + 1;
+		ar_none_outstanding <= 0;
+		end
+	default: begin end
+	endcase
+	// }}}
+
+	// r_stopped
+	// {{{
+	// Following an error or drop of cfg_active, soft_reset will go high.
+	// We then come to a stop once everything becomes inactive
+	initial	r_stopped = 1;
+	always @(posedge  i_clk)
+	if (i_reset)
+		r_stopped <= 1;
+	else if (r_stopped)
+		r_stopped <= soft_reset || !cfg_active;
+	else if (soft_reset && ar_none_outstanding && !M_AXI_ARVALID)
+		r_stopped <= 1;
+	// }}}
+
+	// }}}
+
+	//
+	// start_burst
+	// {{{
+	always @(*)
+	begin
+		start_burst = 1;
+		if (no_fifo_space_available)
+			start_burst = 0;
+		if (phantom_start || lag_start)
+			// Insist on a minimum of two clocks between burst
+			// starts, so we can get our lengths right
+			start_burst = 0;
+
+		// Can't start a new burst if the outgoing channel is still
+		// stalled.
+		if (M_AXI_ARVALID && !M_AXI_ARREADY)
+			start_burst = 0;
+
+		// If the user wants us to stop, then stop
+		if (!cfg_active || soft_reset)
+			start_burst  = 0;
+	end
+	// }}}
+
+	// ARLEN
+	// {{{
+	// Coming in, req_addr and req_line_words can be trusted
+	// lag_start will be true to reflect this
+	always @(posedge i_clk)
+	if (lag_start)
+	begin
+		if (req_line_words >= (1<<LGMAXBURST))
+			max_burst <= (1<<LGMAXBURST);
+		else
+			// Verilator lint_off WIDTH
+			max_burst <= req_line_words;
+			// Verilator lint_on  WIDTH
+	end
+
+	always @(*)
+		till_boundary = ~req_addr[ADDRLSB +: LGMAXBURST];
+
+	always @(posedge i_clk)
+	if (!M_AXI_ARVALID || M_AXI_ARREADY)
+	begin
+		// Verilator lint_off WIDTH
+		if (till_boundary > 0 && max_burst <= till_boundary)
+			axi_arlen <= max_burst-1;
+		// Verilator lint_on WIDTH
+		else
+			axi_arlen <= till_boundary;
+	end
+	// }}}
+
+	// req_hlast
+	// {{{
+	always @(posedge i_clk)
+	if (lag_start || start_burst)
+	begin
+		req_hlast <= 1;
+		// Verilator lint_off WIDTH
+		if (req_line_words > till_boundary+1)
+			req_hlast <= 0;
+		if (req_line_words > max_burst)
+			req_hlast <= 0;
+		// Verilator lint_on WIDTH
+	end
+
+`ifdef	FORMAL
+	always @(*)
+	if (phantom_start)
+	begin
+		if (req_hlast)
+			assert(axi_arlen+1 == req_line_words);
+		else
+			assert(axi_arlen+1 < req_line_words);
+	end else if (!soft_reset && !r_stopped && !lag_start)
+	begin
+		if (max_burst != req_line_words)
+			assert(!req_hlast);
+		else if (!req_hlast && !M_AXI_ARVALID)
+			assert(axi_arlen < max_burst);
+
+		assert(max_burst > 0);
+		if (req_line_words > (1<<LGMAXBURST))
+			assert(max_burst == (1<<LGMAXBURST));
+		else
+			assert(max_burst == req_line_words);
+	end
+`endif
+	// }}}
+
+	// phantom_start
+	// {{{
+	initial	phantom_start = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		phantom_start <= 0;
+	else
+		phantom_start <= start_burst;
+
+	initial	lag_start = 1;
+	always @(posedge i_clk)
+	if (i_reset || r_stopped)
+		lag_start <= 1;
+	else
+		lag_start <= phantom_start;
+	// }}}
+
+	// ARVALID
+	// {{{
+	initial	axi_arvalid = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		axi_arvalid <= 0;
+	else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+		axi_arvalid <= start_burst;
+	// }}}
+
+	// ARADDR
+	// {{{
+	initial	axi_araddr = 0;
+	always @(posedge i_clk)
+	begin
+		if (start_burst)
+			axi_araddr <= req_addr[C_AXI_ADDR_WIDTH-1:0];
+
+		axi_araddr[ADDRLSB-1:0] <= 0;
+	end
+	// }}}
+
+	// Set the constant M_AXI_* signals
+	// {{{
+	assign	M_AXI_ARVALID= axi_arvalid;
+	assign	M_AXI_ARID   = AXI_ID;
+	assign	M_AXI_ARADDR = axi_araddr;
+	assign	M_AXI_ARLEN  = axi_arlen;
+	// Verilator lint_off WIDTH
+	assign	M_AXI_ARSIZE = $clog2(C_AXI_DATA_WIDTH)-3;
+	// Verilator lint_on  WIDTH
+	assign	M_AXI_ARBURST= 2'b01;	// INCR
+	assign	M_AXI_ARLOCK = 0;
+	assign	M_AXI_ARCACHE= 0;
+	assign	M_AXI_ARPROT = 0;
+	assign	M_AXI_ARQOS  = 0;
+	// }}}
+
+	// End AXI protocol section
+	// }}}
+
+	// Verilator lint_off UNUSED
+	// {{{
+	wire	unused;
+	assign	unused = &{ 1'b0, S_AXIL_AWPROT, S_AXIL_ARPROT, M_AXI_RID,
+			M_AXI_RRESP[0], fifo_full, wskd_strb[2:0],
+			S_AXIL_AWADDR[AXILLSB-1:0], S_AXIL_ARADDR[AXILLSB-1:0],
+			new_wideaddr[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH],
+			new_control, new_config, fifo_fill };
+	// Verilator lint_on  UNUSED
+	// }}}
+	// }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties
+//
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The following are only a subset of the formal properties currently
+	// being used to verify this module.  They are not expected to be
+	// syntactically accurate.
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	//
+	// ...
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Properties of the AXI-stream data interface
+	// {{{
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// (These are captured by the FIFO within)
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The AXI-lite control interface
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	localparam	F_AXIL_LGDEPTH = 4;
+	wire	[F_AXIL_LGDEPTH-1:0]	faxil_rd_outstanding,
+			faxil_wr_outstanding, faxil_awr_outstanding;
+
+
+	faxil_slave #(
+		// {{{
+		.C_AXI_DATA_WIDTH(C_AXIL_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXIL_ADDR_WIDTH),
+		.F_LGDEPTH(F_AXIL_LGDEPTH),
+		.F_AXI_MAXWAIT(2),
+		.F_AXI_MAXDELAY(2),
+		.F_AXI_MAXRSTALL(3)
+		// }}}
+	) faxil(
+		// {{{
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXIL_AWVALID),
+		.i_axi_awready(S_AXIL_AWREADY),
+		.i_axi_awaddr( S_AXIL_AWADDR),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot( S_AXIL_AWPROT),
+		//
+		.i_axi_wvalid(S_AXIL_WVALID),
+		.i_axi_wready(S_AXIL_WREADY),
+		.i_axi_wdata( S_AXIL_WDATA),
+		.i_axi_wstrb( S_AXIL_WSTRB),
+		//
+		.i_axi_bvalid(S_AXIL_BVALID),
+		.i_axi_bready(S_AXIL_BREADY),
+		.i_axi_bresp( S_AXIL_BRESP),
+		//
+		.i_axi_arvalid(S_AXIL_ARVALID),
+		.i_axi_arready(S_AXIL_ARREADY),
+		.i_axi_araddr( S_AXIL_ARADDR),
+		.i_axi_arcache(4'h0),
+		.i_axi_arprot( S_AXIL_ARPROT),
+		//
+		.i_axi_rvalid(S_AXIL_RVALID),
+		.i_axi_rready(S_AXIL_RREADY),
+		.i_axi_rdata( S_AXIL_RDATA),
+		.i_axi_rresp( S_AXIL_RRESP),
+		//
+		.f_axi_rd_outstanding(faxil_rd_outstanding),
+		.f_axi_wr_outstanding(faxil_wr_outstanding),
+		.f_axi_awr_outstanding(faxil_awr_outstanding)
+		// }}}
+		);
+
+	always @(*)
+	begin
+		assert(faxil_rd_outstanding == (S_AXIL_RVALID ? 1:0)
+			+(S_AXIL_ARREADY ? 0:1));
+		assert(faxil_wr_outstanding == (S_AXIL_BVALID ? 1:0)
+			+(S_AXIL_WREADY ? 0:1));
+		assert(faxil_awr_outstanding== (S_AXIL_BVALID ? 1:0)
+			+(S_AXIL_AWREADY ? 0:1));
+	end
+
+	always @(*)
+		assert(cfg_zero_length ==
+			((cfg_line_words == 0)||(cfg_frame_lines == 0)));
+
+	always @(*)
+	if (cfg_zero_length)
+		assert(!cfg_active);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The AXI master memory interface
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	//
+	localparam	F_AXI_LGDEPTH = 11; // LGLENW-LGMAXBURST+2 ??
+
+	//
+	// ...
+	//
+
+	faxi_master #(
+		// {{{
+		.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		//
+		// ...
+		//
+		// }}}
+	) faxi(
+		// {{{
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		// The (unused) write interface
+		// {{{
+		.i_axi_awvalid(1'b0),
+		.i_axi_awready(1'b0),
+		.i_axi_awid(   AXI_ID),
+		.i_axi_awaddr( 0),
+		.i_axi_awlen(  0),
+		.i_axi_awsize( 0),
+		.i_axi_awburst(0),
+		.i_axi_awlock( 0),
+		.i_axi_awcache(0),
+		.i_axi_awprot( 0),
+		.i_axi_awqos(  0),
+		//
+		.i_axi_wvalid(0),
+		.i_axi_wready(0),
+		.i_axi_wdata( 0),
+		.i_axi_wstrb( 0),
+		.i_axi_wlast( 0),
+		//
+		.i_axi_bvalid(1'b0),
+		.i_axi_bready(1'b0),
+		.i_axi_bid(   AXI_ID),
+		.i_axi_bresp( 2'b00),
+		// }}}
+		// The read interface
+		// {{{
+		.i_axi_arvalid(M_AXI_ARVALID),
+		.i_axi_arready(M_AXI_ARREADY),
+		.i_axi_arid(   M_AXI_ARID),
+		.i_axi_araddr( M_AXI_ARADDR),
+		.i_axi_arlen(  M_AXI_ARLEN),
+		.i_axi_arsize( M_AXI_ARSIZE),
+		.i_axi_arburst(M_AXI_ARBURST),
+		.i_axi_arlock( M_AXI_ARLOCK),
+		.i_axi_arcache(M_AXI_ARCACHE),
+		.i_axi_arprot( M_AXI_ARPROT),
+		.i_axi_arqos(  M_AXI_ARQOS),
+		//
+		.i_axi_rvalid(M_AXI_RVALID),
+		.i_axi_rready(M_AXI_RREADY),
+		.i_axi_rdata( M_AXI_RDATA),
+		.i_axi_rlast( M_AXI_RLAST),
+		.i_axi_rresp( M_AXI_RRESP),
+		// ...
+		// }}}
+	);
+
+
+	//
+	// ...
+	//
+	always @(*)
+	begin
+		// ...
+
+		assert(M_AXI_ARBURST == 2'b01);
+	end
+
+	always @(*)
+	if (faxi_rd_ckvalid)
+	begin
+		assert(!r_stopped);
+		//
+		// ...
+		//
+	end
+
+	//
+	// ...
+	//
+
+	reg	[LGMAXBURST-1:0]	f_rd_subaddr;
+	always @(*)
+		f_rd_subaddr = f_rd_addr[ADDRLSB +: LGMAXBURST];
+
+	always @(*)
+	begin
+		assert(cfg_frame_addr[ADDRLSB-1:0] == 0);
+		if (!r_stopped)
+		begin
+			assert(req_addr[ADDRLSB-1:0] == 0);
+			assert(req_line_addr[ADDRLSB-1:0] == 0);
+		end
+
+		if (M_AXI_RVALID)
+			assert(M_AXI_RLAST == (rd_hlast || (&f_rd_subaddr)));
+	end
+
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read request to return address correlations
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+		if (M_AXI_RVALID)
+		begin
+			if (rd_hlast || (&f_rd_subaddr))
+			begin
+				// ...
+				assert(M_AXI_RLAST);
+			end else
+				// ...
+				assume(!M_AXI_RLAST);
+		end
+	end
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Other formal properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Contract checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	reg	cvr_full_frame, cvr_full_size;
+	(* anyconst *) reg cvr_hlast_rlast;
+
+	always @(posedge i_clk)
+	if (r_stopped)
+		cvr_full_size <= (cfg_line_step >= cfg_line_words)
+				&&(cfg_line_words > 5)
+				&&(cfg_frame_lines > 4);
+	else begin
+		if ($changed(cfg_line_step))
+			cvr_full_size <= 0;
+		if ($changed(cfg_line_words))
+			cvr_full_size <= 0;
+		if ($changed(cfg_frame_lines))
+			cvr_full_size <= 0;
+		if ($changed(cfg_frame_addr))
+			cvr_full_size <= 0;
+	end
+
+	always @(posedge i_clk)
+	if (r_stopped || !cvr_full_size)
+		cvr_full_frame <= 0;
+	else if (!cvr_full_frame)
+		cvr_full_frame <= rd_vlast && rd_hlast && M_AXI_RVALID && M_AXI_RREADY;
+
+	always @(*)
+		cover(!soft_reset);
+
+	always @(*)
+		cover(start_burst);
+
+	always @(*)
+		cover(M_AXI_ARVALID && M_AXI_ARREADY);
+
+	always @(*)
+		cover(M_AXI_RVALID);
+
+	always @(*)
+		cover(M_AXI_RVALID & M_AXI_RLAST);
+
+	always @(*)
+		cover(!r_stopped && cvr_full_frame);
+
+	always @(*)
+		cover(cvr_full_frame && phantom_start && !r_stopped);
+
+	always @(*)
+	if (cvr_hlast_rlast)
+	begin
+		// assume(M_AXI_RLAST == (rd_hlast && M_AXI_RVALID));
+		assume(M_AXI_ARREADY && M_AXI_RREADY);
+		assume(M_AXIS_TREADY);
+		assume(cfg_frame_addr[12:0] == 0);
+		assume(cfg_line_step[3:0] == 0);
+	end
+
+	always @(*)
+		cover(cvr_hlast_rlast && cvr_full_frame && phantom_start && !r_stopped);
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	//	Simplifying (careless) assumptions
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(posedge i_clk)
+	if (!r_stopped || cfg_active)
+	begin
+		assume($stable(cfg_frame_addr));
+		assume($stable(cfg_frame_lines));
+		assume($stable(cfg_line_words));
+		assume($stable(cfg_line_step));
+	end
+
+
+	always @(*)
+		assume(!f_sequential);
+
+	always @(*)
+		assume(!f_biglines);
+
+	always @(*)
+		assume(!req_addr[C_AXI_ADDR_WIDTH]);
+
+	always @(*)
+		assume(!req_line_addr[C_AXI_ADDR_WIDTH]);
+	// }}}
+	// }}}
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axivfifo.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axivfifo.v
new file mode 100644
index 0000000..165d811
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axivfifo.v
@@ -0,0 +1,1399 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axivfifo.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	A virtual FIFO, using an AXI based memory on the back end.  Data
+//		written via the AXI stream interface is written to an external
+//	memory once enough is available to fill a burst.  It's then copied from
+//	this external memory to a FIFO from which it can drive an outgoing
+//	stream.
+//
+// Registers:
+//	This core is simple--providing no control interface nor registers
+//	whereby it may be controlled.  To place it in a particular region of
+//	SDRAM, limit the address width and fill the rest of the address with
+//	the region you want.  Note: THIS CORE DEPENDS UPON ALIGNED MEMORY
+//	ACCESSES.  Hence, it must be aligned to the memory to keep these
+//	accesses aligned.
+//
+// Performance goals:
+//	100% throughput
+//	Stay off the bus until you can drive it hard
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+// }}}
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+// }}}
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// `define			AXI3
+//
+module	axivfifo #(
+		// {{{
+		parameter	C_AXI_ID_WIDTH = 1,
+		parameter	C_AXI_ADDR_WIDTH = 32,
+		parameter	C_AXI_DATA_WIDTH = 32,
+		//
+		// This core requires that the stream data width be identical
+		// to the bus data width.  Use an upstream core if you need to
+		// pack a smaller width into your bus's width, or a downstream
+		// core if you need to unpack it.
+		localparam	C_AXIS_DATA_WIDTH = C_AXI_DATA_WIDTH,
+		//
+		// LGMAXBURST determines the size of the maximum AXI burst.
+		// In AXI4, the maximum burst size is 256 beats the log_2()
+		// of which is 8.  In AXI3, it's a 16 beat burst of which the
+		// log_2() is 4.  Smaller numbers are also permissible here,
+		// although not verified.  I expect problems if LGMAXBURST is
+		// ever set to zero (no bursting).  An upgrade should fix that.
+		// Lower LGMAXBURST values will decrease the latency in this
+		// core while possibly causing throughput to be decreased
+		// (in the rest of the system--this core can handle 100%
+		// throughput either way.)
+		//
+		// Beware of the AXI requirement that bursts cannot cross
+		// 4kB boundaries.  If your bus is larger than 128 bits wide,
+		// you'll need to lower this maximum burst size to meet that
+		// requirement.
+`ifdef	AXI3
+		parameter	LGMAXBURST=4,	// 16 beats max
+`else
+		parameter	LGMAXBURST=8,	// 256 beats
+`endif
+		// The number of beats in this maximum burst size is
+		// automatically determined from LGMAXBURST, and so its
+		// forced to be a power of two this way.
+		localparam	MAXBURST=(1<<LGMAXBURST),
+		//
+		// LGFIFO: This is the (log-based-2) size of the internal FIFO.
+		// Hence if LGFIFO=8, the internal FIFO will have 256 elements
+		// (words) in it.  High throughput transfers are accomplished
+		// by first storing data into a FIFO, then once a full burst
+		// size is available bursting that data over the bus.  In
+		// order to be able to keep receiving data while bursting it
+		// out, the FIFO size must be at least twice the size of the
+		// maximum burst size--that is LGFIFO must be at least one more
+		// than LGMAXBURST.  Larger sizes are possible as well.
+		parameter	LGFIFO = LGMAXBURST+1,	// 512 element FIFO
+		//
+		// AXI uses ID's to transfer information.  This core rather
+		// ignores them.  Instead, it uses a constant ID for all
+		// transfers.  The following two parameters control that ID.
+		parameter	[C_AXI_ID_WIDTH-1:0]	AXI_READ_ID = 0,
+		parameter	[C_AXI_ID_WIDTH-1:0]	AXI_WRITE_ID = 0,
+		//
+		localparam	ADDRLSB= $clog2(C_AXI_DATA_WIDTH)-3
+		// }}}
+	) (
+		// {{{
+		input	wire	S_AXI_ACLK,
+		input	wire	S_AXI_ARESETN,
+		//
+		// The AXI4-stream interface
+		// {{{
+		// This core does not support TLAST, TKEEP, or TSTRB.  If you
+		// want to support these extra values, expand the width of
+		// TDATA, and unpack them on the output of the FIFO.
+		//
+		// The incoming stream
+		input	wire				S_AXIS_TVALID,
+		output	wire				S_AXIS_TREADY,
+		input	wire	[C_AXIS_DATA_WIDTH-1:0]	S_AXIS_TDATA,
+		//
+		// The outgoing stream
+		output	wire				M_AXIS_TVALID,
+		input	wire				M_AXIS_TREADY,
+		output	reg	[C_AXIS_DATA_WIDTH-1:0]	M_AXIS_TDATA,
+		// }}}
+		//
+		// The AXI Master (DMA) interface
+		// {{{
+		// First to write data to the (external) AXI buffer
+		output	wire				M_AXI_AWVALID,
+		input	wire				M_AXI_AWREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_AWID,
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_AWADDR,
+`ifdef	AXI3
+		output	wire	[3:0]			M_AXI_AWLEN,
+`else
+		output	wire	[7:0]			M_AXI_AWLEN,
+`endif
+		output	wire	[2:0]			M_AXI_AWSIZE,
+		output	wire	[1:0]			M_AXI_AWBURST,
+`ifdef	AXI3
+		output	wire	[1:0]			M_AXI_AWLOCK,
+`else
+		output	wire				M_AXI_AWLOCK,
+`endif
+		output	wire	[3:0]			M_AXI_AWCACHE,
+		output	wire	[2:0]			M_AXI_AWPROT,
+		output	wire	[3:0]			M_AXI_AWQOS,
+		//
+		//
+		output	wire				M_AXI_WVALID,
+		input	wire				M_AXI_WREADY,
+`ifdef	AXI3
+		output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_WID,
+`endif
+		output	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_WDATA,
+		output	wire [C_AXI_DATA_WIDTH/8-1:0]	M_AXI_WSTRB,
+		output	wire				M_AXI_WLAST,
+		//
+		//
+		input	wire				M_AXI_BVALID,
+		output	wire				M_AXI_BREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_BID,
+		input	wire	[1:0]			M_AXI_BRESP,
+		//
+		// Then the read interface to read the data back
+		output	wire				M_AXI_ARVALID,
+		input	wire				M_AXI_ARREADY,
+		output	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_ARID,
+		output	wire	[C_AXI_ADDR_WIDTH-1:0]	M_AXI_ARADDR,
+`ifdef	AXI3
+		output	wire	[3:0]			M_AXI_ARLEN,
+`else
+		output	wire	[7:0]			M_AXI_ARLEN,
+`endif
+		output	wire	[2:0]			M_AXI_ARSIZE,
+		output	wire	[1:0]			M_AXI_ARBURST,
+`ifdef	AXI3
+		output	wire	[1:0]			M_AXI_ARLOCK,
+`else
+		output	wire				M_AXI_ARLOCK,
+`endif
+		output	wire	[3:0]			M_AXI_ARCACHE,
+		output	wire	[2:0]			M_AXI_ARPROT,
+		output	wire	[3:0]			M_AXI_ARQOS,
+		//
+		input	wire				M_AXI_RVALID,
+		output	wire				M_AXI_RREADY,
+		input	wire	[C_AXI_ID_WIDTH-1:0]	M_AXI_RID,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]	M_AXI_RDATA,
+		input	wire				M_AXI_RLAST,
+		input	wire	[1:0]			M_AXI_RRESP,
+		// }}}
+		//
+		// {{{
+		// Request a soft-reset: reset the FIFO without resetting th bus
+		input	wire				i_reset,
+		// o_err is a hard error.  If ever true, the core will come
+		// to a hard stop.
+		output	reg				o_err,
+		// o_overflow is an indication of data changing before it is
+		// accepted.
+		output	reg				o_overflow,
+		// o_mm2s_full is a reference to the last FIFO in our
+		// processing pipeline.  It's true if a burst of (1<<LGMAXBURST)
+		// words of (1<<ADDRLSB) bytes may be read from the downstream
+		// FIFO without waiting on the external memory.
+		output	reg				o_mm2s_full,
+		// o_empty is true if nothing is in the core.
+		output	reg				o_empty,
+		// o_fill counts the number of items in the core.  Just because
+		// the number of items is non-zero, however, doesn't mean you
+		// can read them out.  In general, you will need to write at
+		// least a full (1<<LGMAXBURST) words to the core, those will
+		// need to be written to memory, read from memory, and then
+		// used to fill the downstream FIFO before you can read.  This
+		// number is just available for your informational use.
+		output reg [C_AXI_ADDR_WIDTH-ADDRLSB:0]	o_fill
+		// }}}
+		// }}}
+	);
+
+	// Register and signal definitions
+	// {{{
+	localparam	BURSTAW = C_AXI_ADDR_WIDTH-LGMAXBURST-ADDRLSB;
+
+	reg				soft_reset, vfifo_empty, vfifo_full;
+	wire				reset_fifo;
+	reg	[C_AXI_ADDR_WIDTH-ADDRLSB:0]	vfifo_fill;
+	reg	[BURSTAW:0]		mem_data_available_w,
+					writes_outstanding;
+	reg	[BURSTAW:0]		mem_space_available_w,
+					reads_outstanding;
+	reg				s_last_stalled;
+	reg	[C_AXI_DATA_WIDTH-1:0]	s_last_tdata;
+	wire				read_from_fifo, ififo_full, ififo_empty;
+	wire	[C_AXI_DATA_WIDTH-1:0]	ififo_data;
+	wire	[LGFIFO:0]		ififo_fill;
+
+	reg				start_write, phantom_write,
+					axi_awvalid, axi_wvalid, axi_wlast,
+					writes_idle;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	axi_awaddr;
+	reg	[LGMAXBURST:0]		writes_pending;
+
+	reg				start_read, phantom_read, reads_idle,
+					axi_arvalid;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	axi_araddr;
+
+	reg				skd_valid;
+	reg	[C_AXI_DATA_WIDTH-1:0]	skd_data;
+
+	reg	[LGFIFO:0]	ofifo_space_available;
+	wire			write_to_fifo, ofifo_empty, ofifo_full;
+	wire	[LGFIFO:0]	ofifo_fill;
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Global FIFO signal handling
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// A soft reset
+	// {{{
+	// This is how we reset the FIFO without resetting the rest of the AXI
+	// bus.  On a reset request, we raise the soft_reset flag and reset all
+	// of our internal FIFOs.  We also stop issuing bus commands.  Once all
+	// outstanding bus commands come to a halt, then we release from reset
+	// and start operating as a FIFO.
+	initial	soft_reset = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		soft_reset <= 0;
+	else if (i_reset)
+		soft_reset <= 1;
+	else if (writes_idle && reads_idle)
+		soft_reset <= 0;
+
+	assign	reset_fifo = soft_reset || !S_AXI_ARESETN;
+	// }}}
+
+	//
+	// Calculating the fill of the virtual FIFO, and the associated
+	// full/empty flags that go with it
+	// {{{
+	initial	vfifo_fill  = 0;
+	initial	vfifo_empty = 1;
+	initial	vfifo_full  = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || soft_reset)
+	begin
+		vfifo_fill  <= 0;
+		vfifo_empty <= 1;
+		vfifo_full  <= 0;
+	end else case({ S_AXIS_TVALID && S_AXIS_TREADY,
+			M_AXIS_TVALID && M_AXIS_TREADY })
+	2'b10:	begin
+		vfifo_fill  <= vfifo_fill + 1;
+		vfifo_empty <= 0;
+		vfifo_full  <= (&vfifo_fill[C_AXI_ADDR_WIDTH-ADDRLSB-1:0]);
+		end
+	2'b01:	begin
+		vfifo_fill <= vfifo_fill - 1;
+		vfifo_full <= 0;
+		vfifo_empty<= (vfifo_fill <= 1);
+		end
+	default: begin end
+	endcase
+
+	always @(*)
+		o_fill = vfifo_fill;
+
+	always @(*)
+		o_empty = vfifo_empty;
+	// }}}
+
+	// Determining when the write half is idle
+	// {{{
+	// This is required to know when to come out of soft reset.
+	//
+	// The first step is to count the number of bursts that remain
+	// outstanding
+	initial	writes_outstanding = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		writes_outstanding <= 0;
+	else case({ phantom_write,M_AXI_BVALID && M_AXI_BREADY})
+	2'b01: writes_outstanding <= writes_outstanding - 1;
+	2'b10: writes_outstanding <= writes_outstanding + 1;
+	default: begin end
+	endcase
+
+	// The second step is to use this counter to determine if we are idle.
+	// If WVALID is ever high, or start_write goes high, then we are
+	// obviously not idle.  Otherwise, we become idle when the number of
+	// writes outstanding transitions to (or equals) zero.
+	initial	writes_idle = 1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		writes_idle <= 1;
+	else if (start_write || M_AXI_WVALID)
+		writes_idle <= 0;
+	else
+		writes_idle <= (writes_outstanding
+				== ((M_AXI_BVALID && M_AXI_BREADY) ? 1:0));
+	// }}}
+
+	// Count how much space is used in the memory device
+	// {{{
+	// Well, obviously, we can't fill our memory device or we have problems.
+	// To make sure we don't overflow, we count memory usage here.  We'll
+	// count memory usage in units of bursts of (1<<LGMAXBURST) words of
+	// (1<<ADDRLSB) bytes each.  So ... here we count the amount of device
+	// memory that hasn't (yet) been committed.  This is different from the
+	// memory used (which we don't calculate), or the memory which may yet
+	// be read--which we'll calculate in a moment.
+	initial	mem_space_available_w = (1<<BURSTAW);
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || soft_reset)
+		mem_space_available_w <= (1<<BURSTAW);
+	else case({ phantom_write,M_AXI_RVALID && M_AXI_RREADY && M_AXI_RLAST })
+	2'b01: mem_space_available_w <= mem_space_available_w + 1;
+	2'b10: mem_space_available_w <= mem_space_available_w - 1;
+	default: begin end
+	endcase
+	// }}}
+
+	// Determining when the read half is idle
+	// {{{
+	// Count the number of read bursts that we've committed to.  This
+	// includes bursts that have ARVALID but haven't been accepted, as well
+	// as any the downstream device will yet return an RLAST for.
+	initial	reads_outstanding = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		reads_outstanding <= 0;
+	else case({ phantom_read,M_AXI_RVALID && M_AXI_RREADY && M_AXI_RLAST})
+	2'b01: reads_outstanding <= reads_outstanding - 1;
+	2'b10: reads_outstanding <= reads_outstanding + 1;
+	default: begin end
+	endcase
+
+	// Now, using the reads_outstanding counter, we can check whether or not
+	// we are idle (and can exit a reset) of if instead there are more
+	// bursts outstanding to wait for.
+	//
+	// By registering this counter, we can keep the soft_reset release
+	// simpler.  At least this way, it doesn't need to check two counters
+	// for zero.
+	initial	reads_idle = 1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		reads_idle <= 1;
+	else if (start_read || M_AXI_ARVALID)
+		reads_idle <= 0;
+	else
+		reads_idle <= (reads_outstanding
+		== ((M_AXI_RVALID && M_AXI_RREADY && M_AXI_RLAST) ? 1:0));
+	// }}}
+
+	// Count how much data is in the memory device that we can read out
+	// {{{
+	// In AXI, after you issue a write, you can't depend upon that data
+	// being present on the device and available for a read until the
+	// associated BVALID is returned.  Therefore we don't count any memory
+	// as available to be read until BVALID comes back.  Once a read
+	// command is issued, the memory is again no longer available to be
+	// read.  Note also that we are counting bursts here.  A second
+	// conversion below converts this count to bytes.
+	initial	mem_data_available_w = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || soft_reset)
+		mem_data_available_w <= 0;
+	else case({ M_AXI_BVALID, phantom_read })
+	2'b10: mem_data_available_w <= mem_data_available_w + 1;
+	2'b01: mem_data_available_w <= mem_data_available_w - 1;
+	default: begin end
+	endcase
+	// }}}
+
+	//
+	// Error detection
+	// {{{
+	initial	o_err = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		o_err <= 1'b0;
+	else begin
+		if (M_AXI_BVALID && M_AXI_BRESP[1])
+			o_err <= 1'b1;
+		if (M_AXI_RVALID && M_AXI_RRESP[1])
+			o_err <= 1'b1;
+	end
+	// }}}
+
+	//
+	// Incoming stream overflow detection
+	// {{{
+	// The overflow flag is set if ever an incoming value violates the
+	// stream protocol and changes while stalled.  Internally, however,
+	// the overflow flag is ignored.  It's provided for your information.
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		s_last_stalled <= 0;
+	else
+		s_last_stalled <= S_AXIS_TVALID && !S_AXIS_TREADY;
+
+	always @(posedge S_AXI_ACLK)
+	if (S_AXIS_TVALID)
+		s_last_tdata <= S_AXIS_TDATA;
+
+	initial	o_overflow = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || soft_reset)
+		o_overflow <= 0;
+	else if (s_last_stalled)
+	begin
+		if (!S_AXIS_TVALID)
+			o_overflow <= 1;
+		if (S_AXIS_TDATA != s_last_tdata)
+			o_overflow <= 1;
+	end
+	// }}}
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Incoming FIFO
+	// {{{
+	// Incoming data stream info the FIFO
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	assign	S_AXIS_TREADY = !reset_fifo && !ififo_full && !vfifo_full;
+	assign	read_from_fifo= (!skd_valid || (M_AXI_WVALID && M_AXI_WREADY));
+
+	sfifo #(.BW(C_AXIS_DATA_WIDTH), .LGFLEN(LGFIFO))
+	ififo(S_AXI_ACLK, reset_fifo,
+		S_AXIS_TVALID && S_AXIS_TREADY,
+			S_AXIS_TDATA, ififo_full, ififo_fill,
+		read_from_fifo, ififo_data, ififo_empty);
+
+	//
+	// We need a quick 1-element buffer here in order to keep the soft
+	// reset, which resets the FIFO pointer, from adjusting any FIFO data.
+	// {{{
+	// Here's the rule: we need to fill the buffer before it ever gets
+	// used.  Then, once used, it should be able to maintain 100%
+	// throughput.
+	initial	skd_valid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (reset_fifo)
+		skd_valid <= 0;
+	else if (!ififo_empty)
+		skd_valid <= 1;
+	else if (M_AXI_WVALID && M_AXI_WREADY)
+		skd_valid <= 0;
+
+	always @(posedge S_AXI_ACLK)
+	if (!M_AXI_WVALID || M_AXI_WREADY)
+	begin
+		if (!skd_valid || M_AXI_WREADY)
+			skd_data <= ififo_data;
+	end
+	// }}}
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI write processing
+	// {{{
+	// Write data from our FIFO onto the bus
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// start_write: determining when to issue a write burst
+	// {{{
+	always @(*)
+	begin
+		start_write = 0;
+
+		if (ififo_fill >= (1<<LGMAXBURST))
+			start_write = 1;
+		if (vfifo_full || soft_reset || phantom_write)
+			start_write = 0;
+		if (mem_space_available_w == 0)
+			start_write = 0;
+
+		if (M_AXI_WVALID && (!M_AXI_WREADY || !M_AXI_WLAST))
+			start_write = 0;
+		if (M_AXI_AWVALID && !M_AXI_AWREADY)
+			start_write = 0;
+		if (o_err)
+			start_write = 0;
+	end
+	// }}}
+
+	// Register the start write signal into AWVALID and phantom write
+	// {{{
+	// phantom_write contains the start signal, but immediately clears
+	// on the next clock cycle.  This allows us some time to calculate
+	// the data for the next burst which and if AWVALID remains high and
+	// not yet accepted.
+	initial	phantom_write = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		phantom_write <= 0;
+	else
+		phantom_write <= start_write;
+
+	// Set AWVALID to start_write if every the channel isn't stalled.
+	// Incidentally, start_write is guaranteed to be zero if the channel
+	// is stalled, since that signal is used by other things as well.
+	initial	axi_awvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_awvalid <= 0;
+	else if (!M_AXI_AWVALID || M_AXI_AWREADY)
+		axi_awvalid <= start_write;
+	// }}}
+
+	// Write address
+	// {{{
+	// We insist on alignment.  On every accepted burst, we step forward by
+	// one burst length.  On reset, we reset the address at our first
+	// opportunity.
+	initial	axi_awaddr = 0;
+	always @(posedge S_AXI_ACLK)
+	begin
+		if (M_AXI_AWVALID && M_AXI_AWREADY)
+			axi_awaddr[C_AXI_ADDR_WIDTH-1:LGMAXBURST+ADDRLSB]
+			<= axi_awaddr[C_AXI_ADDR_WIDTH-1:LGMAXBURST+ADDRLSB] +1;
+
+		if ((!M_AXI_AWVALID || M_AXI_AWREADY) && soft_reset)
+			axi_awaddr <= 0;
+
+		if (!S_AXI_ARESETN)
+			axi_awaddr <= 0;
+
+		axi_awaddr[LGMAXBURST+ADDRLSB-1:0] <= 0;
+	end
+	// }}}
+
+	// Write data channel valid
+	// {{{
+	initial	axi_wvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_wvalid <= 0;
+	else if (start_write)
+		axi_wvalid <= 1;
+	else if (!M_AXI_WVALID || M_AXI_WREADY)
+		axi_wvalid <= M_AXI_WVALID && !M_AXI_WLAST;
+	// }}}
+
+	// WLAST generation
+	// {{{
+	// On the beginning of any burst, start a counter of the number of items
+	// in it.  Once the counter gets to 1, set WLAST.
+	initial	writes_pending = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		writes_pending <= 0;
+	else if (start_write)
+		writes_pending <= (1<<LGMAXBURST);
+	else if (M_AXI_WVALID && M_AXI_WREADY)
+		writes_pending <= writes_pending -1;
+
+	always @(posedge S_AXI_ACLK)
+	if (start_write)
+		axi_wlast <= (LGMAXBURST == 0);
+	else if (!M_AXI_WVALID || M_AXI_WREADY)
+		axi_wlast <= (writes_pending == 1 + (M_AXI_WVALID ? 1:0));
+	// }}}
+
+	// Bus assignments based upon the above
+	// {{{
+	assign	M_AXI_AWVALID = axi_awvalid;
+	assign	M_AXI_AWID    = AXI_WRITE_ID;
+	assign	M_AXI_AWADDR  = axi_awaddr;
+	assign	M_AXI_AWLEN   = (1<<LGMAXBURST)-1;
+	assign	M_AXI_AWSIZE  = ADDRLSB[2:0];
+	assign	M_AXI_AWBURST = 2'b01;
+	assign	M_AXI_AWLOCK  = 0;
+	assign	M_AXI_AWCACHE = 0;
+	assign	M_AXI_AWPROT  = 0;
+	assign	M_AXI_AWQOS   = 0;
+
+	assign	M_AXI_WVALID = axi_wvalid;
+	assign	M_AXI_WDATA  = skd_data;
+`ifdef	AXI3
+	assign	M_AXI_WID    = AXI_WRITE_ID;
+`endif
+	assign	M_AXI_WLAST  = axi_wlast;
+	assign	M_AXI_WSTRB  = -1;
+
+	assign	M_AXI_BREADY = 1;
+	// }}}
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI read processing
+	// {{{
+	// Read data into our FIFO
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// How much FIFO space is available?
+	// {{{
+	// One we issue a read command, the FIFO space isn't available any more.
+	// That way we can determine when a second read can be issued--even
+	// before the first has returned--while also guaranteeing that there's
+	// always room in the outgoing FIFO for anything that might return.
+	// Remember: NEVER generate backpressure in a bus master
+	initial	ofifo_space_available = (1<<LGFIFO);
+	always @(posedge S_AXI_ACLK)
+	if (reset_fifo)
+		ofifo_space_available <= (1<<LGFIFO);
+	else case({phantom_read, M_AXIS_TVALID && M_AXIS_TREADY})
+	2'b10:	ofifo_space_available <= ofifo_space_available - (1<<LGMAXBURST);
+	2'b01:	ofifo_space_available <= ofifo_space_available + 1;
+	2'b11:	ofifo_space_available <= ofifo_space_available - (1<<LGMAXBURST) + 1;
+	default: begin end
+	endcase
+	// }}}
+
+	// Determine when to start a next read-from-memory-to-FIFO burst
+	// {{{
+	always @(*)
+	begin
+		start_read = 1;
+
+		// We can't read yet if we don't have space available.
+		// Note the comparison is carefully chosen to make certain
+		// it doesn't use all ofifo_space_available bits, but rather
+		// only the number of bits between LGFIFO and
+		// LGMAXBURST--nominally a single bit.
+		if (ofifo_space_available < (1<<LGMAXBURST))	// FIFO space ?
+			start_read = 0;
+
+		// If there's no memory available for us to read from, then
+		// we can't start a read yet.
+		if (!M_AXI_BVALID && mem_data_available_w == 0)
+			start_read = 0;
+
+		// Don't start anything while waiting on a reset.  Likewise,
+		// insist on a minimum one clock between read burst issuances.
+		if (soft_reset || phantom_read)
+			start_read = 0;
+
+		// We can't start a read request if the AR* channel is stalled
+		if (M_AXI_ARVALID && !M_AXI_ARREADY)
+			start_read = 0;
+
+		// Following a bus error, we come to a complete halt.  Such a
+		// bus error is an indication that something *SERIOUSLY* went
+		// wrong--perhaps we aren't accessing the memory we are supposed
+		// to.  To prevent damage to external devices, we disable
+		// ourselves entirely.  There is no fall back.  We only
+		// restart on a full bus restart.
+		if (o_err)
+			start_read = 0;
+	end
+	// }}}
+
+	// Set phantom_read and ARVALID
+	// {{{
+	initial	phantom_read = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		phantom_read <= 0;
+	else
+		phantom_read <= start_read;
+
+	initial	axi_arvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_arvalid <= 0;
+	else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+		axi_arvalid <= start_read;
+	// }}}
+
+	// Calculate the next ARADDR
+	// {{{
+	initial	axi_araddr = 0;
+	always @(posedge S_AXI_ACLK)
+	begin
+		if (M_AXI_ARVALID && M_AXI_ARREADY)
+			axi_araddr[C_AXI_ADDR_WIDTH-1:LGMAXBURST+ADDRLSB]
+			<= axi_araddr[C_AXI_ADDR_WIDTH-1:LGMAXBURST+ADDRLSB]+ 1;
+
+		if ((!M_AXI_ARVALID || M_AXI_ARREADY) && soft_reset)
+			axi_araddr <= 0;
+
+		if (!S_AXI_ARESETN)
+			axi_araddr <= 0;
+
+		axi_araddr[LGMAXBURST+ADDRLSB-1:0] <= 0;
+	end
+	// }}}
+
+	// Assign values to our bus wires
+	// {{{
+	assign	M_AXI_ARVALID = axi_arvalid;
+	assign	M_AXI_ARID    = AXI_READ_ID;
+	assign	M_AXI_ARADDR  = axi_araddr;
+	assign	M_AXI_ARLEN   = (1<<LGMAXBURST)-1;
+	assign	M_AXI_ARSIZE  = ADDRLSB[2:0];
+	assign	M_AXI_ARBURST = 2'b01;
+	assign	M_AXI_ARLOCK  = 0;
+	assign	M_AXI_ARCACHE = 0;
+	assign	M_AXI_ARPROT  = 0;
+	assign	M_AXI_ARQOS   = 0;
+
+	assign	M_AXI_RREADY = 1;
+	// }}}
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Outgoing AXI stream processing
+	// {{{
+	// Send data out from the MM2S FIFO
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// We basically just stuff the data read from memory back into our
+	// outgoing FIFO here.  The logic is quite straightforward.
+	assign	write_to_fifo = M_AXI_RVALID && M_AXI_RREADY;
+	assign	M_AXIS_TVALID = !ofifo_empty;
+
+	sfifo #(.BW(C_AXIS_DATA_WIDTH), .LGFLEN(LGFIFO))
+	ofifo(S_AXI_ACLK, reset_fifo,
+		write_to_fifo,
+			M_AXI_RDATA, ofifo_full, ofifo_fill,
+		M_AXIS_TVALID && M_AXIS_TREADY, M_AXIS_TDATA, ofifo_empty);
+
+	always @(*)
+		o_mm2s_full = |ofifo_fill[LGFIFO:LGMAXBURST];
+	// }}}
+
+	// Keep Verilator happy
+	// {{{
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, M_AXI_BID, M_AXI_RID,
+			M_AXI_BRESP[0], M_AXI_RRESP[0],
+			ififo_empty, ofifo_full, ofifo_fill
+			// fifo_full, fifo_fill, fifo_empty,
+			};
+
+	// Verilator lint_on UNUSED
+	// }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal property section
+// {{{
+//
+// The following are a subset of the formal properties used to verify this
+// core.  The full set of formal properties, together with the formal
+// property set itself, are available for purchase.
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	// FAXI_DEPTH controls the width of the counters in the bus property
+	// interface file.  In order to support bursts of length 8 (or more),
+	// there's a minimum of 9.  Otherwise, we'll just set this to the width
+	// of the AXI address bus.
+	localparam	FAXI_DEPTH = (C_AXI_ADDR_WIDTH > 8)
+					? (C_AXI_ADDR_WIDTH+1) : 9;
+
+	reg	f_past_valid;
+
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+
+	//
+	// Wires necessary for interacting with the formal property file
+	// {{{
+	// ...
+	// }}}
+
+	// Other registers to keep simplify keeping track of our progress
+	// {{{
+	reg	[C_AXI_ADDR_WIDTH-1:0]	faxi_rd_cknext, faxi_wr_cknext,
+					f_read_beat_addr, f_write_beat_addr,
+					faxi_read_beat_addr;
+	reg	[C_AXI_ADDR_WIDTH-1:0]	f_read_ckbeat_addr;
+	reg	[FAXI_DEPTH-1:0]	f_rd_bursts_after_check;
+
+	reg	[C_AXI_ADDR_WIDTH:0]	f_vfill;
+	reg	[C_AXI_ADDR_WIDTH:0]	f_space_available,
+					f_data_available;
+
+	reg	[C_AXI_ADDR_WIDTH-1:0]	f_read_checksum;
+	reg	[C_AXI_ADDR_WIDTH:0]	mem_space_available, mem_data_available;
+	// }}}
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The main AXI data interface bus property check
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	faxi_master #(
+		// {{{
+		.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.OPT_MAXBURST(MAXBURST-1),
+		.OPT_NARROW_BURST(1'b0),
+		.OPT_ASYNC_RESET(1'b0),	// We don't use asynchronous resets
+		.OPT_EXCLUSIVE(1'b0),	// We don't use the LOCK signal
+		.F_OPT_ASSUME_RESET(1'b1), // We aren't generating the reset
+		.F_OPT_NO_RESET(1'b1),
+		.F_LGDEPTH(FAXI_DEPTH)	// Width of the counters
+		// }}}
+	) faxi(
+		// {{{
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		// Write signals
+		// {{{
+		.i_axi_awvalid(M_AXI_AWVALID),
+		.i_axi_awready(M_AXI_AWREADY),
+		.i_axi_awid(   M_AXI_AWID),
+		.i_axi_awaddr( M_AXI_AWADDR),
+		.i_axi_awlen(  M_AXI_AWLEN),
+		.i_axi_awsize( M_AXI_AWSIZE),
+		.i_axi_awburst(M_AXI_AWBURST),
+		.i_axi_awlock( M_AXI_AWLOCK),
+		.i_axi_awcache(M_AXI_AWCACHE),
+		.i_axi_awprot( M_AXI_AWPROT),
+		.i_axi_awqos(  M_AXI_AWQOS),
+		//
+		.i_axi_wvalid(M_AXI_WVALID),
+		.i_axi_wready(M_AXI_WREADY),
+		.i_axi_wdata( M_AXI_WDATA),
+		.i_axi_wstrb( M_AXI_WSTRB),
+		.i_axi_wlast( M_AXI_WLAST),
+		//
+		.i_axi_bvalid(M_AXI_BVALID),
+		.i_axi_bready(M_AXI_BREADY),
+		.i_axi_bid(   M_AXI_BID),
+		.i_axi_bresp( M_AXI_BRESP),
+		// }}}
+		// Read signals
+		// {{{
+		.i_axi_arvalid(M_AXI_ARVALID),
+		.i_axi_arready(M_AXI_ARREADY),
+		.i_axi_arid(   M_AXI_ARID),
+		.i_axi_araddr( M_AXI_ARADDR),
+		.i_axi_arlen(  M_AXI_ARLEN),
+		.i_axi_arsize( M_AXI_ARSIZE),
+		.i_axi_arburst(M_AXI_ARBURST),
+		.i_axi_arlock( M_AXI_ARLOCK),
+		.i_axi_arcache(M_AXI_ARCACHE),
+		.i_axi_arprot( M_AXI_ARPROT),
+		.i_axi_arqos(  M_AXI_ARQOS),
+		//
+		//
+		.i_axi_rvalid(M_AXI_RVALID),
+		.i_axi_rready(M_AXI_RREADY),
+		.i_axi_rid(   M_AXI_RID),
+		.i_axi_rdata( M_AXI_RDATA),
+		.i_axi_rlast( M_AXI_RLAST),
+		.i_axi_rresp( M_AXI_RRESP),
+		// }}}
+		// Induction signals
+		// {{{
+		// ...
+		// }}}
+		// }}}
+	);
+
+	// Some quick sanity checks
+	// {{{
+	always @(*)
+	begin
+		//
+		// ...
+		//
+	end
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write sanity checking
+	// {{{
+	always @(*)
+		mem_space_available = { mem_space_available_w,
+			{(LGMAXBURST+ADDRLSB){1'b0} } };
+
+	// Let's calculate the address of each write beat
+	// {{{
+	initial	f_write_beat_addr = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_write_beat_addr <= 0;
+	else if ((!M_AXI_WVALID || (M_AXI_WREADY && M_AXI_WLAST)) && soft_reset)
+		f_write_beat_addr <= 0;
+	else if (M_AXI_WVALID && M_AXI_WREADY)
+		f_write_beat_addr <= f_write_beat_addr + (1<<ADDRLSB);
+	// }}}
+
+	//
+	// ...
+	//
+
+	// Verify during any write burst that all the burst parameters are
+	// correct
+	// {{{
+	// ...
+	// }}}
+
+	always @(*)
+	if (M_AXI_AWVALID)
+	begin
+		assert(writes_pending == (1<<LGMAXBURST));
+		// ...
+	end else
+		// ...
+
+	always @(*)
+		assert(M_AXI_WVALID == (writes_pending != 0));
+
+	//
+	// ...
+	//
+
+	// Check the writes-idle signal
+	// {{{
+	// ...
+	// }}}
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read sanity checking
+	// {{{
+
+	always @(*)
+		mem_data_available = { mem_data_available_w,
+			{(LGMAXBURST+ADDRLSB){1'b0} } };
+	//
+	// ...
+	// Check the reads-idle signal
+	// {{{
+	// ...
+	// }}}
+
+	// Regenerate the read beat address
+	// {{{
+	// This works because we are using a single AXI ID for all of our reads.
+	// Therefore we can guarantee that reads will come back in order, thus
+	// we can count the return address here.
+	initial	f_read_beat_addr = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_read_beat_addr <= 0;
+	else if (soft_reset && reads_idle)
+		f_read_beat_addr <= 0;
+	else if (M_AXI_RVALID && M_AXI_RREADY)
+		f_read_beat_addr <= f_read_beat_addr + (1<<ADDRLSB);
+	// }}}
+
+	// Read burst checking
+	// {{{
+
+	//
+	// ...
+	//
+
+	// }}}
+
+
+	// Match our read beat address to ARADDR
+	// {{{
+	// ...
+	// }}}
+
+	// Insist that our burst counters are consistent with bursts of a full
+	// length only
+	// {{{
+	// ...
+	// }}}
+
+	// RLAST checking
+	// {{{
+	// ...
+	// }}}
+
+	// Match the read beat address to the number of items remaining in this
+	// burst
+	// {{{
+	// ...
+	// }}}
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Internal assertions (Induction)
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// On either error, or while waiting for a soft reset to complete
+	// nothing new should issue
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && ($past(soft_reset) || $past(o_err)))
+	begin
+		assert(!$rose(M_AXI_AWVALID));
+		assert(!$rose(M_AXI_WVALID));
+		assert(!$rose(M_AXI_ARVALID));
+		assert(!phantom_write);
+		assert(!phantom_read);
+	end
+	// }}}
+
+	//
+	// Writes and reads always have enough room
+
+	// Bus writes aren't allowed to drain the incoming FIFO dry
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!soft_reset && M_AXI_WVALID)
+		assert(ififo_fill + (skd_valid ? 1:0) >= writes_pending);
+	// }}}
+
+	// Bus reads aren't allowed to overflow the return FIFO
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (!soft_reset && M_AXI_RVALID)
+		assert(!ofifo_full);
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write checks
+	//
+
+	// Make sure the skid buffer only reads when either there's nothing
+	// held in the buffer, or the write channel has accepted data.  Indeed,
+	// the write channel should never be active unless the skid buffer is
+	// full.
+	// {{{
+	always @(*)
+	if (!soft_reset && !skd_valid)
+		assert(!M_AXI_WVALID);
+
+	always @(*)
+	if (M_AXI_WVALID && M_AXI_WREADY)
+		assert(read_from_fifo);
+	else if (!skd_valid && !ififo_empty)
+		assert(read_from_fifo);
+	// }}}
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read checks
+	// {{{
+
+	// No read checks in addition to the ones above
+
+	// }}}
+
+	////////////////////////////////////////
+	//
+	// Errors or resets -- do we properly end gracefully
+	//
+	// {{{
+	// Set o_err on any bus error.  Only clear it on reset
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $past(S_AXI_ARESETN))
+	begin
+		if ($past(M_AXI_BVALID && M_AXI_BRESP[1]))
+			assert(o_err);
+		if ($past(M_AXI_RVALID && M_AXI_RRESP[1]))
+			assert(o_err);
+		if ($past(!M_AXI_BVALID || !M_AXI_BRESP[1])
+			&& $past(!M_AXI_RVALID || !M_AXI_RRESP[1]))
+			assert(!$rose(o_err));
+	end
+
+	// Only release soft_reset once the bus is idle
+	// {{{
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $past(S_AXI_ARESETN) && $fell(soft_reset))
+	begin
+		//
+		// ...
+		//
+		assert(!M_AXI_AWVALID);
+		assert(!M_AXI_WVALID);
+		assert(!M_AXI_ARVALID);
+	end
+	// }}}
+	// }}}
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// FIFO checks
+	// {{{
+
+	// Check the global fill/emtpy values
+	// {{{
+	always @(*)
+		assert(vfifo_full == (vfifo_fill == (1<<(C_AXI_ADDR_WIDTH-ADDRLSB))));
+
+	always @(*)
+		assert(vfifo_fill <= (1<<(C_AXI_ADDR_WIDTH-ADDRLSB)));
+
+	always @(*)
+		assert(vfifo_empty == (vfifo_fill == 0));
+	// }}}
+
+	// An equation for vfill based upon our property checker's counters
+	// {{{
+	always @(*)
+	begin
+		f_vfill = M_AXI_AWADDR - M_AXI_ARADDR;
+		f_vfill[C_AXI_ADDR_WIDTH] = 0;
+		if (!M_AXI_AWVALID)
+			f_vfill = f_vfill - (writes_pending << ADDRLSB);
+		// ...
+		if (skd_valid)
+			f_vfill = f_vfill + (1<<ADDRLSB);
+		f_vfill = f_vfill + ((ififo_fill + ofifo_fill)<<ADDRLSB);
+	end
+	// }}}
+
+	// Make sure the virtual FIFO's fill matches that counter
+	// {{{
+	always @(*)
+	if (!soft_reset)
+	begin
+		assert(vfifo_fill == (f_vfill >> ADDRLSB));
+		assert(f_vfill <= (1<<(C_AXI_ADDR_WIDTH)));
+
+		// Before the equation check, double check that we
+		// don't overflow any of our arithmetic.  Then check our
+		// virtual FIFO's fill counter against the various internal
+		// FIFO fills and read counters.
+
+		// These are just inequality checks, however, so we'll still
+		// need a full equation check elsewhere
+		//
+		// ...
+		//
+	end
+
+	// Make certain we aren't overflowing in our subtraction above
+	always @(*)
+	if (M_AXI_ARVALID && !soft_reset)
+		assert(M_AXI_ARADDR != M_AXI_AWADDR);
+	// }}}
+
+	// Check mem_space_available
+	// {{{
+	always @(*)
+	begin
+		f_space_available = (M_AXI_AWADDR - M_AXI_ARADDR);
+		f_space_available[C_AXI_ADDR_WIDTH] = 0;
+		f_space_available = (1<<C_AXI_ADDR_WIDTH) - f_space_available;
+		if (M_AXI_AWVALID && !phantom_write)
+			f_space_available = f_space_available
+					- (1 << (LGMAXBURST+ADDRLSB));
+		//
+		// ...
+	end
+
+	always @(*)
+	begin
+		assert({ mem_data_available_w, {(LGMAXBURST){1'b0}} }
+			<= vfifo_fill);
+		// ...
+		assert(mem_data_available  <= (1<<C_AXI_ADDR_WIDTH));
+		assert(mem_space_available <= (1<<C_AXI_ADDR_WIDTH));
+		if (!soft_reset)
+		begin
+			assert(mem_space_available == f_space_available);
+
+			if (mem_space_available[C_AXI_ADDR_WIDTH])
+			begin
+				assert(M_AXI_ARADDR == M_AXI_AWADDR);
+				assert(!M_AXI_AWVALID || phantom_write);
+				// ...
+			end
+		end
+	end
+	// }}}
+
+	// Check mem_data_available
+	// {{{
+	// First, generate an equation to describe it
+	always @(*)
+	begin
+		f_data_available = M_AXI_AWADDR - M_AXI_ARADDR;
+		f_data_available[C_AXI_ADDR_WIDTH] = 0;
+		// ...
+		if (M_AXI_ARVALID && !phantom_read)
+			f_data_available = f_data_available
+				- (1 << (ADDRLSB + LGMAXBURST));
+	end
+
+	// Then compare it against that equation
+	always @(*)
+	if (!soft_reset)
+	begin
+		assert(mem_data_available == f_data_available);
+		if (mem_data_available[C_AXI_ADDR_WIDTH])
+		begin
+			assert(vfifo_fill[C_AXI_ADDR_WIDTH]);
+			assert(ofifo_empty);
+		end
+	end
+	// }}}
+
+	// ofifo_space_available
+	// {{{
+	always @(*)
+	if (!reset_fifo)
+	begin
+		// ...
+
+		// Make sure we don't overflow above
+		assert(ofifo_space_available <= (1<<LGFIFO));
+	end
+	// }}}
+
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Initial (only) constraints
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(posedge S_AXI_ACLK)
+	if (!f_past_valid || $past(!S_AXI_ARESETN))
+	begin
+		assert(!M_AXI_AWVALID);
+		assert(!M_AXI_WVALID);
+		assert(!M_AXI_ARVALID);
+
+		assert(mem_space_available == (1<<C_AXI_ADDR_WIDTH));
+		assert(mem_data_available  == 0);
+
+		assert(!phantom_read);
+		assert(!phantom_write);
+
+		assert(vfifo_fill == 0);
+	end
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Formal contract checking
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// This core doesn't (yet) have any formal contract check
+
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	[2:0]		cvr_write_bursts, cvr_read_bursts;
+	(* anyconst *)	reg	cvr_high_speed;
+
+	always @(posedge S_AXI_ACLK)
+	if (cvr_high_speed)
+	begin
+		assume(!$fell(S_AXIS_TVALID));
+		// if (S_AXI_ARESETN && $past(S_AXIS_TVALID && !S_AXIS_TREADY))
+			// assume(S_AXIS_TVALID && $stable(S_AXIS_TDATA));
+
+		assume(M_AXI_AWREADY || writes_pending > 0);
+		assume(M_AXIS_TREADY);
+		assume(M_AXI_WREADY);
+		assume(M_AXI_ARREADY);
+	end
+
+	initial	cvr_write_bursts = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || soft_reset || o_err || o_overflow)
+		cvr_write_bursts <= 0;
+	else if (M_AXI_BVALID && !cvr_write_bursts[2])
+		cvr_write_bursts <= cvr_write_bursts + 1;
+
+	initial	cvr_read_bursts = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN || soft_reset || o_err || o_overflow)
+		cvr_read_bursts <= 0;
+	else if (M_AXI_RVALID && M_AXI_RLAST && !cvr_read_bursts[2])
+		cvr_read_bursts <= cvr_read_bursts + 1;
+
+	//
+	// ...
+	//
+
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARESETN && !soft_reset)
+		cover(cvr_read_bursts > 1 && cvr_write_bursts > 1);
+
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARESETN && !soft_reset)
+		cover(cvr_read_bursts > 1 && cvr_write_bursts > 1
+							&& cvr_high_speed);
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Careless assumptions (i.e. constraints)
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// No careless assumptions.  Indeed, no assumptions at all beyond
+	// what's in the bus property file, and some optional cover assumptions.
+
+	// }}}
+	// }}}
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axixbar.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axixbar.v
new file mode 100644
index 0000000..3044565
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axixbar.v
@@ -0,0 +1,2477 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axixbar.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Create a full crossbar between NM AXI sources (masters), and NS
+//		AXI slaves.  Every master can talk to any slave, provided it
+//	isn't already busy.
+// {{{
+// Performance:	This core has been designed with the goal of being able to push
+//		one transaction through the interconnect, from any master to
+//	any slave, per clock cycle.  This may perhaps be its most unique
+//	feature.  While throughput is good, latency is something else.
+//
+//	The arbiter requires a clock to switch, then another clock to send data
+//	downstream.  This creates a minimum two clock latency up front.  The
+//	return path suffers another clock of latency as well, placing the
+//	minimum latency at four clocks.  The minimum write latency is at
+//	least one clock longer, since the write data must wait for the write
+//	address before proceeeding.
+//
+//	Note that this arbiter only forwards AxID fields.  It does not use
+//	them in arbitration.  As a result, only one master may ever make
+//	requests of any given slave at a time.  All responses from a slave
+//	will be returned to that known master.  This is a known limitation in
+//	this implementation which will be fixed (in time) with funding and
+//	interest.  Until that time, in order for a second master to access
+//	a given slave, the first master must receive all of its acknowledgments.
+//
+// Usage:	To use, you must first set NM and NS to the number of masters
+//	and the number of slaves you wish to connect to.  You then need to
+//	adjust the addresses of the slaves, found SLAVE_ADDR array.  Those
+//	bits that are relevant in SLAVE_ADDR to then also be set in SLAVE_MASK.
+//	Adjusting the data and address widths go without saying.
+//
+//	Lower numbered masters are given priority in any "fight".
+//
+//	Channel grants are given on the condition that 1) they are requested,
+//	2) no other channel has a grant, 3) all of the responses have been
+//	received from the current channel, and 4) the internal counters are
+//	not overflowing.
+//
+//	The core limits the number of outstanding transactions on any channel to
+//	1<<LGMAXBURST-1.
+//
+//	Channel grants are lost 1) after OPT_LINGER clocks of being idle, or
+//	2) when another master requests an idle (but still lingering) channel
+//	assignment, or 3) once all the responses have been returned to the
+//	current channel, and the current master is requesting another channel.
+//
+//	A special slave is allocated for the case of no valid address.
+//
+//	Since the write channel has no address information, the write data
+//	channel always be delayed by at least one clock from the write address
+//	channel.
+//
+//	If OPT_LOWPOWER is set, then unused values will be set to zero.
+//	This can also be used to help identify relevant values within any
+//	trace.
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+// }}}
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+//
+`default_nettype none
+//
+module	axixbar #(
+		// {{{
+		parameter integer C_AXI_DATA_WIDTH = 32,
+		parameter integer C_AXI_ADDR_WIDTH = 32,
+		parameter integer C_AXI_ID_WIDTH = 2,
+		//
+		// NM is the number of masters driving incoming slave channels
+		parameter	NM = 4,
+		//
+		// NS is the number of slaves connected to the crossbar
+		parameter	NS = 8,
+		//
+		// IW, AW, and DW, are short-hand abbreviations used locally.
+		localparam	IW = C_AXI_ID_WIDTH,
+		localparam	AW = C_AXI_ADDR_WIDTH,
+		localparam	DW = C_AXI_DATA_WIDTH,
+		//
+		// SLAVE_ADDR is an array of addresses, describing each of
+		// {{{
+		// the slave channels.  It works tightly with SLAVE_MASK,
+		// so that when (ADDR & MASK == ADDR), the channel in question
+		// has been requested.
+		//
+		// It is an internal in the setup of this core to doubly map
+		// an address, such that (addr & SLAVE_MASK[k])==SLAVE_ADDR[k]
+		// for two separate values of k.
+		//
+		// Any attempt to access an address that is a hole in this
+		// address list will result in a returned xRESP value of
+		// INTERCONNECT_ERROR (2'b11)
+		parameter	[NS*AW-1:0]	SLAVE_ADDR = {
+			3'b111,  {(AW-3){1'b0}},
+			3'b110,  {(AW-3){1'b0}},
+			3'b101,  {(AW-3){1'b0}},
+			3'b100,  {(AW-3){1'b0}},
+			3'b011,  {(AW-3){1'b0}},
+			3'b010,  {(AW-3){1'b0}},
+			4'b0001, {(AW-4){1'b0}},
+			4'b0000, {(AW-4){1'b0}} },
+		// }}}
+		//
+		// SLAVE_MASK: is an array, much like SLAVE_ADDR, describing
+		// {{{
+		// which of the bits in SLAVE_ADDR are relevant.  It is
+		// important to maintain for every slave that
+		// 	(~SLAVE_MASK[i] & SLAVE_ADDR[i]) == 0.
+		// Verilator lint_off WIDTH
+		parameter	[NS*AW-1:0]	SLAVE_MASK =
+			(NS <= 1) ? { 4'b1111, {(AW-4){1'b0}} }
+			: { {(NS-2){ 3'b111, {(AW-3){1'b0}} }},
+				{(2){ 4'b1111, {(AW-4){1'b0}} } } },
+		// Verilator lint_on  WIDTH
+		// }}}
+		//
+		// OPT_LOWPOWER: If set, it forces all unused values to zero,
+		// {{{
+		// preventing them from unnecessarily toggling.  This will
+		// raise the logic count of the core, but might also lower
+		// the power used by the interconnect and the bus driven wires
+		// which (in my experience) tend to have a high fan out.
+		parameter [0:0]	OPT_LOWPOWER = 0,
+		// }}}
+		//
+		// OPT_LINGER: Set this to the number of clocks an idle
+		// {{{
+		// channel shall be left open before being closed.  Once
+		// closed, it will take a minimum of two clocks before the
+		// channel can be opened and data transmitted through it again.
+		parameter	OPT_LINGER = 4,
+		// }}}
+		//
+		// [EXPERIMENTAL] OPT_QOS: If set, the QOS transmission values
+		// {{{
+		// will be honored when determining who wins arbitration for
+		// accessing a given slave.  (This feature has not yet been
+		// verified)
+		parameter [0:0]	OPT_QOS = 0,
+		// }}}
+		//
+		// LGMAXBURST: Specifies the log based two of the maximum
+		// {{{
+		// number of bursts transactions that may be outstanding at any
+		// given time.  This is different from the maximum number of
+		// outstanding beats.
+		parameter	LGMAXBURST = 3
+		// }}}
+		// }}}
+	) (
+		// {{{
+		input	wire	S_AXI_ACLK,
+		input	wire	S_AXI_ARESETN,
+		// Write slave channels from the controlling AXI masters
+		// {{{
+		input	wire	[NM*C_AXI_ID_WIDTH-1:0]		S_AXI_AWID,
+		input	wire	[NM*C_AXI_ADDR_WIDTH-1:0]	S_AXI_AWADDR,
+		input	wire	[NM*8-1:0]			S_AXI_AWLEN,
+		input	wire	[NM*3-1:0]			S_AXI_AWSIZE,
+		input	wire	[NM*2-1:0]			S_AXI_AWBURST,
+		input	wire	[NM-1:0]			S_AXI_AWLOCK,
+		input	wire	[NM*4-1:0]			S_AXI_AWCACHE,
+		input	wire	[NM*3-1:0]			S_AXI_AWPROT,
+		input	wire	[NM*4-1:0]			S_AXI_AWQOS,
+		input	wire	[NM-1:0]			S_AXI_AWVALID,
+		output	wire	[NM-1:0]			S_AXI_AWREADY,
+		//
+		input	wire	[NM*C_AXI_DATA_WIDTH-1:0]	S_AXI_WDATA,
+		input	wire	[NM*C_AXI_DATA_WIDTH/8-1:0]	S_AXI_WSTRB,
+		input	wire	[NM-1:0]			S_AXI_WLAST,
+		input	wire	[NM-1:0]			S_AXI_WVALID,
+		output	wire	[NM-1:0]			S_AXI_WREADY,
+		//
+		output	wire	[NM*C_AXI_ID_WIDTH-1:0]		S_AXI_BID,
+		output	wire	[NM*2-1:0]			S_AXI_BRESP,
+		output	wire	[NM-1:0]			S_AXI_BVALID,
+		input	wire	[NM-1:0]			S_AXI_BREADY,
+		// }}}
+		// Read slave channels from the controlling AXI masters
+		// {{{
+		input	wire	[NM*C_AXI_ID_WIDTH-1:0]		S_AXI_ARID,
+		input	wire	[NM*C_AXI_ADDR_WIDTH-1:0]	S_AXI_ARADDR,
+		input	wire	[NM*8-1:0]			S_AXI_ARLEN,
+		input	wire	[NM*3-1:0]			S_AXI_ARSIZE,
+		input	wire	[NM*2-1:0]			S_AXI_ARBURST,
+		input	wire	[NM-1:0]			S_AXI_ARLOCK,
+		input	wire	[NM*4-1:0]			S_AXI_ARCACHE,
+		input	wire	[NM*3-1:0]			S_AXI_ARPROT,
+		input	wire	[NM*4-1:0]			S_AXI_ARQOS,
+		input	wire	[NM-1:0]			S_AXI_ARVALID,
+		output	wire	[NM-1:0]			S_AXI_ARREADY,
+		//
+		output	wire	[NM*C_AXI_ID_WIDTH-1:0]		S_AXI_RID,
+		output	wire	[NM*C_AXI_DATA_WIDTH-1:0]	S_AXI_RDATA,
+		output	wire	[NM*2-1:0]			S_AXI_RRESP,
+		output	wire	[NM-1:0]			S_AXI_RLAST,
+		output	wire	[NM-1:0]			S_AXI_RVALID,
+		input	wire	[NM-1:0]			S_AXI_RREADY,
+		// }}}
+		// Write channel master outputs to the connected AXI slaves
+		// {{{
+		output	wire	[NS*C_AXI_ID_WIDTH-1:0]		M_AXI_AWID,
+		output	wire	[NS*C_AXI_ADDR_WIDTH-1:0]	M_AXI_AWADDR,
+		output	wire	[NS*8-1:0]			M_AXI_AWLEN,
+		output	wire	[NS*3-1:0]			M_AXI_AWSIZE,
+		output	wire	[NS*2-1:0]			M_AXI_AWBURST,
+		output	wire	[NS-1:0]			M_AXI_AWLOCK,
+		output	wire	[NS*4-1:0]			M_AXI_AWCACHE,
+		output	wire	[NS*3-1:0]			M_AXI_AWPROT,
+		output	wire	[NS*4-1:0]			M_AXI_AWQOS,
+		output	wire	[NS-1:0]			M_AXI_AWVALID,
+		input	wire	[NS-1:0]			M_AXI_AWREADY,
+		//
+		//
+		output	wire	[NS*C_AXI_DATA_WIDTH-1:0]	M_AXI_WDATA,
+		output	wire	[NS*C_AXI_DATA_WIDTH/8-1:0]	M_AXI_WSTRB,
+		output	wire	[NS-1:0]			M_AXI_WLAST,
+		output	wire	[NS-1:0]			M_AXI_WVALID,
+		input	wire	[NS-1:0]			M_AXI_WREADY,
+		//
+		input	wire	[NS*C_AXI_ID_WIDTH-1:0]		M_AXI_BID,
+		input	wire	[NS*2-1:0]			M_AXI_BRESP,
+		input	wire	[NS-1:0]			M_AXI_BVALID,
+		output	wire	[NS-1:0]			M_AXI_BREADY,
+		// }}}
+		// Read channel master outputs to the connected AXI slaves
+		// {{{
+		output	wire	[NS*C_AXI_ID_WIDTH-1:0]		M_AXI_ARID,
+		output	wire	[NS*C_AXI_ADDR_WIDTH-1:0]	M_AXI_ARADDR,
+		output	wire	[NS*8-1:0]			M_AXI_ARLEN,
+		output	wire	[NS*3-1:0]			M_AXI_ARSIZE,
+		output	wire	[NS*2-1:0]			M_AXI_ARBURST,
+		output	wire	[NS-1:0]			M_AXI_ARLOCK,
+		output	wire	[NS*4-1:0]			M_AXI_ARCACHE,
+		output	wire	[NS*4-1:0]			M_AXI_ARQOS,
+		output	wire	[NS*3-1:0]			M_AXI_ARPROT,
+		output	wire	[NS-1:0]			M_AXI_ARVALID,
+		input	wire	[NS-1:0]			M_AXI_ARREADY,
+		//
+		//
+		input	wire	[NS*C_AXI_ID_WIDTH-1:0]		M_AXI_RID,
+		input	wire	[NS*C_AXI_DATA_WIDTH-1:0]	M_AXI_RDATA,
+		input	wire	[NS*2-1:0]			M_AXI_RRESP,
+		input	wire	[NS-1:0]			M_AXI_RLAST,
+		input	wire	[NS-1:0]			M_AXI_RVALID,
+		output	wire	[NS-1:0]			M_AXI_RREADY
+		// }}}
+		// }}}
+	);
+	//
+	// Local parameters, derived from those above
+	// {{{
+	localparam	LGLINGER = (OPT_LINGER>1) ? $clog2(OPT_LINGER+1) : 1;
+	//
+	localparam	LGNM = (NM>1) ? $clog2(NM) : 1;
+	localparam	LGNS = (NS>1) ? $clog2(NS+1) : 1;
+	//
+	// In order to use indexes, and hence fully balanced mux trees, it helps
+	// to make certain that we have a power of two based lookup.  NMFULL
+	// is the number of masters in this lookup, with potentially some
+	// unused extra ones.  NSFULL is defined similarly.
+	localparam	NMFULL = (NM>1) ? (1<<LGNM) : 1;
+	localparam	NSFULL = (NS>1) ? (1<<LGNS) : 2;
+	//
+	localparam [1:0] INTERCONNECT_ERROR = 2'b11;
+	//
+	// OPT_SKID_INPUT controls whether the input skid buffers register
+	// their outputs or not.  If set, all skid buffers will cost one more
+	// clock of latency.  It's not clear that there's a performance gain
+	// to be had by setting this.
+	localparam [0:0]	OPT_SKID_INPUT = 0;
+	//
+	// OPT_BUFFER_DECODER determines whether or not the outputs of the
+	// address decoder will be buffered or not.  If buffered, there will
+	// be an extra (registered) clock delay on each of the A* channels from
+	// VALID to issue.
+	localparam [0:0]	OPT_BUFFER_DECODER = 1;
+	//
+	// OPT_AWW controls whether or not a W* beat may be issued to a slave
+	// at the same time as the first AW* beat gets sent to the slave.  Set
+	// to 1'b1 for lower latency, at the potential cost of a greater
+	// combinatorial path length
+	localparam	OPT_AWW = 1'b1;
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Internal signal declarations and definitions
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	genvar	N,M;
+	integer	iN, iM;
+
+	reg	[NSFULL-1:0]	wrequest		[0:NM-1];
+	reg	[NSFULL-1:0]	rrequest		[0:NM-1];
+	reg	[NSFULL-1:0]	wrequested		[0:NM];
+	reg	[NSFULL-1:0]	rrequested		[0:NM];
+	reg	[NS:0]		wgrant			[0:NM-1];
+	reg	[NS:0]		rgrant			[0:NM-1];
+	reg	[NM-1:0]	mwgrant;
+	reg	[NM-1:0]	mrgrant;
+	reg	[NS-1:0]	swgrant;
+	reg	[NS-1:0]	srgrant;
+
+	// verilator lint_off UNUSED
+	wire	[LGMAXBURST-1:0]	w_mawpending	[0:NM-1];
+	wire	[LGMAXBURST-1:0]	wlasts_pending	[0:NM-1];
+	wire	[LGMAXBURST-1:0]	w_mrpending	[0:NM-1];
+	// verilator lint_on  UNUSED
+	reg	[NM-1:0]		mwfull;
+	reg	[NM-1:0]		mrfull;
+	reg	[NM-1:0]		mwempty;
+	reg	[NM-1:0]		mrempty;
+	//
+	reg	[LGNS-1:0]		mwindex	[0:NMFULL-1];
+	reg	[LGNS-1:0]		mrindex	[0:NMFULL-1];
+	reg	[LGNM-1:0]		swindex	[0:NSFULL-1];
+	reg	[LGNM-1:0]		srindex	[0:NSFULL-1];
+
+	(* keep *) reg	[NM-1:0]		wdata_expected;
+
+	// The shadow buffers
+	reg	[NMFULL-1:0]	m_awvalid, m_arvalid;
+	wire	[NMFULL-1:0]	m_wvalid;
+	wire	[NM-1:0]	dcd_awvalid, dcd_arvalid;
+
+	wire	[C_AXI_ID_WIDTH-1:0]		m_awid		[0:NMFULL-1];
+	wire	[C_AXI_ADDR_WIDTH-1:0]		m_awaddr	[0:NMFULL-1];
+	wire	[7:0]				m_awlen		[0:NMFULL-1];
+	wire	[2:0]				m_awsize	[0:NMFULL-1];
+	wire	[1:0]				m_awburst	[0:NMFULL-1];
+	wire	[NMFULL-1:0]			m_awlock;
+	wire	[3:0]				m_awcache	[0:NMFULL-1];
+	wire	[2:0]				m_awprot	[0:NMFULL-1];
+	wire	[3:0]				m_awqos		[0:NMFULL-1];
+	//
+	wire	[C_AXI_DATA_WIDTH-1:0]		m_wdata		[0:NMFULL-1];
+	wire	[C_AXI_DATA_WIDTH/8-1:0]	m_wstrb		[0:NMFULL-1];
+	wire	[NMFULL-1:0]			m_wlast;
+
+	wire	[C_AXI_ID_WIDTH-1:0]		m_arid		[0:NMFULL-1];
+	wire	[C_AXI_ADDR_WIDTH-1:0]		m_araddr	[0:NMFULL-1];
+	wire	[8-1:0]				m_arlen		[0:NMFULL-1];
+	wire	[3-1:0]				m_arsize	[0:NMFULL-1];
+	wire	[2-1:0]				m_arburst	[0:NMFULL-1];
+	wire	[NMFULL-1:0]			m_arlock;
+	wire	[4-1:0]				m_arcache	[0:NMFULL-1];
+	wire	[2:0]				m_arprot	[0:NMFULL-1];
+	wire	[3:0]				m_arqos		[0:NMFULL-1];
+	//
+	//
+	reg	[NM-1:0]			berr_valid;
+	reg	[IW-1:0]			berr_id		[0:NM-1];
+	//
+	reg	[NM-1:0]			rerr_none;
+	reg	[NM-1:0]			rerr_last;
+	reg	[8:0]				rerr_outstanding [0:NM-1];
+	reg	[IW-1:0]			rerr_id		 [0:NM-1];
+
+	wire	[NM-1:0]	skd_awvalid, skd_awstall;
+	wire	[NM-1:0]	skd_arvalid, skd_arstall;
+	wire	[IW-1:0]	skd_awid			[0:NM-1];
+	wire	[AW-1:0]	skd_awaddr			[0:NM-1];
+	wire	[8-1:0]		skd_awlen			[0:NM-1];
+	wire	[3-1:0]		skd_awsize			[0:NM-1];
+	wire	[2-1:0]		skd_awburst			[0:NM-1];
+	wire	[NM-1:0]	skd_awlock;
+	wire	[4-1:0]		skd_awcache			[0:NM-1];
+	wire	[3-1:0]		skd_awprot			[0:NM-1];
+	wire	[4-1:0]		skd_awqos			[0:NM-1];
+	//
+	wire	[IW-1:0]	skd_arid			[0:NM-1];
+	wire	[AW-1:0]	skd_araddr			[0:NM-1];
+	wire	[8-1:0]		skd_arlen			[0:NM-1];
+	wire	[3-1:0]		skd_arsize			[0:NM-1];
+	wire	[2-1:0]		skd_arburst			[0:NM-1];
+	wire	[NM-1:0]	skd_arlock;
+	wire	[4-1:0]		skd_arcache			[0:NM-1];
+	wire	[3-1:0]		skd_arprot			[0:NM-1];
+	wire	[4-1:0]		skd_arqos			[0:NM-1];
+
+	// Verilator lint_off UNUSED
+	reg	[NSFULL-1:0]	m_axi_awvalid;
+	reg	[NSFULL-1:0]	m_axi_awready;
+	reg	[IW-1:0]	m_axi_awid	[0:NSFULL-1];
+	reg	[7:0]		m_axi_awlen	[0:NSFULL-1];
+
+	reg	[NSFULL-1:0]	m_axi_wvalid;
+	reg	[NSFULL-1:0]	m_axi_wready;
+	reg	[NSFULL-1:0]	m_axi_bvalid;
+	reg	[NSFULL-1:0]	m_axi_bready;
+	// Verilator lint_on  UNUSED
+	reg	[1:0]		m_axi_bresp	[0:NSFULL-1];
+	reg	[IW-1:0]	m_axi_bid	[0:NSFULL-1];
+
+	// Verilator lint_off UNUSED
+	reg	[NSFULL-1:0]	m_axi_arvalid;
+	reg	[7:0]		m_axi_arlen	[0:NSFULL-1];
+	reg	[IW-1:0]	m_axi_arid	[0:NSFULL-1];
+	reg	[NSFULL-1:0]	m_axi_arready;
+	// Verilator lint_on  UNUSED
+	reg	[NSFULL-1:0]	m_axi_rvalid;
+	// Verilator lint_off UNUSED
+	reg	[NSFULL-1:0]	m_axi_rready;
+	// Verilator lint_on  UNUSED
+	//
+	reg	[IW-1:0]	m_axi_rid	[0:NSFULL-1];
+	reg	[DW-1:0]	m_axi_rdata	[0:NSFULL-1];
+	reg	[NSFULL-1:0]	m_axi_rlast;
+	reg	[2-1:0]		m_axi_rresp	[0:NSFULL-1];
+
+	reg	[NM-1:0]	slave_awaccepts;
+	reg	[NM-1:0]	slave_waccepts;
+	reg	[NM-1:0]	slave_raccepts;
+
+	reg	[NM-1:0]	bskd_valid;
+	reg	[NM-1:0]	rskd_valid, rskd_rlast;
+	wire	[NM-1:0]	bskd_ready;
+	wire	[NM-1:0]	rskd_ready;
+
+	reg	[NMFULL-1:0]	write_qos_lockout,
+				read_qos_lockout;
+
+	reg	[NSFULL-1:0]	slave_awready, slave_wready, slave_arready;
+	// }}}
+
+	// m_axi_* convenience signals (write side)
+	// {{{
+	always @(*)
+	begin
+		m_axi_awvalid = -1;
+		m_axi_awready = -1;
+		m_axi_wvalid = -1;
+		m_axi_wready = -1;
+		m_axi_bvalid = 0;
+		m_axi_bready = -1;
+
+		m_axi_awvalid[NS-1:0] = M_AXI_AWVALID;
+		m_axi_awready[NS-1:0] = M_AXI_AWREADY;
+		m_axi_wvalid[NS-1:0]  = M_AXI_WVALID;
+		m_axi_wready[NS-1:0]  = M_AXI_WREADY;
+		m_axi_bvalid[NS-1:0]  = M_AXI_BVALID;
+		m_axi_bready[NS-1:0]  = M_AXI_BREADY;
+
+		for(iM=0; iM<NS; iM=iM+1)
+		begin
+			m_axi_awid[iM]   = M_AXI_AWID[   iM*IW +: IW];
+			m_axi_awlen[iM]  = M_AXI_AWLEN[  iM* 8 +:  8];
+
+			m_axi_bid[iM]   = M_AXI_BID[iM* IW +:  IW];
+			m_axi_bresp[iM] = M_AXI_BRESP[iM* 2 +:  2];
+
+			m_axi_rid[iM]   = M_AXI_RID[  iM*IW +: IW];
+			m_axi_rdata[iM] = M_AXI_RDATA[iM*DW +: DW];
+			m_axi_rresp[iM] = M_AXI_RRESP[iM* 2 +:  2];
+			m_axi_rlast[iM] = M_AXI_RLAST[iM];
+		end
+		for(iM=NS; iM<NSFULL; iM=iM+1)
+		begin
+			m_axi_awid[iM]   = 0;
+			m_axi_awlen[iM]  = 0;
+
+			m_axi_bresp[iM] = INTERCONNECT_ERROR;
+			m_axi_bid[iM]   = 0;
+
+			m_axi_rid[iM]   = 0;
+			m_axi_rdata[iM] = 0;
+			m_axi_rresp[iM] = INTERCONNECT_ERROR;
+			m_axi_rlast[iM] = 1;
+		end
+	end
+	// }}}
+
+	// m_axi_* convenience signals (read side)
+	// {{{
+	always @(*)
+	begin
+		m_axi_arvalid = 0;
+		m_axi_arready = 0;
+		m_axi_rvalid = 0;
+		m_axi_rready = 0;
+		for(iM=0; iM<NS; iM=iM+1)
+		begin
+			m_axi_arlen[iM] = M_AXI_ARLEN[iM* 8 +:  8];
+			m_axi_arid[iM]  = M_AXI_ARID[ iM*IW +: IW];
+		end
+		for(iM=NS; iM<NSFULL; iM=iM+1)
+		begin
+			m_axi_arlen[iM] = 0;
+			m_axi_arid[iM]  = 0;
+		end
+
+		m_axi_arvalid[NS-1:0] = M_AXI_ARVALID;
+		m_axi_arready[NS-1:0] = M_AXI_ARREADY;
+		m_axi_rvalid[NS-1:0]  = M_AXI_RVALID;
+		m_axi_rready[NS-1:0]  = M_AXI_RREADY;
+	end
+	// }}}
+
+	// slave_*ready convenience signals
+	// {{{
+	always @(*)
+	begin
+		// These are designed to keep us from doing things like
+		// m_axi_*[m?index[N]] && m_axi_*[m?index[N]] && .. etc
+		//
+		// First, we'll set bits for all slaves--to include those that
+		// are undefined (but required by our static analysis tools).
+		slave_awready = -1;
+		slave_wready  = -1;
+		slave_arready = -1;
+		//
+		// Here we do all of the combinatoric calculations, so the
+		// master only needs to reference one bit of this signal
+		slave_awready[NS-1:0] = (~M_AXI_AWVALID | M_AXI_AWREADY);
+		slave_wready[NS-1:0]  = (~M_AXI_WVALID | M_AXI_WREADY);
+		slave_arready[NS-1:0] = (~M_AXI_ARVALID | M_AXI_ARREADY);
+	end
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Process our incoming signals: AW*, W*, and AR*
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	generate for(N=0; N<NM; N=N+1)
+	begin : W1_DECODE_WRITE_REQUEST
+	// {{{
+		wire	[NS:0]	wdecode;
+
+		// awskid, the skidbuffer for the incoming AW* channel
+		// {{{
+		skidbuffer #(.DW(IW+AW+8+3+2+1+4+3+4),
+					.OPT_OUTREG(OPT_SKID_INPUT))
+		awskid(S_AXI_ACLK, !S_AXI_ARESETN,
+			S_AXI_AWVALID[N], S_AXI_AWREADY[N],
+			{ S_AXI_AWID[N*IW +: IW], S_AXI_AWADDR[N*AW +: AW],
+			  S_AXI_AWLEN[N*8 +: 8], S_AXI_AWSIZE[N*3 +: 3],
+			  S_AXI_AWBURST[N*2 +: 2], S_AXI_AWLOCK[N],
+			  S_AXI_AWCACHE[N*4 +: 4], S_AXI_AWPROT[N*3 +: 3],
+			  S_AXI_AWQOS[N*4 +: 4] },
+			skd_awvalid[N], !skd_awstall[N],
+			{ skd_awid[N], skd_awaddr[N], skd_awlen[N],
+			  skd_awsize[N], skd_awburst[N], skd_awlock[N],
+			  skd_awcache[N], skd_awprot[N], skd_awqos[N] });
+		// }}}
+
+		// wraddr, decode the write channel's address request to a
+		// particular slave index
+		// {{{
+		addrdecode #(.AW(AW), .DW(IW+8+3+2+1+4+3+4), .NS(NS),
+			.SLAVE_ADDR(SLAVE_ADDR),
+			.SLAVE_MASK(SLAVE_MASK),
+			.OPT_REGISTERED(OPT_BUFFER_DECODER))
+		wraddr(.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+			.i_valid(skd_awvalid[N]), .o_stall(skd_awstall[N]),
+				.i_addr(skd_awaddr[N]), .i_data({ skd_awid[N],
+				skd_awlen[N], skd_awsize[N], skd_awburst[N],
+				skd_awlock[N], skd_awcache[N], skd_awprot[N],
+				skd_awqos[N] }),
+			.o_valid(dcd_awvalid[N]),
+				.i_stall(!dcd_awvalid[N]||!slave_awaccepts[N]),
+				.o_decode(wdecode), .o_addr(m_awaddr[N]),
+				.o_data({ m_awid[N], m_awlen[N], m_awsize[N],
+				  m_awburst[N], m_awlock[N], m_awcache[N],
+				  m_awprot[N], m_awqos[N]}));
+		// }}}
+
+		// wskid, the skid buffer for the incoming W* channel
+		// {{{
+		skidbuffer #(.DW(DW+DW/8+1),
+			.OPT_OUTREG(OPT_SKID_INPUT || OPT_BUFFER_DECODER))
+		wskid(S_AXI_ACLK, !S_AXI_ARESETN,
+			S_AXI_WVALID[N], S_AXI_WREADY[N],
+			{ S_AXI_WDATA[N*DW +: DW], S_AXI_WSTRB[N*DW/8 +: DW/8],
+			  S_AXI_WLAST[N] },
+			m_wvalid[N], slave_waccepts[N],
+			{ m_wdata[N], m_wstrb[N], m_wlast[N] });
+		// }}}
+
+		// slave_awaccepts
+		// {{{
+		always @(*)
+		begin
+			slave_awaccepts[N] = 1'b1;
+
+			// Cannot accept/forward a packet without a bus grant
+			// This handles whether or not write data is still
+			// pending.
+			if (!mwgrant[N])
+				slave_awaccepts[N] = 1'b0;
+			if (write_qos_lockout[N])
+				slave_awaccepts[N] = 1'b0;
+			if (mwfull[N])
+				slave_awaccepts[N] = 1'b0;
+			// Don't accept a packet unless its to the same slave
+			// the grant is issued for
+			if (!wrequest[N][mwindex[N]])
+				slave_awaccepts[N] = 1'b0;
+			if (!wgrant[N][NS])
+			begin
+				if (!slave_awready[mwindex[N]])
+					slave_awaccepts[N] = 1'b0;
+			end else if (!berr_valid[N] || !bskd_ready[N])
+			begin
+				// Can't accept an write address channel request
+				// for the no-address-mapped channel if the
+				// B* channel is stalled, lest we lose the ID
+				// of the transaction
+				//
+				// !berr_valid[N] => we have to accept more
+				//	write data before we can issue BVALID
+				slave_awaccepts[N] = 1'b0;
+			end
+		end
+		// }}}
+
+		// slave_waccepts
+		// {{{
+		always @(*)
+		begin
+			slave_waccepts[N] = 1'b1;
+			if (!mwgrant[N])
+				slave_waccepts[N] = 1'b0;
+			if (!wdata_expected[N] && (!OPT_AWW || !slave_awaccepts[N]))
+				slave_waccepts[N] = 1'b0;
+			if (!wgrant[N][NS])
+			begin
+				if (!slave_wready[mwindex[N]])
+					slave_waccepts[N] = 1'b0;
+			end else if (berr_valid[N] && !bskd_ready[N])
+				slave_waccepts[N] = 1'b0;
+		end
+		// }}}
+
+		always @(*)
+		begin
+			m_awvalid[N]= dcd_awvalid[N] && !mwfull[N];
+			wrequest[N]= 0;
+			if (!mwfull[N])
+				wrequest[N][NS:0] = wdecode;
+		end
+
+		// QOS handling via write_qos_lockout
+		// {{{
+		if (!OPT_QOS || NM == 1)
+		begin : WRITE_NO_QOS
+
+			// If we aren't using QOS, then never lock any packets
+			// out from arbitration
+			always @(*)
+				write_qos_lockout[N] = 0;
+
+		end else begin : WRITE_QOS
+
+			// Lock out a master based upon a second master having
+			// a higher QOS request level
+			// {{{
+			initial	write_qos_lockout[N] = 0;
+			always @(posedge  S_AXI_ACLK)
+			if (!S_AXI_ARESETN)
+				write_qos_lockout[N] <= 0;
+			else begin
+				write_qos_lockout[N] <= 0;
+
+				for(iN=0; iN<NM; iN=iN+1)
+				if (iN != N)
+				begin
+					if (m_awvalid[N]
+						&&(|(wrequest[iN][NS-1:0]
+							& wdecode[NS-1:0]))
+						&&(m_awqos[N] < m_awqos[iN]))
+						write_qos_lockout[N] <= 1;
+				end
+			end
+			// }}}
+		end
+		// }}}
+
+	end for (N=NM; N<NMFULL; N=N+1)
+	begin : UNUSED_WSKID_BUFFERS
+	// {{{
+		// The following values are unused.  They need to be defined
+		// so that our indexing scheme will work, but indexes should
+		// never actually reference them
+		assign	m_awid[N]    = 0;
+		assign	m_awaddr[N]  = 0;
+		assign	m_awlen[N]   = 0;
+		assign	m_awsize[N]  = 0;
+		assign	m_awburst[N] = 0;
+		assign	m_awlock[N]  = 0;
+		assign	m_awcache[N] = 0;
+		assign	m_awprot[N]  = 0;
+		assign	m_awqos[N]   = 0;
+
+		always @(*)
+			m_awvalid[N] = 0;
+
+		assign	m_wvalid[N]  = 0;
+		//
+		assign	m_wdata[N] = 0;
+		assign	m_wstrb[N] = 0;
+		assign	m_wlast[N] = 0;
+
+		always @(*)
+			write_qos_lockout[N] = 0;
+	// }}}
+	// }}}
+	end endgenerate
+
+	// Read skid buffers and address decoding, slave_araccepts logic
+	generate for(N=0; N<NM; N=N+1)
+	begin : R1_DECODE_READ_REQUEST
+	// {{{
+		wire	[NS:0]	rdecode;
+
+		// arskid
+		// {{{
+		skidbuffer #(.DW(IW+AW+8+3+2+1+4+3+4),
+					.OPT_OUTREG(OPT_SKID_INPUT))
+		arskid(S_AXI_ACLK, !S_AXI_ARESETN,
+			S_AXI_ARVALID[N], S_AXI_ARREADY[N],
+			{ S_AXI_ARID[N*IW +: IW], S_AXI_ARADDR[N*AW +: AW],
+			  S_AXI_ARLEN[N*8 +: 8], S_AXI_ARSIZE[N*3 +: 3],
+			  S_AXI_ARBURST[N*2 +: 2], S_AXI_ARLOCK[N],
+			  S_AXI_ARCACHE[N*4 +: 4], S_AXI_ARPROT[N*3 +: 3],
+			  S_AXI_ARQOS[N*4 +: 4] },
+			skd_arvalid[N], !skd_arstall[N],
+			{ skd_arid[N], skd_araddr[N], skd_arlen[N],
+			  skd_arsize[N], skd_arburst[N], skd_arlock[N],
+			  skd_arcache[N], skd_arprot[N], skd_arqos[N] });
+		// }}}
+
+		// Read address decoder
+		// {{{
+		addrdecode #(.AW(AW), .DW(IW+8+3+2+1+4+3+4), .NS(NS),
+			.SLAVE_ADDR(SLAVE_ADDR),
+			.SLAVE_MASK(SLAVE_MASK),
+			.OPT_REGISTERED(OPT_BUFFER_DECODER))
+		rdaddr(.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+			.i_valid(skd_arvalid[N]), .o_stall(skd_arstall[N]),
+				.i_addr(skd_araddr[N]), .i_data({ skd_arid[N],
+				skd_arlen[N], skd_arsize[N], skd_arburst[N],
+				skd_arlock[N], skd_arcache[N], skd_arprot[N],
+				skd_arqos[N] }),
+			.o_valid(dcd_arvalid[N]),
+				.i_stall(!m_arvalid[N] || !slave_raccepts[N]),
+				.o_decode(rdecode), .o_addr(m_araddr[N]),
+				.o_data({ m_arid[N], m_arlen[N], m_arsize[N],
+				  m_arburst[N], m_arlock[N], m_arcache[N],
+				  m_arprot[N], m_arqos[N]}));
+		// }}}
+
+		always @(*)
+		begin
+			m_arvalid[N] = dcd_arvalid[N] && !mrfull[N];
+			rrequest[N] = 0;
+			if (!mrfull[N])
+				rrequest[N][NS:0] = rdecode;
+		end
+
+		// slave_raccepts decoding
+		// {{{
+		always @(*)
+		begin
+			slave_raccepts[N] = 1'b1;
+			if (!mrgrant[N])
+				slave_raccepts[N] = 1'b0;
+			if (read_qos_lockout[N])
+				slave_raccepts[N] = 1'b0;
+			if (mrfull[N])
+				slave_raccepts[N] = 1'b0;
+			// If we aren't requesting access to the channel we've
+			// been granted access to, then we can't accept this
+			// verilator lint_off  WIDTH
+			if (!rrequest[N][mrindex[N]])
+				slave_raccepts[N] = 1'b0;
+			// verilator lint_on  WIDTH
+			if (!rgrant[N][NS])
+			begin
+				if (!slave_arready[mrindex[N]])
+					slave_raccepts[N] = 1'b0;
+			end else if (!mrempty[N] || !rerr_none[N] || rskd_valid[N])
+				slave_raccepts[N] = 1'b0;
+		end
+		// }}}
+
+		// Read QOS logic
+		// {{{
+		// read_qos_lockout will get set if a master with a higher
+		// QOS number is requesting a given slave.  It will not
+		// affect existing outstanding packets, but will be used to
+		// prevent further packets from being sent to a given slave.
+		if (!OPT_QOS || NM == 1)
+		begin : READ_NO_QOS
+
+			// If we aren't implementing QOS, then the lockout
+			// signal is never set
+			always @(*)
+				read_qos_lockout[N] = 0;
+
+		end else begin : READ_QOS
+
+			// We set lockout if another master (with a higher
+			// QOS) is requesting this slave *and* the slave
+			// channel is currently stalled.
+			initial	read_qos_lockout[N] = 0;
+			always @(posedge  S_AXI_ACLK)
+			if (!S_AXI_ARESETN)
+				read_qos_lockout[N] <= 0;
+			else begin
+				read_qos_lockout[N] <= 0;
+
+				for(iN=0; iN<NM; iN=iN+1)
+				if (iN != N)
+				begin
+					if (m_arvalid[iN]
+						&& !slave_raccepts[N]
+						&&(|(rrequest[iN][NS-1:0]
+							& rdecode[NS-1:0]))
+						&&(m_arqos[N] < m_arqos[iN]))
+						read_qos_lockout[N] <= 1;
+				end
+			end
+		end
+		// }}}
+
+	end for (N=NM; N<NMFULL; N=N+1)
+	begin : UNUSED_RSKID_BUFFERS
+	// {{{
+		always @(*)
+			m_arvalid[N] = 0;
+		assign	m_arid[N]    = 0;
+		assign	m_araddr[N]  = 0;
+		assign	m_arlen[N]   = 0;
+		assign	m_arsize[N]  = 0;
+		assign	m_arburst[N] = 0;
+		assign	m_arlock[N]  = 0;
+		assign	m_arcache[N] = 0;
+		assign	m_arprot[N]  = 0;
+		assign	m_arqos[N]   = 0;
+
+		always @(*)
+			read_qos_lockout[N] = 0;
+	// }}}
+	// }}}
+	end endgenerate
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Channel arbitration
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// wrequested
+	// {{{
+	always @(*)
+	begin : W2_DECONFLICT_WRITE_REQUESTS
+
+		for(iN=0; iN<=NM; iN=iN+1)
+			wrequested[iN] = 0;
+
+		// Vivado may complain about too many bits for wrequested.
+		// This is (currrently) expected.  mwindex is used to index
+		// into wrequested, and mwindex has LGNS bits, where LGNS
+		// is $clog2(NS+1) rather than $clog2(NS).  The extra bits
+		// are defined to be zeros, but the point is they are defined.
+		// Therefore, no matter what mwindex is, it will always
+		// reference something valid.
+		wrequested[NM] = 0;
+
+		for(iM=0; iM<NS; iM=iM+1)
+		begin
+			wrequested[0][iM] = 1'b0;
+			for(iN=1; iN<NM ; iN=iN+1)
+			begin
+				// Continue to request any channel with
+				// a grant and pending operations
+				if (wrequest[iN-1][iM] && wgrant[iN-1][iM])
+					wrequested[iN][iM] = 1;
+				if (wrequest[iN-1][iM] && (!mwgrant[iN-1]||mwempty[iN-1]))
+					wrequested[iN][iM] = 1;
+				// Otherwise, if it's already claimed, then
+				// it can't be claimed again
+				if (wrequested[iN-1][iM])
+					wrequested[iN][iM] = 1;
+			end
+			wrequested[NM][iM] = wrequest[NM-1][iM] || wrequested[NM-1][iM];
+		end
+	end
+	// }}}
+
+	// rrequested
+	// {{{
+	always @(*)
+	begin : R2_DECONFLICT_READ_REQUESTS
+
+		for(iN=0; iN<NM ; iN=iN+1)
+			rrequested[iN] = 0;
+
+		// See the note above for wrequested.  This applies to
+		// rrequested as well.
+		rrequested[NM] = 0;
+
+		for(iM=0; iM<NS; iM=iM+1)
+		begin
+			rrequested[0][iM] = 0;
+			for(iN=1; iN<NM ; iN=iN+1)
+			begin
+				// Continue to request any channel with
+				// a grant and pending operations
+				if (rrequest[iN-1][iM] && rgrant[iN-1][iM])
+					rrequested[iN][iM] = 1;
+				if (rrequest[iN-1][iM] && (!mrgrant[iN-1] || mrempty[iN-1]))
+					rrequested[iN][iM] = 1;
+				// Otherwise, if it's already claimed, then
+				// it can't be claimed again
+				if (rrequested[iN-1][iM])
+					rrequested[iN][iM] = 1;
+			end
+			rrequested[NM][iM] = rrequest[NM-1][iM] || rrequested[NM-1][iM];
+		end
+	end
+	// }}}
+
+
+	generate for(N=0; N<NM; N=N+1)
+	begin : W3_ARBITRATE_WRITE_REQUESTS
+	// {{{
+		reg			stay_on_channel;
+		reg			requested_channel_is_available;
+		reg			leave_channel;
+		reg	[LGNS-1:0]	requested_index;
+		reg			linger;
+
+		// The basic logic:
+		// 1. If we must stay_on_channel, then nothing changes
+		// 2. If the requested channel isn't available, then no grant
+		//   is issued
+		// 3. Otherwise, if we need to leave this channel--such as if
+		//   another master is requesting it, then we lose our grant
+
+		// stay_on_channel
+		// {{{
+		// We must stay on the channel if we aren't done working with it
+		// i.e. more writes requested, more acknowledgments expected,
+		// etc.
+		always @(*)
+		begin
+			stay_on_channel = |(wrequest[N][NS:0] & wgrant[N]);
+			if (write_qos_lockout[N])
+				stay_on_channel = 0;
+
+			// We must stay on this channel until we've received
+			// our last acknowledgment signal.  Only then can we
+			// switch grants
+			if (mwgrant[N] && !mwempty[N])
+				stay_on_channel = 1;
+
+			// if berr_valid is true, we have a grant to the
+			// internal slave-error channel.  While this grant
+			// exists, we cannot issue any others.
+			if (berr_valid[N])
+				stay_on_channel = 1;
+		end
+		// }}}
+
+		// requested_channel_is_available
+		// {{{
+		always @(*)
+		begin
+			// The channel is available to us if 1) we want it,
+			// 2) no one else is using it, and 3) no one earlier
+			// has requested it
+			requested_channel_is_available =
+				|(wrequest[N][NS-1:0] & ~swgrant
+						& ~wrequested[N][NS-1:0]);
+
+			// Of course, the error pseudo-channel is *always*
+			// available to us.
+			if (wrequest[N][NS])
+				requested_channel_is_available = 1;
+
+			// Likewise, if we are the only master, then the
+			// channel is always available on any request
+			if (NM < 2)
+				requested_channel_is_available = m_awvalid[N];
+		end
+		// }}}
+
+		// Linger option, and setting the "linger" flag
+		// {{{
+		// If used, linger will hold on to a given channels grant
+		// for some number of clock ticks after the channel has become
+		// idle.  This will spare future requests from the same master
+		// to the same slave from neding to go through the arbitration
+		// clock cycle again--potentially saving a clock period.  If,
+		// however, the master in question requests a different slave
+		// or a different master requests this slave, then the linger
+		// option is voided and the grant given up anyway.
+		if (OPT_LINGER == 0)
+		begin
+			always @(*)
+				linger = 0;
+		end else begin : WRITE_LINGER
+
+			reg [LGLINGER-1:0]	linger_counter;
+
+			initial	linger = 0;
+			initial	linger_counter = 0;
+			always @(posedge S_AXI_ACLK)
+			if (!S_AXI_ARESETN || wgrant[N][NS])
+			begin
+				linger <= 0;
+				linger_counter <= 0;
+			end else if (!mwempty[N] || bskd_valid[N])
+			begin
+				// While the channel is in use, we set the
+				// linger counter
+				linger_counter <= OPT_LINGER;
+				linger <= 1;
+			end else if (linger_counter > 0)
+			begin
+				// Otherwise, we decrement it until it reaches
+				// zero
+				linger <= (linger_counter > 1);
+				linger_counter <= linger_counter - 1;
+			end else
+				linger <= 0;
+
+		end
+		// }}}
+
+		// leave_channel
+		// {{{
+		// True of another master is requesting access to this slave,
+		// or if we are requesting access to another slave.  If QOS
+		// lockout is enabled, then we also leave the channel if a
+		// request with a higher QOS has arrived
+		always @(*)
+		begin
+			leave_channel = 0;
+			if (!m_awvalid[N]
+				&& (!linger || wrequested[NM][mwindex[N]]))
+				// Leave the channel after OPT_LINGER counts
+				// of the channel being idle, or when someone
+				// else asks for the channel
+				leave_channel = 1;
+			if (m_awvalid[N] && !wrequest[N][mwindex[N]])
+				// Need to leave this channel to connect
+				// to any other channel
+				leave_channel = 1;
+			if (write_qos_lockout[N])
+				// Need to leave this channel for another higher
+				// priority request
+				leave_channel = 1;
+		end
+		// }}}
+
+		// WRITE GRANT ALLOCATION
+		// {{{
+		// Now that we've done our homework, we can switch grants
+		// if necessary
+		initial	wgrant[N]  = 0;
+		initial	mwgrant[N] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+		begin
+			wgrant[N]  <= 0;
+			mwgrant[N] <= 0;
+		end else if (!stay_on_channel)
+		begin
+			if (requested_channel_is_available)
+			begin
+				// Switch to a new channel
+				mwgrant[N] <= 1'b1;
+				wgrant[N]  <= wrequest[N][NS:0];
+			end else if (leave_channel)
+			begin
+				// Revoke the given grant
+				mwgrant[N] <= 1'b0;
+				wgrant[N]  <= 0;
+			end
+		end
+		// }}}
+
+		// mwindex (registered)
+		// {{{
+		always @(*)
+		begin
+			requested_index = 0;
+			for(iM=0; iM<=NS; iM=iM+1)
+			if (wrequest[N][iM])
+				requested_index= requested_index | iM[LGNS-1:0];
+		end
+
+		// Now for mwindex
+		initial	mwindex[N] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!stay_on_channel && requested_channel_is_available)
+			mwindex[N] <= requested_index;
+		// }}}
+
+	end for (N=NM; N<NMFULL; N=N+1)
+	begin
+
+		always @(*)
+			mwindex[N] = 0;
+	// }}}
+	end endgenerate
+
+	generate for(N=0; N<NM; N=N+1)
+	begin : R3_ARBITRATE_READ_REQUESTS
+	// {{{
+		reg			stay_on_channel;
+		reg			requested_channel_is_available;
+		reg			leave_channel;
+		reg	[LGNS-1:0]	requested_index;
+		reg			linger;
+
+		// The basic logic:
+		// 1. If we must stay_on_channel, then nothing changes
+		// 2. If the requested channel isn't available, then no grant
+		//   is issued
+		// 3. Otherwise, if we need to leave this channel--such as if
+		//   another master is requesting it, then we lose our grant
+
+		// stay_on_channel
+		// {{{
+		// We must stay on the channel if we aren't done working with it
+		// i.e. more reads requested, more acknowledgments expected,
+		// etc.
+		always @(*)
+		begin
+			stay_on_channel = |(rrequest[N][NS:0] & rgrant[N]);
+			if (read_qos_lockout[N])
+				stay_on_channel = 0;
+
+			// We must stay on this channel until we've received
+			// our last acknowledgment signal.  Only then can we
+			// switch grants
+			if (mrgrant[N] && !mrempty[N])
+				stay_on_channel = 1;
+
+			// if we have a grant to the internal slave-error
+			// channel, then we cannot issue a grant to any other
+			// while this grant is active
+			if (rgrant[N][NS] && (!rerr_none[N] || rskd_valid[N]))
+				stay_on_channel = 1;
+		end
+		// }}}
+
+		// requested_channel_is_available
+		// {{{
+		always @(*)
+		begin
+			// The channel is available to us if 1) we want it,
+			// 2) no one else is using it, and 3) no one earlier
+			// has requested it
+			requested_channel_is_available =
+				|(rrequest[N][NS-1:0] & ~srgrant
+						& ~rrequested[N][NS-1:0]);
+
+			// Of course, the error pseudo-channel is *always*
+			// available to us.
+			if (rrequest[N][NS])
+				requested_channel_is_available = 1;
+
+			// Likewise, if we are the only master, then the
+			// channel is always available on any request
+			if (NM < 2)
+				requested_channel_is_available = m_arvalid[N];
+		end
+		// }}}
+
+		// Linger option, and setting the "linger" flag
+		// {{{
+		// If used, linger will hold on to a given channels grant
+		// for some number of clock ticks after the channel has become
+		// idle.  This will spare future requests from the same master
+		// to the same slave from neding to go through the arbitration
+		// clock cycle again--potentially saving a clock period.  If,
+		// however, the master in question requests a different slave
+		// or a different master requests this slave, then the linger
+		// option is voided and the grant given up anyway.
+		if (OPT_LINGER == 0)
+		begin
+			always @(*)
+				linger = 0;
+		end else begin : READ_LINGER
+
+			reg [LGLINGER-1:0]	linger_counter;
+
+			initial	linger = 0;
+			initial	linger_counter = 0;
+			always @(posedge S_AXI_ACLK)
+			if (!S_AXI_ARESETN || rgrant[N][NS])
+			begin
+				linger <= 0;
+				linger_counter <= 0;
+			end else if (!mrempty[N] || rskd_valid[N])
+			begin
+				linger_counter <= OPT_LINGER;
+				linger <= 1;
+			end else if (linger_counter > 0)
+			begin
+				linger <= (linger_counter > 1);
+				linger_counter <= linger_counter - 1;
+			end else
+				linger <= 0;
+
+		end
+		// }}}
+
+		// leave_channel
+		// {{{
+		// True of another master is requesting access to this slave,
+		// or if we are requesting access to another slave.  If QOS
+		// lockout is enabled, then we also leave the channel if a
+		// request with a higher QOS has arrived
+		always @(*)
+		begin
+			leave_channel = 0;
+			if (!m_arvalid[N]
+				&& (!linger || rrequested[NM][mrindex[N]]))
+				// Leave the channel after OPT_LINGER counts
+				// of the channel being idle, or when someone
+				// else asks for the channel
+				leave_channel = 1;
+			if (m_arvalid[N] && !rrequest[N][mrindex[N]])
+				// Need to leave this channel to connect
+				// to any other channel
+				leave_channel = 1;
+			if (read_qos_lockout[N])
+				leave_channel = 1;
+		end
+		// }}}
+
+
+		// READ GRANT ALLOCATION
+		// {{{
+		initial	rgrant[N]  = 0;
+		initial	mrgrant[N] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+		begin
+			rgrant[N]  <= 0;
+			mrgrant[N] <= 0;
+		end else if (!stay_on_channel)
+		begin
+			if (requested_channel_is_available)
+			begin
+				// Switching channels
+				mrgrant[N] <= 1'b1;
+				rgrant[N] <= rrequest[N][NS:0];
+			end else if (leave_channel)
+			begin
+				mrgrant[N] <= 1'b0;
+				rgrant[N]  <= 0;
+			end
+		end
+		// }}}
+
+		// mrindex (registered)
+		// {{{
+		always @(*)
+		begin
+			requested_index = 0;
+			for(iM=0; iM<=NS; iM=iM+1)
+			if (rrequest[N][iM])
+				requested_index = requested_index|iM[LGNS-1:0];
+		end
+
+		initial	mrindex[N] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!stay_on_channel && requested_channel_is_available)
+			mrindex[N] <= requested_index;
+		// }}}
+
+	end for (N=NM; N<NMFULL; N=N+1)
+	begin
+
+		always @(*)
+			mrindex[N] = 0;
+	// }}}
+	end endgenerate
+
+	// Calculate swindex (registered)
+	generate for (M=0; M<NS; M=M+1)
+	begin : W4_SLAVE_WRITE_INDEX
+	// {{{
+		// swindex is a per slave index, containing the index of the
+		// master that has currently won write arbitration and so
+		// has permission to access this slave
+		if (NM <= 1)
+		begin
+
+			// If there's only ever one master, that index is
+			// always the index of the one master.
+			always @(*)
+				swindex[M] = 0;
+
+		end else begin : MULTIPLE_MASTERS
+
+			reg [LGNM-1:0]	reqwindex;
+
+			// In the case of multiple masters, we follow the logic
+			// of the arbiter to generate the appropriate index
+			// here, and register it on the next clock cycle.  If
+			// no slave has arbitration, the index will remain zero
+			always @(*)
+			begin
+				reqwindex = 0;
+			for(iN=0; iN<NM; iN=iN+1)
+			if ((!mwgrant[iN] || mwempty[iN])
+				&&(wrequest[iN][M] && !wrequested[iN][M]))
+					reqwindex = reqwindex | iN[LGNM-1:0];
+			end
+
+			always @(posedge S_AXI_ACLK)
+			if (!swgrant[M])
+				swindex[M] <= reqwindex;
+		end
+
+	end for (M=NS; M<NSFULL; M=M+1)
+	begin
+
+		always @(*)
+			swindex[M] = 0;
+	// }}}
+	end endgenerate
+
+	// Calculate srindex (registered)
+	generate for (M=0; M<NS; M=M+1)
+	begin : R4_SLAVE_READ_INDEX
+	// {{{
+		// srindex is an index to the master that has currently won
+		// read arbitration to the given slave.
+
+		if (NM <= 1)
+		begin
+			// If there's only one master, srindex can always
+			// point to that master--no longic required
+			always @(*)
+				srindex[M] = 0;
+
+		end else begin : MULTIPLE_MASTERS
+
+			reg [LGNM-1:0]	reqrindex;
+
+			// In the case of multiple masters, we'll follow the
+			// read arbitration logic to generate the index--first
+			// combinatorially, then we'll register it.
+			always @(*)
+			begin
+				reqrindex = 0;
+			for(iN=0; iN<NM; iN=iN+1)
+			if ((!mrgrant[iN] || mrempty[iN])
+				&&(rrequest[iN][M] && !rrequested[iN][M]))
+					reqrindex = reqrindex | iN[LGNM-1:0];
+			end
+
+			always @(posedge S_AXI_ACLK)
+			if (!srgrant[M])
+				srindex[M] <= reqrindex;
+		end
+
+	end for (M=NS; M<NSFULL; M=M+1)
+	begin
+
+		always @(*)
+			srindex[M] = 0;
+	// }}}
+	end endgenerate
+
+	// swgrant and srgrant (combinatorial)
+	generate for(M=0; M<NS; M=M+1)
+	begin : SGRANT
+	// {{{
+
+		// s?grant is a convenience to tell a slave that some master
+		// has won arbitration and so has a grant to that slave.
+
+		// swgrant: write arbitration
+		always @(*)
+		begin
+			swgrant[M] = 0;
+			for(iN=0; iN<NM; iN=iN+1)
+			if (wgrant[iN][M])
+				swgrant[M] = 1;
+		end
+
+		// srgrant: read arbitration
+		always @(*)
+		begin
+			srgrant[M] = 0;
+			for(iN=0; iN<NM; iN=iN+1)
+			if (rgrant[iN][M])
+				srgrant[M] = 1;
+		end
+	// }}}
+	end endgenerate
+
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Generate the signals for the various slaves--the forward channel
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Assign outputs to the various slaves
+	generate for(M=0; M<NS; M=M+1)
+	begin : W5_WRITE_SLAVE_OUTPUTS
+	// {{{
+		reg			axi_awvalid;
+		reg	[IW-1:0]	axi_awid;
+		reg	[AW-1:0]	axi_awaddr;
+		reg	[7:0]		axi_awlen;
+		reg	[2:0]		axi_awsize;
+		reg	[1:0]		axi_awburst;
+		reg			axi_awlock;
+		reg	[3:0]		axi_awcache;
+		reg	[2:0]		axi_awprot;
+		reg	[3:0]		axi_awqos;
+
+		reg			axi_wvalid;
+		reg	[DW-1:0]	axi_wdata;
+		reg	[DW/8-1:0]	axi_wstrb;
+		reg			axi_wlast;
+		//
+		reg			axi_bready;
+
+		reg			sawstall, swstall;
+		reg			awaccepts;
+
+		// Control the slave's AW* channel
+		// {{{
+
+		// Personalize the slave_awaccepts signal
+		always @(*)
+			awaccepts = slave_awaccepts[swindex[M]];
+
+		always @(*)
+			sawstall= (M_AXI_AWVALID[M]&& !M_AXI_AWREADY[M]);
+
+		initial	axi_awvalid = 0;
+		always @(posedge  S_AXI_ACLK)
+		if (!S_AXI_ARESETN || !swgrant[M])
+			axi_awvalid <= 0;
+		else if (!sawstall)
+		begin
+			axi_awvalid <= m_awvalid[swindex[M]] &&(awaccepts);
+		end
+
+		initial	axi_awid    = 0;
+		initial	axi_awaddr  = 0;
+		initial	axi_awlen   = 0;
+		initial	axi_awsize  = 0;
+		initial	axi_awburst = 0;
+		initial	axi_awlock  = 0;
+		initial	axi_awcache = 0;
+		initial	axi_awprot  = 0;
+		initial	axi_awqos   = 0;
+		always @(posedge  S_AXI_ACLK)
+		if (OPT_LOWPOWER && (!S_AXI_ARESETN || !swgrant[M]))
+		begin
+			// Under the OPT_LOWPOWER option, we clear all signals
+			// we aren't using
+			axi_awid    <= 0;
+			axi_awaddr  <= 0;
+			axi_awlen   <= 0;
+			axi_awsize  <= 0;
+			axi_awburst <= 0;
+			axi_awlock  <= 0;
+			axi_awcache <= 0;
+			axi_awprot  <= 0;
+			axi_awqos   <= 0;
+		end else if (!sawstall)
+		begin
+			if (!OPT_LOWPOWER||(m_awvalid[swindex[M]]&&awaccepts))
+			begin
+				// swindex[M] is defined as 0 above in the
+				// case where NM <= 1
+				axi_awid    <= m_awid[   swindex[M]];
+				axi_awaddr  <= m_awaddr[ swindex[M]];
+				axi_awlen   <= m_awlen[  swindex[M]];
+				axi_awsize  <= m_awsize[ swindex[M]];
+				axi_awburst <= m_awburst[swindex[M]];
+				axi_awlock  <= m_awlock[ swindex[M]];
+				axi_awcache <= m_awcache[swindex[M]];
+				axi_awprot  <= m_awprot[ swindex[M]];
+				axi_awqos   <= m_awqos[  swindex[M]];
+			end else begin
+				axi_awid    <= 0;
+				axi_awaddr  <= 0;
+				axi_awlen   <= 0;
+				axi_awsize  <= 0;
+				axi_awburst <= 0;
+				axi_awlock  <= 0;
+				axi_awcache <= 0;
+				axi_awprot  <= 0;
+				axi_awqos   <= 0;
+			end
+		end
+		// }}}
+
+		// Control the slave's W* channel
+		// {{{
+		always @(*)
+			swstall = (M_AXI_WVALID[M] && !M_AXI_WREADY[M]);
+
+		initial	axi_wvalid = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN || !swgrant[M])
+			axi_wvalid <= 0;
+		else if (!swstall)
+		begin
+			axi_wvalid <= (m_wvalid[swindex[M]])
+					&&(slave_waccepts[swindex[M]]);
+		end
+
+		initial axi_wdata  = 0;
+		initial axi_wstrb  = 0;
+		initial axi_wlast  = 0;
+		always @(posedge S_AXI_ACLK)
+		if (OPT_LOWPOWER && !S_AXI_ARESETN)
+		begin
+			axi_wdata  <= 0;
+			axi_wstrb  <= 0;
+			axi_wlast  <= 0;
+		end else if (OPT_LOWPOWER && !swgrant[M])
+		begin
+			axi_wdata  <= 0;
+			axi_wstrb  <= 0;
+			axi_wlast  <= 0;
+		end else if (!swstall)
+		begin
+			if (!OPT_LOWPOWER || (m_wvalid[swindex[M]]&&slave_waccepts[swindex[M]]))
+			begin
+				// If NM <= 1, swindex[M] is already defined
+				// to be zero above
+				axi_wdata  <= m_wdata[swindex[M]];
+				axi_wstrb  <= m_wstrb[swindex[M]];
+				axi_wlast  <= m_wlast[swindex[M]];
+			end else begin
+				axi_wdata  <= 0;
+				axi_wstrb  <= 0;
+				axi_wlast  <= 0;
+			end
+		end
+		// }}}
+
+		//
+		always @(*)
+		if (!swgrant[M])
+			axi_bready = 1;
+		else
+			axi_bready = bskd_ready[swindex[M]];
+
+		// Combinatorial assigns
+		// {{{
+		assign	M_AXI_AWVALID[M]          = axi_awvalid;
+		assign	M_AXI_AWID[   M*IW +: IW] = axi_awid;
+		assign	M_AXI_AWADDR[ M*AW +: AW] = axi_awaddr;
+		assign	M_AXI_AWLEN[  M* 8 +:  8] = axi_awlen;
+		assign	M_AXI_AWSIZE[ M* 3 +:  3] = axi_awsize;
+		assign	M_AXI_AWBURST[M* 2 +:  2] = axi_awburst;
+		assign	M_AXI_AWLOCK[ M]          = axi_awlock;
+		assign	M_AXI_AWCACHE[M* 4 +:  4] = axi_awcache;
+		assign	M_AXI_AWPROT[ M* 3 +:  3] = axi_awprot;
+		assign	M_AXI_AWQOS[  M* 4 +:  4] = axi_awqos;
+		//
+		//
+		assign	M_AXI_WVALID[M]             = axi_wvalid;
+		assign	M_AXI_WDATA[M*DW +: DW]     = axi_wdata;
+		assign	M_AXI_WSTRB[M*DW/8 +: DW/8] = axi_wstrb;
+		assign	M_AXI_WLAST[M]              = axi_wlast;
+		//
+		//
+		assign	M_AXI_BREADY[M]             = axi_bready;
+		// }}}
+		//
+	// }}}
+	end endgenerate
+
+
+	generate for(M=0; M<NS; M=M+1)
+	begin : R5_READ_SLAVE_OUTPUTS
+	// {{{
+		reg				axi_arvalid;
+		reg	[IW-1:0]		axi_arid;
+		reg	[AW-1:0]		axi_araddr;
+		reg	[7:0]			axi_arlen;
+		reg	[2:0]			axi_arsize;
+		reg	[1:0]			axi_arburst;
+		reg				axi_arlock;
+		reg	[3:0]			axi_arcache;
+		reg	[2:0]			axi_arprot;
+		reg	[3:0]			axi_arqos;
+		//
+		reg				axi_rready;
+		reg				arstall;
+
+		always @(*)
+			arstall= axi_arvalid && !M_AXI_ARREADY[M];
+
+		initial	axi_arvalid = 0;
+		always @(posedge  S_AXI_ACLK)
+		if (!S_AXI_ARESETN || !srgrant[M])
+			axi_arvalid <= 0;
+		else if (!arstall)
+			axi_arvalid <= m_arvalid[srindex[M]] && slave_raccepts[srindex[M]];
+		else if (M_AXI_ARREADY[M])
+			axi_arvalid <= 0;
+
+		initial axi_arid    = 0;
+		initial axi_araddr  = 0;
+		initial axi_arlen   = 0;
+		initial axi_arsize  = 0;
+		initial axi_arburst = 0;
+		initial axi_arlock  = 0;
+		initial axi_arcache = 0;
+		initial axi_arprot  = 0;
+		initial axi_arqos   = 0;
+		always @(posedge  S_AXI_ACLK)
+		if (OPT_LOWPOWER && (!S_AXI_ARESETN || !srgrant[M]))
+		begin
+			axi_arid    <= 0;
+			axi_araddr  <= 0;
+			axi_arlen   <= 0;
+			axi_arsize  <= 0;
+			axi_arburst <= 0;
+			axi_arlock  <= 0;
+			axi_arcache <= 0;
+			axi_arprot  <= 0;
+			axi_arqos   <= 0;
+		end else if (!arstall)
+		begin
+			if (!OPT_LOWPOWER || (m_arvalid[srindex[M]] && slave_raccepts[srindex[M]]))
+			begin
+				// If NM <=1, srindex[M] is defined to be zero
+				axi_arid    <= m_arid[   srindex[M]];
+				axi_araddr  <= m_araddr[ srindex[M]];
+				axi_arlen   <= m_arlen[  srindex[M]];
+				axi_arsize  <= m_arsize[ srindex[M]];
+				axi_arburst <= m_arburst[srindex[M]];
+				axi_arlock  <= m_arlock[ srindex[M]];
+				axi_arcache <= m_arcache[srindex[M]];
+				axi_arprot  <= m_arprot[ srindex[M]];
+				axi_arqos   <= m_arqos[  srindex[M]];
+			end else begin
+				axi_arid    <= 0;
+				axi_araddr  <= 0;
+				axi_arlen   <= 0;
+				axi_arsize  <= 0;
+				axi_arburst <= 0;
+				axi_arlock  <= 0;
+				axi_arcache <= 0;
+				axi_arprot  <= 0;
+				axi_arqos   <= 0;
+			end
+		end
+
+		always @(*)
+		if (!srgrant[M])
+			axi_rready = 1;
+		else
+			axi_rready = rskd_ready[srindex[M]];
+
+		//
+		assign	M_AXI_ARVALID[M]          = axi_arvalid;
+		assign	M_AXI_ARID[   M*IW +: IW] = axi_arid;
+		assign	M_AXI_ARADDR[ M*AW +: AW] = axi_araddr;
+		assign	M_AXI_ARLEN[  M* 8 +:  8] = axi_arlen;
+		assign	M_AXI_ARSIZE[ M* 3 +:  3] = axi_arsize;
+		assign	M_AXI_ARBURST[M* 2 +:  2] = axi_arburst;
+		assign	M_AXI_ARLOCK[ M]          = axi_arlock;
+		assign	M_AXI_ARCACHE[M* 4 +:  4] = axi_arcache;
+		assign	M_AXI_ARPROT[ M* 3 +:  3] = axi_arprot;
+		assign	M_AXI_ARQOS[  M* 4 +:  4] = axi_arqos;
+		//
+		assign	M_AXI_RREADY[M]          = axi_rready;
+		//
+	// }}}
+	end endgenerate
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Generate the signals for the various masters--the return channel
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Return values
+	generate for (N=0; N<NM; N=N+1)
+	begin : W6_WRITE_RETURN_CHANNEL
+	// {{{
+		reg	[1:0]	i_axi_bresp;
+		reg	[IW-1:0] i_axi_bid;
+
+		// Write error (no slave selected) state machine
+		// {{{
+		initial	berr_valid[N] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			berr_valid[N] <= 0;
+		else if (wgrant[N][NS] && m_wvalid[N] && m_wlast[N]
+				&& slave_waccepts[N])
+			berr_valid[N] <= 1;
+		else if (bskd_ready[N])
+			berr_valid[N] <= 0;
+
+		always @(*)
+		if (berr_valid[N])
+			bskd_valid[N] = 1;
+		else
+			bskd_valid[N] = mwgrant[N]&&m_axi_bvalid[mwindex[N]];
+
+		always @(posedge S_AXI_ACLK)
+		if (m_awvalid[N] && slave_awaccepts[N])
+			berr_id[N] <= m_awid[N];
+
+		always @(*)
+		if (wgrant[N][NS])
+		begin
+			i_axi_bid   = berr_id[N];
+			i_axi_bresp = INTERCONNECT_ERROR;
+		end else begin
+			i_axi_bid   = m_axi_bid[mwindex[N]];
+			i_axi_bresp = m_axi_bresp[mwindex[N]];
+		end
+		// }}}
+
+		// bskid, the B* channel skidbuffer
+		// {{{
+		skidbuffer #(.DW(IW+2),
+				.OPT_LOWPOWER(OPT_LOWPOWER),
+				.OPT_OUTREG(1))
+		bskid(S_AXI_ACLK, !S_AXI_ARESETN,
+			bskd_valid[N], bskd_ready[N],
+			{ i_axi_bid, i_axi_bresp },
+			S_AXI_BVALID[N], S_AXI_BREADY[N],
+			{ S_AXI_BID[N*IW +: IW], S_AXI_BRESP[N*2 +: 2] });
+		// }}}
+	// }}}
+	end endgenerate
+
+	// Return values
+	generate for (N=0; N<NM; N=N+1)
+	begin : R6_READ_RETURN_CHANNEL
+	// {{{
+
+		reg	[DW-1:0]	i_axi_rdata;
+		reg	[IW-1:0]	i_axi_rid;
+		reg	[2-1:0]		i_axi_rresp;
+
+		// generate the read response
+		// {{{
+		// Here we have two choices.  We can either generate our
+		// response from the slave itself, or from our internally
+		// generated (no-slave exists) FSM.
+		always @(*)
+		if (rgrant[N][NS])
+			rskd_valid[N] = !rerr_none[N];
+		else
+			rskd_valid[N] = mrgrant[N] && m_axi_rvalid[mrindex[N]];
+
+		always @(*)
+		if (rgrant[N][NS])
+		begin
+			i_axi_rid   = rerr_id[N];
+			i_axi_rdata = 0;
+			rskd_rlast[N] = rerr_last[N];
+			i_axi_rresp = INTERCONNECT_ERROR;
+		end else begin
+			i_axi_rid   = m_axi_rid[mrindex[N]];
+			i_axi_rdata = m_axi_rdata[mrindex[N]];
+			rskd_rlast[N]= m_axi_rlast[mrindex[N]];
+			i_axi_rresp = m_axi_rresp[mrindex[N]];
+		end
+		// }}}
+
+		// rskid, the outgoing read skidbuffer
+		// {{{
+		// Since our various read signals are all combinatorially
+		// determined, we'll throw them into an outgoing skid buffer
+		// to register them (per spec) and to make it easier to meet
+		// timing.
+		skidbuffer #(.DW(IW+DW+1+2),
+				.OPT_LOWPOWER(OPT_LOWPOWER),
+				.OPT_OUTREG(1))
+		rskid(S_AXI_ACLK, !S_AXI_ARESETN,
+			rskd_valid[N], rskd_ready[N],
+			{ i_axi_rid, i_axi_rdata, rskd_rlast[N], i_axi_rresp },
+			S_AXI_RVALID[N], S_AXI_RREADY[N],
+			{ S_AXI_RID[N*IW +: IW], S_AXI_RDATA[N*DW +: DW],
+			  S_AXI_RLAST[N], S_AXI_RRESP[N*2 +: 2] });
+		// }}}
+	// }}}
+	end endgenerate
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Count pending transactions
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate for (N=0; N<NM; N=N+1)
+	begin : W7_COUNT_PENDING_WRITES
+	// {{{
+
+		reg	[LGMAXBURST-1:0]	awpending, wpending;
+		reg				r_wdata_expected;
+
+		// awpending, and the associated flags mwempty and mwfull
+		// {{{
+		// awpending is a count of all of the AW* packets that have
+		// been forwarded to the slave, but for which the slave has
+		// yet to return a B* response.  This number can be as large
+		// as (1<<LGMAXBURST)-1.  The two associated flags, mwempty
+		// and mwfull, are there to keep us from checking awempty==0
+		// and &awempty respectively.
+		initial	awpending    = 0;
+		initial	mwempty[N]   = 1;
+		initial	mwfull[N]    = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+		begin
+			awpending     <= 0;
+			mwempty[N]    <= 1;
+			mwfull[N]     <= 0;
+		end else case ({(m_awvalid[N] && slave_awaccepts[N]),
+				(bskd_valid[N] && bskd_ready[N])})
+		2'b01: begin
+			awpending     <= awpending - 1;
+			mwempty[N]    <= (awpending <= 1);
+			mwfull[N]     <= 0;
+			end
+		2'b10: begin
+			awpending <= awpending + 1;
+			mwempty[N] <= 0;
+			mwfull[N]     <= &awpending[LGMAXBURST-1:1];
+			end
+		default: begin end
+		endcase
+
+		// Just so we can access this counter elsewhere, let's make
+		// it available outside of this generate block.  (The formal
+		// section uses this.)
+		assign	w_mawpending[N] = awpending;
+		// }}}
+
+		// r_wdata_expected and wdata_expected
+		// {{{
+		// This section keeps track of whether or not we are expecting
+		// more W* data from the given burst.  It's designed to keep us
+		// from accepting new W* information before the AW* portion
+		// has been routed to the new slave.
+		//
+		// Addition: wpending.  wpending counts the number of write
+		// bursts that are pending, based upon the write channel.
+		// Bursts are counted from AWVALID & AWREADY, and decremented
+		// once we see the WVALID && WREADY signal.  Packets should
+		// not be accepted without a prior (or concurrent)
+		// AWVALID && AWREADY.
+		initial	r_wdata_expected = 0;
+		initial	wpending = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+		begin
+			r_wdata_expected <= 0;
+			wpending <= 0;
+		end else case ({(m_awvalid[N] && slave_awaccepts[N]),
+				(m_wvalid[N]&&slave_waccepts[N] && m_wlast[N])})
+		2'b01: begin
+			r_wdata_expected <= (wpending > 1);
+			wpending <= wpending - 1;
+			end
+		2'b10: begin
+			wpending <= wpending + 1;
+			r_wdata_expected <= 1;
+			end
+		default: begin end
+		endcase
+
+		always @(*)
+			wdata_expected[N] = r_wdata_expected;
+
+		assign wlasts_pending[N] = wpending;
+		// }}}
+	// }}}
+	end endgenerate
+
+	generate for (N=0; N<NM; N=N+1)
+	begin : R7_COUNT_PENDING_READS
+	// {{{
+
+		reg	[LGMAXBURST-1:0]	rpending;
+
+		// rpending, and its associated mrempty and mrfull
+		// {{{
+		// rpending counts the number of read transactions that have
+		// been accepted, but for which rlast has yet to be returned.
+		// This specifically counts grants to valid slaves.  The error
+		// slave is excluded from this count.  mrempty and mrfull have
+		// analogous definitions to mwempty and mwfull, being equal to
+		// rpending == 0 and (&rpending) respectfully.
+		initial	rpending     = 0;
+		initial	mrempty[N]   = 1;
+		initial	mrfull[N]    = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+		begin
+			rpending  <= 0;
+			mrempty[N]<= 1;
+			mrfull[N] <= 0;
+		end else case ({(m_arvalid[N] && slave_raccepts[N] && !rgrant[N][NS]),
+				(rskd_valid[N] && rskd_ready[N]
+					&& rskd_rlast[N] && !rgrant[N][NS])})
+		2'b01: begin
+			rpending      <= rpending - 1;
+			mrempty[N]    <= (rpending == 1);
+			mrfull[N]     <= 0;
+			end
+		2'b10: begin
+			rpending      <= rpending + 1;
+			mrfull[N]     <= &rpending[LGMAXBURST-1:1];
+			mrempty[N]    <= 0;
+			end
+		default: begin end
+		endcase
+
+		assign	w_mrpending[N]  = rpending;
+		// }}}
+
+		// Read error state machine, rerr_outstanding and rerr_id
+		// {{{
+		// rerr_outstanding is the count of read *beats* that remain
+		// to be returned to a master from a non-existent slave.
+		// rerr_last is true on the last of these read beats,
+		// equivalent to rerr_outstanding == 1, and rerr_none is true
+		// when the error state machine is idle
+		initial	rerr_outstanding[N] = 0;
+		initial	rerr_last[N] = 0;
+		initial	rerr_none[N] = 1;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+		begin
+			rerr_outstanding[N] <= 0;
+			rerr_last[N] <= 0;
+			rerr_none[N] <= 1;
+		end else if (!rerr_none[N])
+		begin
+			if (!rskd_valid[N] || rskd_ready[N])
+			begin
+				rerr_none[N] <= (rerr_outstanding[N] == 1);
+				rerr_last[N] <= (rerr_outstanding[N] == 2);
+				rerr_outstanding[N] <= rerr_outstanding[N] - 1;
+			end
+		end else if (m_arvalid[N] && rrequest[N][NS]
+						&& slave_raccepts[N])
+		begin
+			rerr_none[N] <= 0;
+			rerr_last[N] <= (m_arlen[N] == 0);
+			rerr_outstanding[N] <= m_arlen[N] + 1;
+		end
+
+		// rerr_id is the ARID field of the currently outstanding
+		// error.  It's used when generating a read response to a
+		// non-existent slave.
+		initial	rerr_id[N] = 0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN && OPT_LOWPOWER)
+			rerr_id[N] <= 0;
+		else if (m_arvalid[N] && slave_raccepts[N])
+		begin
+			if (rrequest[N][NS] || !OPT_LOWPOWER)
+				// A low-logic definition
+				rerr_id[N] <= m_arid[N];
+			else
+				rerr_id[N] <= 0;
+		end else if (OPT_LOWPOWER && rerr_last[N]
+				&& (!rskd_valid[N] || rskd_ready[N]))
+			rerr_id[N] <= 0;
+		// }}}
+
+`ifdef	FORMAL
+		always @(*)
+			assert(rerr_none[N] ==  (rerr_outstanding[N] == 0));
+		always @(*)
+			assert(rerr_last[N] ==  (rerr_outstanding[N] == 1));
+		always @(*)
+		if (OPT_LOWPOWER && rerr_none[N])
+			assert(rerr_id[N] ==  0);
+`endif
+	// }}}
+	end endgenerate
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// (Partial) Parameter validation
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	initial begin
+		if (NM == 0) begin
+                        $display("At least one master must be defined");
+                        $stop;
+                end
+
+		if (NS == 0) begin
+                        $display("At least one slave must be defined");
+                        $stop;
+                end
+        end
+	// }}}
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal property verification section
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	localparam	F_LGDEPTH = LGMAXBURST+9;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Declare signals used for formal checking
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	//
+	// ...
+	//
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Initial/reset value checking
+	// {{{
+	initial	assert(NS >= 1);
+	initial	assert(NM >= 1);
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Check the arbiter signals for consistency
+	// {{{
+	generate for(N=0; N<NM; N=N+1)
+	begin : F1_CHECK_MASTER_GRANTS
+	// {{{
+		// Write grants
+		always @(*)
+		for(iM=0; iM<=NS; iM=iM+1)
+		begin
+			if (wgrant[N][iM])
+			begin
+				assert((wgrant[N] ^ (1<<iM))==0);
+				assert(mwgrant[N]);
+				assert(mwindex[N] == iM);
+				if (iM < NS)
+				begin
+					assert(swgrant[iM]);
+					assert(swindex[iM] == N);
+				end
+			end
+		end
+
+		always @(*)
+		if (mwgrant[N])
+			assert(wgrant[N] != 0);
+
+		always @(*)
+		if (wrequest[N][NS])
+			assert(wrequest[N][NS-1:0] == 0);
+
+
+		always @(posedge S_AXI_ACLK)
+		if (S_AXI_ARESETN && f_past_valid && bskd_valid[N])
+		begin
+			assert($stable(wgrant[N]));
+			assert($stable(mwindex[N]));
+		end
+
+		////////////////////////////////////////////////////////////////
+		//
+		// Read grant checking
+		//
+		always @(*)
+		for(iM=0; iM<=NS; iM=iM+1)
+		begin
+			if (rgrant[N][iM])
+			begin
+				assert((rgrant[N] ^ (1<<iM))==0);
+				assert(mrgrant[N]);
+				assert(mrindex[N] == iM);
+				if (iM < NS)
+				begin
+					assert(srgrant[iM]);
+					assert(srindex[iM] == N);
+				end
+			end
+		end
+
+		always @(*)
+		if (mrgrant[N])
+			assert(rgrant[N] != 0);
+
+		always @(posedge S_AXI_ACLK)
+		if (S_AXI_ARESETN && f_past_valid && S_AXI_RVALID[N])
+		begin
+			assert($stable(rgrant[N]));
+			assert($stable(mrindex[N]));
+			if (!rgrant[N][NS])
+				assert(!mrempty[N]);
+		end
+	// }}}
+	end endgenerate
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI signaling check, (incoming) master side
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	generate for(N=0; N<NM; N=N+1)
+	begin : F2_CHECK_MASTERS
+	// {{{
+		faxi_slave #(
+			.C_AXI_ID_WIDTH(IW),
+			.C_AXI_DATA_WIDTH(DW),
+			.C_AXI_ADDR_WIDTH(AW),
+			.F_OPT_ASSUME_RESET(1'b1),
+			.F_AXI_MAXSTALL(0),
+			.F_AXI_MAXRSTALL(2),
+			.F_AXI_MAXDELAY(0),
+			.F_OPT_READCHECK(0),
+			.F_OPT_NO_RESET(1),
+			.F_LGDEPTH(F_LGDEPTH))
+		  mstri(.i_clk(S_AXI_ACLK),
+			.i_axi_reset_n(S_AXI_ARESETN),
+			//
+			.i_axi_awid(   S_AXI_AWID[   N*IW +:IW]),
+			.i_axi_awaddr( S_AXI_AWADDR[ N*AW +:AW]),
+			.i_axi_awlen(  S_AXI_AWLEN[  N* 8 +: 8]),
+			.i_axi_awsize( S_AXI_AWSIZE[ N* 3 +: 3]),
+			.i_axi_awburst(S_AXI_AWBURST[N* 2 +: 2]),
+			.i_axi_awlock( S_AXI_AWLOCK[ N]),
+			.i_axi_awcache(S_AXI_AWCACHE[N* 4 +: 4]),
+			.i_axi_awprot( S_AXI_AWPROT[ N* 3 +: 3]),
+			.i_axi_awqos(  S_AXI_AWQOS[  N* 4 +: 4]),
+			.i_axi_awvalid(S_AXI_AWVALID[N]),
+			.i_axi_awready(S_AXI_AWREADY[N]),
+			//
+			.i_axi_wdata( S_AXI_WDATA[ N*DW   +: DW]),
+			.i_axi_wstrb( S_AXI_WSTRB[ N*DW/8 +: DW/8]),
+			.i_axi_wlast( S_AXI_WLAST[ N]),
+			.i_axi_wvalid(S_AXI_WVALID[N]),
+			.i_axi_wready(S_AXI_WREADY[N]),
+			//
+			.i_axi_bid(   S_AXI_BID[   N*IW +:IW]),
+			.i_axi_bresp( S_AXI_BRESP[ N*2 +: 2]),
+			.i_axi_bvalid(S_AXI_BVALID[N]),
+			.i_axi_bready(S_AXI_BREADY[N]),
+			//
+			.i_axi_arid(   S_AXI_ARID[   N*IW +:IW]),
+			.i_axi_arready(S_AXI_ARREADY[N]),
+			.i_axi_araddr( S_AXI_ARADDR[ N*AW +:AW]),
+			.i_axi_arlen(  S_AXI_ARLEN[  N* 8 +: 8]),
+			.i_axi_arsize( S_AXI_ARSIZE[ N* 3 +: 3]),
+			.i_axi_arburst(S_AXI_ARBURST[N* 2 +: 2]),
+			.i_axi_arlock( S_AXI_ARLOCK[ N]),
+			.i_axi_arcache(S_AXI_ARCACHE[N* 4 +: 4]),
+			.i_axi_arprot( S_AXI_ARPROT[ N* 3 +: 3]),
+			.i_axi_arqos(  S_AXI_ARQOS[  N* 4 +: 4]),
+			.i_axi_arvalid(S_AXI_ARVALID[N]),
+			//
+			//
+			.i_axi_rid(   S_AXI_RID[   N*IW +: IW]),
+			.i_axi_rdata( S_AXI_RDATA[ N*DW +: DW]),
+			.i_axi_rresp( S_AXI_RRESP[ N* 2 +: 2]),
+			.i_axi_rlast( S_AXI_RLAST[ N]),
+			.i_axi_rvalid(S_AXI_RVALID[N]),
+			.i_axi_rready(S_AXI_RREADY[N]),
+			//
+			// ...
+			//
+			);
+
+		//
+		// ...
+		//
+
+		//
+		// Check full/empty flags
+		//
+
+		always @(*)
+		begin
+			assert(mwfull[N] == &w_mawpending[N]);
+			assert(mwempty[N] == (w_mawpending[N] == 0));
+		end
+
+		always @(*)
+		begin
+			assert(mrfull[N] == &w_mrpending[N]);
+			assert(mrempty[N] == (w_mrpending[N] == 0));
+		end
+	// }}}
+	end endgenerate
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI signaling check, (outgoing) slave side
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	generate for(M=0; M<NS; M=M+1)
+	begin : F3_CHECK_SLAVES
+	// {{{
+		faxi_master #(
+			.C_AXI_ID_WIDTH(IW),
+			.C_AXI_DATA_WIDTH(DW),
+			.C_AXI_ADDR_WIDTH(AW),
+			.F_OPT_ASSUME_RESET(1'b1),
+			.F_AXI_MAXSTALL(2),
+			.F_AXI_MAXRSTALL(0),
+			.F_AXI_MAXDELAY(2),
+			.F_OPT_READCHECK(0),
+			.F_OPT_NO_RESET(1),
+			.F_LGDEPTH(F_LGDEPTH))
+		  slvi(.i_clk(S_AXI_ACLK),
+			.i_axi_reset_n(S_AXI_ARESETN),
+			//
+			.i_axi_awid(   M_AXI_AWID[   M*IW+:IW]),
+			.i_axi_awaddr( M_AXI_AWADDR[ M*AW +: AW]),
+			.i_axi_awlen(  M_AXI_AWLEN[  M*8 +: 8]),
+			.i_axi_awsize( M_AXI_AWSIZE[ M*3 +: 3]),
+			.i_axi_awburst(M_AXI_AWBURST[M*2 +: 2]),
+			.i_axi_awlock( M_AXI_AWLOCK[ M]),
+			.i_axi_awcache(M_AXI_AWCACHE[M*4 +: 4]),
+			.i_axi_awprot( M_AXI_AWPROT[ M*3 +: 3]),
+			.i_axi_awqos(  M_AXI_AWQOS[  M*4 +: 4]),
+			.i_axi_awvalid(M_AXI_AWVALID[M]),
+			.i_axi_awready(M_AXI_AWREADY[M]),
+			//
+			.i_axi_wready(M_AXI_WREADY[M]),
+			.i_axi_wdata( M_AXI_WDATA[ M*DW   +: DW]),
+			.i_axi_wstrb( M_AXI_WSTRB[ M*DW/8 +: DW/8]),
+			.i_axi_wlast( M_AXI_WLAST[ M]),
+			.i_axi_wvalid(M_AXI_WVALID[M]),
+			//
+			.i_axi_bid(   M_AXI_BID[   M*IW +: IW]),
+			.i_axi_bresp( M_AXI_BRESP[ M*2 +: 2]),
+			.i_axi_bvalid(M_AXI_BVALID[M]),
+			.i_axi_bready(M_AXI_BREADY[M]),
+			//
+			.i_axi_arid(   M_AXI_ARID[   M*IW +:IW]),
+			.i_axi_araddr( M_AXI_ARADDR[ M*AW +:AW]),
+			.i_axi_arlen(  M_AXI_ARLEN[  M*8  +: 8]),
+			.i_axi_arsize( M_AXI_ARSIZE[ M*3  +: 3]),
+			.i_axi_arburst(M_AXI_ARBURST[M*2  +: 2]),
+			.i_axi_arlock( M_AXI_ARLOCK[ M]),
+			.i_axi_arcache(M_AXI_ARCACHE[M* 4 +: 4]),
+			.i_axi_arprot( M_AXI_ARPROT[ M* 3 +: 3]),
+			.i_axi_arqos(  M_AXI_ARQOS[  M* 4 +: 4]),
+			.i_axi_arvalid(M_AXI_ARVALID[M]),
+			.i_axi_arready(M_AXI_ARREADY[M]),
+			//
+			//
+			.i_axi_rresp( M_AXI_RRESP[ M*2 +: 2]),
+			.i_axi_rvalid(M_AXI_RVALID[M]),
+			.i_axi_rdata( M_AXI_RDATA[ M*DW +: DW]),
+			.i_axi_rready(M_AXI_RREADY[M]),
+			.i_axi_rlast( M_AXI_RLAST[ M]),
+			.i_axi_rid(   M_AXI_RID[   M*IW +: IW]),
+			//
+			// ...
+			//
+			);
+
+			//
+			// ...
+			//
+
+		always @(*)
+		if (M_AXI_AWVALID[M])
+			assert(((M_AXI_AWADDR[M*AW +:AW]^SLAVE_ADDR[M*AW +:AW])
+				& SLAVE_MASK[M*AW +: AW]) == 0);
+
+		always @(*)
+		if (M_AXI_ARVALID[M])
+			assert(((M_AXI_ARADDR[M*AW +:AW]^SLAVE_ADDR[M*AW +:AW])
+				& SLAVE_MASK[M*AW +: AW]) == 0);
+	// }}}
+	end endgenerate
+	// }}}
+
+	// m_axi_* convenience signals
+	// {{{
+	// ...
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// ...
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	generate for(N=0; N<NM; N=N+1)
+	begin : // ...
+	// {{{
+	// }}}
+	end endgenerate
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Double buffer checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate for(N=0; N<NM; N=N+1)
+	begin : F4_DOUBLE_BUFFER_CHECKS
+	// {{{
+	// ...
+	// }}}
+	end endgenerate
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Can every master reach every slave?
+	// Can things transition without dropping the request line(s)?
+	generate for(N=0; N<NM; N=N+1)
+	begin : F5_COVER_CONNECTIVITY_FROM_MASTER
+	// {{{
+	// ...
+	// }}}
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Focused check: How fast can one master talk to each of the slaves?
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// ...
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Focused check: How fast can one master talk to a particular slave?
+	// We'll pick master 1 and slave 1.
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// ...
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Poor man's cover check
+	// {{{
+	// ...
+	// }}}
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Negation check
+	// {{{
+	// Pick a particular value.  Assume the value doesn't show up on the
+	// input.  Prove it doesn't show up on the output.  This will check for
+	// ...
+	// 1. Stuck bits on the output channel
+	// 2. Cross-talk between channels
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	// ...
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Artificially constraining assumptions
+	// {{{
+	// Ideally, this section should be empty--there should be no
+	// assumptions here.  The existence of these assumptions should
+	// give you an idea of where I'm at with this project.
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	generate for(N=0; N<NM; N=N+1)
+	begin : F6_LIMITING_ASSUMPTIONS
+
+		if (!OPT_WRITES)
+		begin
+			always @(*)
+				assume(S_AXI_AWVALID[N] == 0);
+			always @(*)
+				assert(wgrant[N] == 0);
+			always @(*)
+				assert(mwgrant[N] == 0);
+			always @(*)
+				assert(S_AXI_BVALID[N]== 0);
+		end
+
+		if (!OPT_READS)
+		begin
+			always @(*)
+				assume(S_AXI_ARVALID [N]== 0);
+			always @(*)
+				assert(rgrant[N] == 0);
+			always @(*)
+				assert(S_AXI_RVALID[N] == 0);
+		end
+
+	end endgenerate
+
+	always@(*)
+		assert(OPT_READS | OPT_WRITES);
+	// }}}
+`endif
+// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axixclk.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axixclk.v
new file mode 100644
index 0000000..d362974
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axixclk.v
@@ -0,0 +1,309 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axixclk.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Cross AXI clock domains
+//
+// Performance:
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module axixclk #(
+	parameter integer C_S_AXI_ID_WIDTH	= 2,
+	parameter integer C_S_AXI_DATA_WIDTH	= 32,
+	parameter integer C_S_AXI_ADDR_WIDTH	= 6,
+	// Some useful short-hand definitions
+	localparam	AW = C_S_AXI_ADDR_WIDTH,
+	localparam	DW = C_S_AXI_DATA_WIDTH,
+	localparam	IW = C_S_AXI_ID_WIDTH,
+	localparam	LSB = $clog2(C_S_AXI_DATA_WIDTH)-3,
+	//
+	parameter [0:0]	OPT_WRITE_ONLY = 1'b0,
+	parameter [0:0]	OPT_READ_ONLY = 1'b0,
+	parameter	XCLOCK_FFS = 2,
+	parameter	LGFIFO = 5
+	) (
+		// Users to add ports here
+
+		// User ports ends
+		// Do not modify the ports beyond this line
+
+		input	wire				S_AXI_ACLK,
+		input	wire				S_AXI_ARESETN,
+		//
+		input	wire [C_S_AXI_ID_WIDTH-1 : 0]	S_AXI_AWID,
+		input	wire [C_S_AXI_ADDR_WIDTH-1 : 0]	S_AXI_AWADDR,
+		input	wire [7 : 0]			S_AXI_AWLEN,
+		input	wire [2 : 0]			S_AXI_AWSIZE,
+		input	wire [1 : 0]			S_AXI_AWBURST,
+		input	wire				S_AXI_AWLOCK,
+		input	wire [3 : 0]			S_AXI_AWCACHE,
+		input	wire [2 : 0]			S_AXI_AWPROT,
+		input	wire [3 : 0]			S_AXI_AWQOS,
+		input	wire				S_AXI_AWVALID,
+		output	wire				S_AXI_AWREADY,
+		//
+		input	wire [C_S_AXI_DATA_WIDTH-1 : 0]	S_AXI_WDATA,
+		input	wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,
+		input	wire				S_AXI_WLAST,
+		input	wire				S_AXI_WVALID,
+		output	wire				S_AXI_WREADY,
+		//
+		output	wire [C_S_AXI_ID_WIDTH-1 : 0]	S_AXI_BID,
+		output	wire [1 : 0]			S_AXI_BRESP,
+		output	wire				S_AXI_BVALID,
+		input	wire				S_AXI_BREADY,
+		//
+		input	wire [C_S_AXI_ID_WIDTH-1 : 0]	S_AXI_ARID,
+		input	wire [C_S_AXI_ADDR_WIDTH-1 : 0]	S_AXI_ARADDR,
+		input	wire [7 : 0]			S_AXI_ARLEN,
+		input	wire [2 : 0]			S_AXI_ARSIZE,
+		input	wire [1 : 0]			S_AXI_ARBURST,
+		input	wire				S_AXI_ARLOCK,
+		input	wire [3 : 0]			S_AXI_ARCACHE,
+		input	wire [2 : 0]			S_AXI_ARPROT,
+		input	wire [3 : 0]			S_AXI_ARQOS,
+		input	wire				S_AXI_ARVALID,
+		output	wire				S_AXI_ARREADY,
+		//
+		output	wire [C_S_AXI_ID_WIDTH-1 : 0]	S_AXI_RID,
+		output	wire [C_S_AXI_DATA_WIDTH-1 : 0]	S_AXI_RDATA,
+		output	wire [1 : 0]			S_AXI_RRESP,
+		output	wire				S_AXI_RLAST,
+		output	wire				S_AXI_RVALID,
+		input	wire				S_AXI_RREADY,
+
+		//
+		//	Downstream port
+		//
+		input	wire				M_AXI_ACLK,
+		output	wire				M_AXI_ARESETN,
+		//
+		output	wire [C_S_AXI_ID_WIDTH-1 : 0]	M_AXI_AWID,
+		output	wire [C_S_AXI_ADDR_WIDTH-1 : 0]	M_AXI_AWADDR,
+		output	wire [7 : 0]			M_AXI_AWLEN,
+		output	wire [2 : 0]			M_AXI_AWSIZE,
+		output	wire [1 : 0]			M_AXI_AWBURST,
+		output	wire				M_AXI_AWLOCK,
+		output	wire [3 : 0]			M_AXI_AWCACHE,
+		output	wire [2 : 0]			M_AXI_AWPROT,
+		output	wire [3 : 0]			M_AXI_AWQOS,
+		output	wire				M_AXI_AWVALID,
+		input	wire				M_AXI_AWREADY,
+		//
+		output	wire [C_S_AXI_DATA_WIDTH-1 : 0]	M_AXI_WDATA,
+		output	wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] M_AXI_WSTRB,
+		output	wire				M_AXI_WLAST,
+		output	wire				M_AXI_WVALID,
+		input	wire				M_AXI_WREADY,
+		//
+		input	wire [C_S_AXI_ID_WIDTH-1 : 0]	M_AXI_BID,
+		input	wire [1 : 0]			M_AXI_BRESP,
+		input	wire				M_AXI_BVALID,
+		output	wire				M_AXI_BREADY,
+		//
+		output	wire [C_S_AXI_ID_WIDTH-1 : 0]	M_AXI_ARID,
+		output	wire [C_S_AXI_ADDR_WIDTH-1 : 0]	M_AXI_ARADDR,
+		output	wire [7 : 0]			M_AXI_ARLEN,
+		output	wire [2 : 0]			M_AXI_ARSIZE,
+		output	wire [1 : 0]			M_AXI_ARBURST,
+		output	wire				M_AXI_ARLOCK,
+		output	wire [3 : 0]			M_AXI_ARCACHE,
+		output	wire [2 : 0]			M_AXI_ARPROT,
+		output	wire [3 : 0]			M_AXI_ARQOS,
+		output	wire				M_AXI_ARVALID,
+		input	wire				M_AXI_ARREADY,
+		//
+		input	wire [C_S_AXI_ID_WIDTH-1 : 0]	M_AXI_RID,
+		input	wire [C_S_AXI_DATA_WIDTH-1 : 0]	M_AXI_RDATA,
+		input	wire [1 : 0]			M_AXI_RRESP,
+		input	wire				M_AXI_RLAST,
+		input	wire				M_AXI_RVALID,
+		output	wire				M_AXI_RREADY
+	);
+
+	reg	[2:0]	mreset;
+
+	(* ASYNC_REG = "TRUE" *) initial	mreset = 3'b000;
+	always @(posedge M_AXI_ACLK, negedge S_AXI_ARESETN)
+	if (!S_AXI_ARESETN)
+		mreset <= 3'b000;
+	else
+		mreset <= { mreset[1:0], 1'b1 };
+
+	assign	M_AXI_ARESETN = mreset[2];
+
+	generate if (OPT_READ_ONLY)
+	begin : READ_ONLY
+
+		assign	M_AXI_AWID = 0;
+		assign	M_AXI_AWADDR = 0;
+		assign	M_AXI_AWLEN  = 0;
+		assign	M_AXI_AWSIZE = 0;
+		assign	M_AXI_AWBURST= 0;
+		assign	M_AXI_AWLOCK = 0;
+		assign	M_AXI_AWCACHE= 0;
+		assign	M_AXI_AWPROT = 0;
+		assign	M_AXI_AWQOS  = 0;
+		// Either way we do these we're wrong, so don't try accessing
+		// the write side of the bus when OPT_READ_ONLY is set or your
+		// design will hang.
+
+		assign	M_AXI_AWVALID = 1'b0;
+		assign	S_AXI_AWREADY = 1'b0;
+
+		assign	M_AXI_WDATA = 0;
+		assign	M_AXI_WSTRB = 0;
+		assign	M_AXI_WLAST = 0;
+
+		assign	M_AXI_WVALID = 1'b0;
+		assign	S_AXI_WREADY = 1'b0;
+
+		assign	S_AXI_BID   = 0;
+		assign	S_AXI_BRESP = 2'b11;
+
+		assign	M_AXI_BREADY = 1'b0;
+		assign	S_AXI_BVALID = 1'b0;
+
+	end else begin : WRITE_FIFO
+		wire	awfull, awempty, wfull, wempty, bfull, bempty;
+
+		afifo #(.LGFIFO(LGFIFO),
+			.NFF(XCLOCK_FFS),
+			.WIDTH(C_S_AXI_ID_WIDTH + C_S_AXI_ADDR_WIDTH
+				+ 8 + 3 + 2 + 1 + 4 + 3 + 4))
+		awfifo(S_AXI_ACLK, S_AXI_ARESETN, S_AXI_AWVALID&& S_AXI_AWREADY,
+			{ S_AXI_AWID, S_AXI_AWADDR,
+				S_AXI_AWLEN, S_AXI_AWSIZE, S_AXI_AWBURST,
+				S_AXI_AWLOCK,
+				S_AXI_AWCACHE, S_AXI_AWPROT, S_AXI_AWQOS },
+			awfull,
+			M_AXI_ACLK, M_AXI_ARESETN, M_AXI_AWREADY,
+			{ M_AXI_AWID, M_AXI_AWADDR,
+				M_AXI_AWLEN, M_AXI_AWSIZE, M_AXI_AWBURST,
+				M_AXI_AWLOCK,
+				M_AXI_AWCACHE, M_AXI_AWPROT, M_AXI_AWQOS },
+			awempty);
+
+		assign	M_AXI_AWVALID = !awempty;
+		assign	S_AXI_AWREADY = !awfull;
+
+		afifo #(.LGFIFO(LGFIFO),
+			.NFF(XCLOCK_FFS),
+			.WIDTH(C_S_AXI_DATA_WIDTH + C_S_AXI_DATA_WIDTH/8 + 1))
+		wfifo(S_AXI_ACLK, S_AXI_ARESETN, S_AXI_WVALID&& S_AXI_WREADY,
+			{ S_AXI_WDATA, S_AXI_WSTRB, S_AXI_WLAST },
+			wfull,
+			M_AXI_ACLK, M_AXI_ARESETN, M_AXI_WREADY,
+			{ M_AXI_WDATA, M_AXI_WSTRB, M_AXI_WLAST },
+			wempty);
+
+		assign	M_AXI_WVALID = !wempty;
+		assign	S_AXI_WREADY = !wfull;
+
+		afifo #(.LGFIFO(LGFIFO),
+			.NFF(XCLOCK_FFS),
+			.WIDTH(C_S_AXI_ID_WIDTH + 2))
+		bfifo(M_AXI_ACLK, M_AXI_ARESETN, M_AXI_BVALID&& M_AXI_BREADY,
+			{ M_AXI_BID, M_AXI_BRESP }, bfull,
+			S_AXI_ACLK, S_AXI_ARESETN, S_AXI_BREADY,
+			{ S_AXI_BID, S_AXI_BRESP }, bempty);
+
+		assign	S_AXI_BVALID = !bempty;
+		assign	M_AXI_BREADY = !bfull;
+	end endgenerate
+
+	generate if (OPT_WRITE_ONLY)
+	begin : NO_READS
+
+		assign	M_AXI_ARID = 0;
+		assign	M_AXI_ARADDR = 0;
+		assign	M_AXI_ARLEN  = 0;
+		assign	M_AXI_ARSIZE = 0;
+		assign	M_AXI_ARBURST= 0;
+		assign	M_AXI_ARLOCK = 0;
+		assign	M_AXI_ARCACHE= 0;
+		assign	M_AXI_ARPROT = 0;
+		assign	M_AXI_ARQOS  = 0;
+		// Either way we do these we're wrong, so don't try accessing
+		// the write side of the bus when OPT_READ_ONLY is set or your
+		// design will hang.
+
+		assign	M_AXI_ARVALID = 1'b0;
+		assign	S_AXI_ARREADY = 1'b0;
+
+		assign	S_AXI_RID   = 0;
+		assign	S_AXI_RDATA = 2'b11;
+		assign	S_AXI_RLAST = 1'b1;
+		assign	S_AXI_RRESP = 2'b11;
+
+		assign	M_AXI_RREADY = 1'b0;
+		assign	S_AXI_RVALID = 1'b0;
+
+	end else begin : READ_FIFO
+		wire	arfull, arempty, rfull, rempty;
+
+		afifo #(.LGFIFO(LGFIFO),
+			.NFF(XCLOCK_FFS),
+			.WIDTH(C_S_AXI_ID_WIDTH + C_S_AXI_ADDR_WIDTH
+				+ 8 + 3 + 2 + 1 + 4 + 3 + 4))
+		arfifo(S_AXI_ACLK, S_AXI_ARESETN, S_AXI_ARVALID&& S_AXI_ARREADY,
+			{ S_AXI_ARID, S_AXI_ARADDR,
+				S_AXI_ARLEN, S_AXI_ARSIZE, S_AXI_ARBURST,
+				S_AXI_ARLOCK,
+				S_AXI_ARCACHE, S_AXI_ARPROT, S_AXI_ARQOS },
+			arfull,
+			M_AXI_ACLK, M_AXI_ARESETN, M_AXI_ARREADY,
+			{ M_AXI_ARID, M_AXI_ARADDR,
+				M_AXI_ARLEN, M_AXI_ARSIZE, M_AXI_ARBURST,
+				M_AXI_ARLOCK,
+				M_AXI_ARCACHE, M_AXI_ARPROT, M_AXI_ARQOS },
+			arempty);
+
+		assign	M_AXI_ARVALID = !arempty;
+		assign	S_AXI_ARREADY = !arfull;
+
+
+		afifo #(.LGFIFO(LGFIFO),
+			.NFF(XCLOCK_FFS),
+			.WIDTH(C_S_AXI_ID_WIDTH + C_S_AXI_DATA_WIDTH+3))
+		rfifo(M_AXI_ACLK, M_AXI_ARESETN, M_AXI_RVALID&& M_AXI_RREADY,
+			{ M_AXI_RID, M_AXI_RDATA, M_AXI_RLAST, M_AXI_RRESP },
+			rfull,
+			S_AXI_ACLK, S_AXI_ARESETN, S_AXI_RREADY,
+			{ S_AXI_RID, S_AXI_RDATA, S_AXI_RLAST, S_AXI_RRESP },
+			rempty);
+
+		assign	S_AXI_RVALID = !rempty;
+		assign	M_AXI_RREADY = !rfull;
+
+	end endgenerate
+
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axlite2wbsp.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/axlite2wbsp.v
new file mode 100644
index 0000000..d252005
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axlite2wbsp.v
@@ -0,0 +1,477 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	axlite2wbsp.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Take an AXI lite input, and convert it into WB.
+//
+//	We'll treat AXI as two separate busses: one for writes, another for
+//	reads, further, we'll insist that the two channels AXI uses for writes
+//	combine into one channel for our purposes.
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2016-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module axlite2wbsp( i_clk, i_axi_reset_n,
+	//
+	o_axi_awready, i_axi_awaddr, i_axi_awcache, i_axi_awprot,i_axi_awvalid,
+	//
+	o_axi_wready, i_axi_wdata, i_axi_wstrb, i_axi_wvalid,
+	//
+	o_axi_bresp, o_axi_bvalid, i_axi_bready,
+	//
+	o_axi_arready, i_axi_araddr, i_axi_arcache, i_axi_arprot, i_axi_arvalid,
+	//
+	o_axi_rresp, o_axi_rvalid, o_axi_rdata, i_axi_rready,
+	//
+	// Wishbone interface
+	o_reset, o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, o_wb_sel,
+	i_wb_ack, i_wb_stall, i_wb_data, i_wb_err);
+	//
+	parameter C_AXI_DATA_WIDTH	= 32;// Width of the AXI R&W data
+	parameter C_AXI_ADDR_WIDTH	= 28;	// AXI Address width
+	parameter		LGFIFO = 4;
+	parameter		F_MAXSTALL = 3;
+	parameter		F_MAXDELAY = 3;
+	parameter	[0:0]	OPT_READONLY  = 1'b0;
+	parameter	[0:0]	OPT_WRITEONLY = 1'b0;
+	localparam	F_LGDEPTH = LGFIFO+1;
+	//
+	input	wire			i_clk;	// System clock
+	input	wire			i_axi_reset_n;
+
+// AXI write address channel signals
+	output	wire			o_axi_awready;//Slave is ready to accept
+	input	wire	[C_AXI_ADDR_WIDTH-1:0]	i_axi_awaddr;	// Write address
+	input	wire	[3:0]		i_axi_awcache;	// Write Cache type
+	input	wire	[2:0]		i_axi_awprot;	// Write Protection type
+	input	wire			i_axi_awvalid;	// Write address valid
+
+// AXI write data channel signals
+	output	wire			o_axi_wready;  // Write data ready
+	input	wire	[C_AXI_DATA_WIDTH-1:0]	i_axi_wdata;	// Write data
+	input	wire	[C_AXI_DATA_WIDTH/8-1:0] i_axi_wstrb;	// Write strobes
+	input	wire			i_axi_wvalid;	// Write valid
+
+// AXI write response channel signals
+	output	wire [1:0]		o_axi_bresp;	// Write response
+	output	wire 			o_axi_bvalid;  // Write reponse valid
+	input	wire			i_axi_bready;  // Response ready
+
+// AXI read address channel signals
+	output	wire			o_axi_arready;	// Read address ready
+	input	wire	[C_AXI_ADDR_WIDTH-1:0]	i_axi_araddr;	// Read address
+	input	wire	[3:0]		i_axi_arcache;	// Read Cache type
+	input	wire	[2:0]		i_axi_arprot;	// Read Protection type
+	input	wire			i_axi_arvalid;	// Read address valid
+
+// AXI read data channel signals
+	output	wire [1:0]		o_axi_rresp;   // Read response
+	output	wire			o_axi_rvalid;  // Read reponse valid
+	output	wire [C_AXI_DATA_WIDTH-1:0] o_axi_rdata;    // Read data
+	input	wire			i_axi_rready;  // Read Response ready
+
+	// We'll share the clock and the reset
+	output	wire			o_reset;
+	output	wire			o_wb_cyc;
+	output	wire			o_wb_stb;
+	output	wire			o_wb_we;
+	output	wire [(C_AXI_ADDR_WIDTH-3):0]		o_wb_addr;
+	output	wire [(C_AXI_DATA_WIDTH-1):0]		o_wb_data;
+	output	wire [(C_AXI_DATA_WIDTH/8-1):0]	o_wb_sel;
+	input	wire			i_wb_ack;
+	input	wire			i_wb_stall;
+	input	wire [(C_AXI_DATA_WIDTH-1):0]		i_wb_data;
+	input	wire			i_wb_err;
+
+
+	localparam DW = C_AXI_DATA_WIDTH;
+	localparam AW = C_AXI_ADDR_WIDTH-2;
+	//
+	//
+	//
+
+	wire	[(AW-1):0]			w_wb_addr, r_wb_addr;
+	wire	[(C_AXI_DATA_WIDTH-1):0]	w_wb_data;
+	wire	[(C_AXI_DATA_WIDTH/8-1):0]	w_wb_sel;
+	wire	r_wb_err, r_wb_cyc, r_wb_stb, r_wb_stall, r_wb_ack;
+	wire	w_wb_err, w_wb_cyc, w_wb_stb, w_wb_stall, w_wb_ack;
+
+	// verilator lint_off UNUSED
+	wire	r_wb_we, w_wb_we;
+
+	assign	r_wb_we = 1'b0;
+	assign	w_wb_we = 1'b1;
+	// verilator lint_on  UNUSED
+
+`ifdef	FORMAL
+	wire	[LGFIFO:0]	f_wr_fifo_first, f_rd_fifo_first,
+				f_wr_fifo_mid,   f_rd_fifo_mid,
+				f_wr_fifo_last,  f_rd_fifo_last;
+	wire	[(F_LGDEPTH-1):0]	f_wb_nreqs, f_wb_nacks,
+					f_wb_outstanding;
+	wire	[(F_LGDEPTH-1):0]	f_wb_wr_nreqs, f_wb_wr_nacks,
+					f_wb_wr_outstanding;
+	wire	[(F_LGDEPTH-1):0]	f_wb_rd_nreqs, f_wb_rd_nacks,
+					f_wb_rd_outstanding;
+	wire			f_pending_awvalid, f_pending_wvalid;
+`endif
+
+	//
+	// AXI-lite write channel to WB processing
+	//
+	generate if (!OPT_READONLY)
+	begin : AXI_WR
+	axilwr2wbsp #(
+		// .F_LGDEPTH(F_LGDEPTH),
+		// .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), // .AW(AW),
+		.LGFIFO(LGFIFO))
+		axi_write_decoder(
+			.i_clk(i_clk), .i_axi_reset_n(i_axi_reset_n),
+			//
+			.o_axi_awready(o_axi_awready),
+			.i_axi_awaddr( i_axi_awaddr),
+			.i_axi_awcache(i_axi_awcache),
+			.i_axi_awprot( i_axi_awprot),
+			.i_axi_awvalid(i_axi_awvalid),
+			//
+			.o_axi_wready( o_axi_wready),
+			.i_axi_wdata(  i_axi_wdata),
+			.i_axi_wstrb(  i_axi_wstrb),
+			.i_axi_wvalid( i_axi_wvalid),
+			//
+			.o_axi_bresp(o_axi_bresp),
+			.o_axi_bvalid(o_axi_bvalid),
+			.i_axi_bready(i_axi_bready),
+			//
+			.o_wb_cyc(  w_wb_cyc),
+			.o_wb_stb(  w_wb_stb),
+			.o_wb_addr( w_wb_addr),
+			.o_wb_data( w_wb_data),
+			.o_wb_sel(  w_wb_sel),
+			.i_wb_ack(  w_wb_ack),
+			.i_wb_stall(w_wb_stall),
+			.i_wb_err(  w_wb_err)
+`ifdef	FORMAL
+			,
+			.f_first(f_wr_fifo_first),
+			.f_mid(  f_wr_fifo_mid),
+			.f_last( f_wr_fifo_last),
+			.f_wpending({ f_pending_awvalid, f_pending_wvalid })
+`endif
+		);
+	end else begin
+		assign	w_wb_cyc  = 0;
+		assign	w_wb_stb  = 0;
+		assign	w_wb_addr = 0;
+		assign	w_wb_data = 0;
+		assign	w_wb_sel  = 0;
+		assign	o_axi_awready = 0;
+		assign	o_axi_wready  = 0;
+		assign	o_axi_bvalid  = (i_axi_wvalid);
+		assign	o_axi_bresp   = 2'b11;
+`ifdef	FORMAL
+		assign	f_wr_fifo_first = 0;
+		assign	f_wr_fifo_mid   = 0;
+		assign	f_wr_fifo_last  = 0;
+		assign	f_pending_awvalid=0;
+		assign	f_pending_wvalid =0;
+`endif
+	end endgenerate
+	assign	w_wb_we = 1'b1;
+
+	//
+	// AXI-lite read channel to WB processing
+	//
+	generate if (!OPT_WRITEONLY)
+	begin : AXI_RD
+	axilrd2wbsp #(
+		// .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.LGFIFO(LGFIFO))
+		axi_read_decoder(
+			.i_clk(i_clk), .i_axi_reset_n(i_axi_reset_n),
+			//
+			.o_axi_arready(o_axi_arready),
+			.i_axi_araddr( i_axi_araddr),
+			.i_axi_arcache(i_axi_arcache),
+			.i_axi_arprot( i_axi_arprot),
+			.i_axi_arvalid(i_axi_arvalid),
+			//
+			.o_axi_rresp( o_axi_rresp),
+			.o_axi_rvalid(o_axi_rvalid),
+			.o_axi_rdata( o_axi_rdata),
+			.i_axi_rready(i_axi_rready),
+			//
+			.o_wb_cyc(  r_wb_cyc),
+			.o_wb_stb(  r_wb_stb),
+			.o_wb_addr( r_wb_addr),
+			.i_wb_ack(  r_wb_ack),
+			.i_wb_stall(r_wb_stall),
+			.i_wb_data( i_wb_data),
+			.i_wb_err(  r_wb_err)
+`ifdef	FORMAL
+			,
+			.f_first(f_rd_fifo_first),
+			.f_mid(  f_rd_fifo_mid),
+			.f_last( f_rd_fifo_last)
+`endif
+			);
+	end else begin
+		assign	r_wb_cyc  = 0;
+		assign	r_wb_stb  = 0;
+		assign	r_wb_addr = 0;
+		//
+		assign o_axi_arready = 1'b1;
+		assign o_axi_rvalid  = (i_axi_arvalid)&&(o_axi_arready);
+		assign o_axi_rresp   = (i_axi_arvalid) ? 2'b11 : 2'b00;
+		assign o_axi_rdata   = 0;
+`ifdef	FORMAL
+		assign	f_rd_fifo_first = 0;
+		assign	f_rd_fifo_mid   = 0;
+		assign	f_rd_fifo_last  = 0;
+`endif
+	end endgenerate
+
+	//
+	//
+	// The arbiter that pastes the two sides together
+	//
+	//
+	generate if (OPT_READONLY)
+	begin : ARB_RD
+		assign	o_wb_cyc  = r_wb_cyc;
+		assign	o_wb_stb  = r_wb_stb;
+		assign	o_wb_we   = 1'b0;
+		assign	o_wb_addr = r_wb_addr;
+		assign	o_wb_data = 32'h0;
+		assign	o_wb_sel  = 0;
+		assign	r_wb_ack  = i_wb_ack;
+		assign	r_wb_stall= i_wb_stall;
+		assign	r_wb_ack  = i_wb_ack;
+		assign	r_wb_err  = i_wb_err;
+
+`ifdef	FORMAL
+		fwb_master #(.DW(DW), .AW(AW),
+			.F_LGDEPTH(F_LGDEPTH),
+			.F_MAX_STALL(F_MAXSTALL),
+			.F_MAX_ACK_DELAY(F_MAXDELAY))
+		f_wb(i_clk, !i_axi_reset_n,
+			o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data,
+				o_wb_sel,
+			i_wb_ack, i_wb_stall, i_wb_data, i_wb_err,
+			f_wb_nreqs, f_wb_nacks, f_wb_outstanding);
+
+		assign f_wb_rd_nreqs = f_wb_nreqs;
+		assign f_wb_rd_nacks = f_wb_nacks;
+		assign f_wb_rd_outstanding = f_wb_outstanding;
+		//
+		assign f_wb_wr_nreqs = 0;
+		assign f_wb_wr_nacks = 0;
+		assign f_wb_wr_outstanding = 0;
+`endif
+	end else if (OPT_WRITEONLY)
+	begin : ARB_WR
+		assign	o_wb_cyc  = w_wb_cyc;
+		assign	o_wb_stb  = w_wb_stb;
+		assign	o_wb_we   = 1'b1;
+		assign	o_wb_addr = w_wb_addr;
+		assign	o_wb_data = w_wb_data;
+		assign	o_wb_sel  = w_wb_sel;
+		assign	w_wb_ack  = i_wb_ack;
+		assign	w_wb_stall= i_wb_stall;
+		assign	w_wb_ack  = i_wb_ack;
+		assign	w_wb_err  = i_wb_err;
+
+`ifdef FORMAL
+		fwb_master #(.DW(DW), .AW(AW),
+			.F_LGDEPTH(F_LGDEPTH),
+			.F_MAX_STALL(F_MAXSTALL),
+			.F_MAX_ACK_DELAY(F_MAXDELAY))
+		f_wb(i_clk, !i_axi_reset_n,
+			o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data,
+				o_wb_sel,
+			i_wb_ack, i_wb_stall, i_wb_data, i_wb_err,
+			f_wb_nreqs, f_wb_nacks, f_wb_outstanding);
+
+		assign f_wb_wr_nreqs = f_wb_nreqs;
+		assign f_wb_wr_nacks = f_wb_nacks;
+		assign f_wb_wr_outstanding = f_wb_outstanding;
+		//
+		assign f_wb_rd_nreqs = 0;
+		assign f_wb_rd_nacks = 0;
+		assign f_wb_rd_outstanding = 0;
+`endif
+	end else begin : ARB_WB
+		wbarbiter	#(.DW(DW), .AW(AW),
+			.F_LGDEPTH(F_LGDEPTH),
+			.F_MAX_STALL(F_MAXSTALL),
+			.F_MAX_ACK_DELAY(F_MAXDELAY))
+			readorwrite(i_clk, !i_axi_reset_n,
+			r_wb_cyc, r_wb_stb, 1'b0, r_wb_addr, w_wb_data, w_wb_sel,
+				r_wb_ack, r_wb_stall, r_wb_err,
+			w_wb_cyc, w_wb_stb, 1'b1, w_wb_addr, w_wb_data, w_wb_sel,
+				w_wb_ack, w_wb_stall, w_wb_err,
+			o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, o_wb_sel,
+				i_wb_ack, i_wb_stall, i_wb_err
+`ifdef	FORMAL
+			,
+			f_wb_rd_nreqs, f_wb_rd_nacks, f_wb_rd_outstanding,
+			f_wb_wr_nreqs, f_wb_wr_nacks, f_wb_wr_outstanding,
+			f_wb_nreqs, f_wb_nacks, f_wb_outstanding
+`endif
+			);
+	end endgenerate
+
+	assign	o_reset = (i_axi_reset_n == 1'b0);
+
+`ifdef	FORMAL
+	reg	f_past_valid;
+
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid = 1'b1;
+
+	initial	assume(!i_axi_reset_n);
+	always @(*)
+	if (!f_past_valid)
+		assume(!i_axi_reset_n);
+
+	wire	[(F_LGDEPTH-1):0]	f_axi_rd_outstanding,
+					f_axi_wr_outstanding,
+					f_axi_awr_outstanding;
+	wire	[(F_LGDEPTH-1):0]	f_axi_rd_id_outstanding,
+					f_axi_awr_id_outstanding,
+					f_axi_wr_id_outstanding;
+	wire	[8:0]			f_axi_wr_pending,
+					f_axi_rd_count,
+					f_axi_wr_count;
+
+	faxil_slave #(
+			// .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+			.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+			.F_LGDEPTH(F_LGDEPTH),
+			.F_AXI_MAXWAIT(0),
+			.F_AXI_MAXDELAY(0))
+		f_axi(.i_clk(i_clk), .i_axi_reset_n(i_axi_reset_n),
+			// AXI write address channnel
+			.i_axi_awready(o_axi_awready),
+			.i_axi_awaddr( i_axi_awaddr),
+			.i_axi_awcache(i_axi_awcache),
+			.i_axi_awprot( i_axi_awprot),
+			.i_axi_awvalid(i_axi_awvalid),
+			// AXI write data channel
+			.i_axi_wready( o_axi_wready),
+			.i_axi_wdata(  i_axi_wdata),
+			.i_axi_wstrb(  i_axi_wstrb),
+			.i_axi_wvalid( i_axi_wvalid),
+			// AXI write acknowledgement channel
+			.i_axi_bresp( o_axi_bresp),
+			.i_axi_bvalid(o_axi_bvalid),
+			.i_axi_bready(i_axi_bready),
+			// AXI read address channel
+			.i_axi_arready(o_axi_arready),
+			.i_axi_araddr( i_axi_araddr),
+			.i_axi_arcache(i_axi_arcache),
+			.i_axi_arprot( i_axi_arprot),
+			.i_axi_arvalid(i_axi_arvalid),
+			// AXI read data return
+			.i_axi_rresp(  o_axi_rresp),
+			.i_axi_rvalid( o_axi_rvalid),
+			.i_axi_rdata(  o_axi_rdata),
+			.i_axi_rready( i_axi_rready),
+			// Quantify where we are within a transaction
+			.f_axi_rd_outstanding( f_axi_rd_outstanding),
+			.f_axi_wr_outstanding( f_axi_wr_outstanding),
+			.f_axi_awr_outstanding(f_axi_awr_outstanding));
+
+	wire	f_axi_ard_req, f_axi_awr_req, f_axi_wr_req,
+		f_axi_rd_ack, f_axi_wr_ack;
+
+	assign	f_axi_ard_req = (i_axi_arvalid)&&(o_axi_arready);
+	assign	f_axi_awr_req = (i_axi_awvalid)&&(o_axi_awready);
+	assign	f_axi_wr_req  = (i_axi_wvalid)&&(o_axi_wready);
+	assign	f_axi_wr_ack  = (o_axi_bvalid)&&(i_axi_bready);
+	assign	f_axi_rd_ack  = (o_axi_rvalid)&&(i_axi_rready);
+
+	wire	[LGFIFO:0]	f_awr_fifo_axi_used,
+				f_dwr_fifo_axi_used,
+				f_rd_fifo_axi_used,
+				f_wr_fifo_wb_outstanding,
+				f_rd_fifo_wb_outstanding;
+
+	assign	f_awr_fifo_axi_used = f_wr_fifo_first - f_wr_fifo_last;
+	assign	f_rd_fifo_axi_used  = f_rd_fifo_first - f_rd_fifo_last;
+	assign	f_wr_fifo_wb_outstanding = f_wr_fifo_first - f_wr_fifo_last;
+	assign	f_rd_fifo_wb_outstanding = f_rd_fifo_first - f_rd_fifo_last;
+
+	always @(*)
+	begin
+		assert(f_axi_rd_outstanding  == f_rd_fifo_axi_used);
+		assert(f_axi_awr_outstanding == f_awr_fifo_axi_used+ (f_pending_awvalid?1:0));
+		assert(f_axi_wr_outstanding  == f_awr_fifo_axi_used+ (f_pending_wvalid?1:0));
+	end
+
+	always @(*)
+	if (OPT_READONLY)
+	begin
+		assert(f_axi_awr_outstanding == 0);
+		assert(f_axi_wr_outstanding  == 0);
+	end
+
+	always @(*)
+	if (OPT_WRITEONLY)
+	begin
+		assert(f_axi_rd_outstanding == 0);
+	end
+
+	//
+	initial assert((!OPT_READONLY)||(!OPT_WRITEONLY));
+
+	always @(*)
+	if (OPT_READONLY)
+	begin
+		assume(i_axi_awvalid == 0);
+		assume(i_axi_wvalid == 0);
+
+		assert(o_axi_bvalid == 0);
+	end
+
+	always @(*)
+	if (OPT_WRITEONLY)
+	begin
+		assume(i_axi_arvalid == 0);
+		assert(o_axi_rvalid == 0);
+	end
+`endif
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/axlite_wrapper.vhd b/verilog/rtl/softshell/third_party/wb2axip/rtl/axlite_wrapper.vhd
new file mode 100644
index 0000000..e580485
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/axlite_wrapper.vhd
@@ -0,0 +1,136 @@
+--------------------------------------------------------------------------------
+--
+-- Filename: 	axlite_wrapper.vhd
+--
+-- Project:	WB2AXIPSP: bus bridges and other odds and ends
+--
+-- Purpose:	When wrapped with this wrapper, the axlite2wbsp.v core was
+--		verified to work in FPGA silicon via Vivado.
+--
+--	Thank you Ambroz for donating this code!
+--
+-- Creator:	Ambroz Bizjak
+--
+--------------------------------------------------------------------------------
+--
+-- Copyright (C) 2019-2020, Gisselquist Technology, LLC
+--
+-- This file is part of the WB2AXIP project.
+--
+-- The WB2AXIP project contains free software and gateware, licensed under the
+-- Apache License, Version 2.0 (the "License").  You may not use this project,
+-- or this file, except in compliance with the License.  You may obtain a copy
+-- of the License at
+--
+--	http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+-- License for the specific language governing permissions and limitations
+-- under the License.
+--
+--------------------------------------------------------------------------------
+--
+--
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+ 
+entity axlite2wbsp_wrapper is
+    generic (
+        C_AXI_ADDR_WIDTH : integer := 28;
+        LGFIFO : integer := 4;
+        F_MAXSTALL : integer := 3;
+        F_MAXDELAY : integer := 3;
+       
+        --- Must not be changed.
+        C_AXI_DATA_WIDTH : integer := 32
+    );
+    port (
+        s_axi_aclk : in std_logic;        
+        s_axi_aresetn : in std_logic;
+       
+        s_axi_awready : out std_logic;
+        s_axi_awaddr : in std_logic_vector(C_AXI_ADDR_WIDTH-1 downto 0);
+        s_axi_awcache : in std_logic_vector(3 downto 0);
+        s_axi_awprot : in std_logic_vector(2 downto 0);
+        s_axi_awvalid : in std_logic;
+        s_axi_wready : out std_logic;
+        s_axi_wdata : in std_logic_vector(C_AXI_DATA_WIDTH-1 downto 0);
+        s_axi_wstrb : in std_logic_vector(C_AXI_DATA_WIDTH/8-1 downto 0);
+        s_axi_wvalid : in std_logic;
+        s_axi_bresp : out std_logic_vector(1 downto 0);
+        s_axi_bvalid : out std_logic;
+        s_axi_bready : in std_logic;
+        s_axi_arready : out std_logic;
+        s_axi_araddr : in std_logic_vector(C_AXI_ADDR_WIDTH-1 downto 0);
+        s_axi_arcache : in std_logic_vector(3 downto 0);
+        s_axi_arprot : in std_logic_vector(2 downto 0);
+        s_axi_arvalid : in std_logic;
+        s_axi_rresp : out std_logic_vector(1 downto 0);
+        s_axi_rvalid : out std_logic;
+        s_axi_rdata : out std_logic_vector(C_AXI_DATA_WIDTH-1 downto 0);
+        s_axi_rready : in std_logic;
+       
+        m_wb_reset : out std_logic;
+        m_wb_cyc : out std_logic;
+        m_wb_stb : out std_logic;
+        m_wb_we : out std_logic;
+        m_wb_adr : out std_logic_vector(C_AXI_ADDR_WIDTH-2-1 downto 0);
+        m_wb_dat_w : out std_logic_vector(C_AXI_DATA_WIDTH-1 downto 0);
+        m_wb_sel : out std_logic_vector(C_AXI_DATA_WIDTH/8-1 downto 0);
+        m_wb_ack : in std_logic;
+        m_wb_stall : in std_logic;
+        m_wb_dat_r : in std_logic_vector(C_AXI_DATA_WIDTH-1 downto 0);
+        m_wb_err : in std_logic
+    );
+end axlite2wbsp_wrapper;
+ 
+architecture Behavioral of axlite2wbsp_wrapper is
+ 
+begin
+    axlite2wbsp : entity work.axlite2wbsp
+        generic map (
+            C_AXI_ADDR_WIDTH => C_AXI_ADDR_WIDTH,
+            LGFIFO => LGFIFO,
+            F_MAXSTALL => F_MAXSTALL,
+            F_MAXDELAY => F_MAXDELAY
+        )
+        port map (
+            i_clk => s_axi_aclk,
+            i_axi_reset_n => s_axi_aresetn,
+            o_axi_awready => s_axi_awready,
+            i_axi_awaddr => s_axi_awaddr,
+            i_axi_awcache => s_axi_awcache,
+            i_axi_awprot => s_axi_awprot,
+            i_axi_awvalid => s_axi_awvalid,
+            o_axi_wready => s_axi_wready,
+            i_axi_wdata => s_axi_wdata,
+            i_axi_wstrb => s_axi_wstrb,
+            i_axi_wvalid => s_axi_wvalid,
+            o_axi_bresp => s_axi_bresp,
+            o_axi_bvalid => s_axi_bvalid,
+            i_axi_bready => s_axi_bready,
+            o_axi_arready => s_axi_arready,
+            i_axi_araddr => s_axi_araddr,
+            i_axi_arcache => s_axi_arcache,
+            i_axi_arprot => s_axi_arprot,
+            i_axi_arvalid => s_axi_arvalid,
+            o_axi_rresp => s_axi_rresp,
+            o_axi_rvalid => s_axi_rvalid,
+            o_axi_rdata => s_axi_rdata,
+            i_axi_rready => s_axi_rready,
+            o_reset => m_wb_reset,
+            o_wb_cyc => m_wb_cyc,
+            o_wb_stb => m_wb_stb,
+            o_wb_we => m_wb_we,
+            o_wb_addr => m_wb_adr,
+            o_wb_data => m_wb_dat_w,
+            o_wb_sel => m_wb_sel,
+            i_wb_ack => m_wb_ack,
+            i_wb_stall => m_wb_stall,
+            i_wb_data => m_wb_dat_r,
+            i_wb_err => m_wb_err
+        );
+ 
+end Behavioral;
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/demoaxi.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/demoaxi.v
new file mode 100644
index 0000000..aba4cb1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/demoaxi.v
@@ -0,0 +1,717 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	demoaxi.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Demonstrate an AXI-lite bus design.  The goal of this design
+//		is to support a completely pipelined AXI-lite transaction
+//	which can transfer one data item per clock.
+//
+//	Note that the AXI spec requires that there be no combinatorial
+//	logic between input ports and output ports.  Hence all of the *valid
+//	and *ready signals produced here are registered.  This forces us into
+//	the buffered handshake strategy.
+//
+//	Some curious variable meanings below:
+//
+//	!axi_arvalid is synonymous with having a request, but stalling because
+//		of a current request sitting in axi_rvalid with !axi_rready
+//	!axi_awvalid is also synonymous with having an axi address being
+//		received, but either the axi_bvalid && !axi_bready, or
+//		no write data has been received
+//	!axi_wvalid is similar to axi_awvalid.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2018-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+
+`timescale 1 ns / 1 ps
+
+module	demoaxi
+	#(
+		// Users to add parameters here
+		parameter [0:0] OPT_READ_SIDEEFFECTS = 1,
+		// User parameters ends
+		// Do not modify the parameters beyond this line
+		// Width of S_AXI data bus
+		parameter integer C_S_AXI_DATA_WIDTH	= 32,
+		// Width of S_AXI address bus
+		parameter integer C_S_AXI_ADDR_WIDTH	= 8
+	) (
+		// Users to add ports here
+		// No user ports (yet) in this design
+		// User ports ends
+
+		// Do not modify the ports beyond this line
+		// Global Clock Signal
+		input wire  S_AXI_ACLK,
+		// Global Reset Signal. This Signal is Active LOW
+		input wire  S_AXI_ARESETN,
+		// Write address (issued by master, acceped by Slave)
+		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
+		// Write channel Protection type. This signal indicates the
+    		// privilege and security level of the transaction, and whether
+    		// the transaction is a data access or an instruction access.
+		input wire [2 : 0] S_AXI_AWPROT,
+		// Write address valid. This signal indicates that the master
+		// signaling valid write address and control information.
+		input wire  S_AXI_AWVALID,
+		// Write address ready. This signal indicates that the slave
+		// is ready to accept an address and associated control signals.
+		output wire  S_AXI_AWREADY,
+		// Write data (issued by master, acceped by Slave)
+		input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,
+		// Write strobes. This signal indicates which byte lanes hold
+    		// valid data. There is one write strobe bit for each eight
+    		// bits of the write data bus.
+		input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,
+		// Write valid. This signal indicates that valid write
+    		// data and strobes are available.
+		input wire  S_AXI_WVALID,
+		// Write ready. This signal indicates that the slave
+    		// can accept the write data.
+		output wire  S_AXI_WREADY,
+		// Write response. This signal indicates the status
+    		// of the write transaction.
+		output wire [1 : 0] S_AXI_BRESP,
+		// Write response valid. This signal indicates that the channel
+    		// is signaling a valid write response.
+		output wire  S_AXI_BVALID,
+		// Response ready. This signal indicates that the master
+    		// can accept a write response.
+		input wire  S_AXI_BREADY,
+		// Read address (issued by master, acceped by Slave)
+		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
+		// Protection type. This signal indicates the privilege
+    		// and security level of the transaction, and whether the
+    		// transaction is a data access or an instruction access.
+		input wire [2 : 0] S_AXI_ARPROT,
+		// Read address valid. This signal indicates that the channel
+    		// is signaling valid read address and control information.
+		input wire  S_AXI_ARVALID,
+		// Read address ready. This signal indicates that the slave is
+    		// ready to accept an address and associated control signals.
+		output wire  S_AXI_ARREADY,
+		// Read data (issued by slave)
+		output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
+		// Read response. This signal indicates the status of the
+    		// read transfer.
+		output wire [1 : 0] S_AXI_RRESP,
+		// Read valid. This signal indicates that the channel is
+    		// signaling the required read data.
+		output wire  S_AXI_RVALID,
+		// Read ready. This signal indicates that the master can
+    		// accept the read data and response information.
+		input wire  S_AXI_RREADY
+	);
+
+	// AXI4LITE signals
+	reg		axi_awready;
+	reg		axi_wready;
+	reg		axi_bvalid;
+	reg		axi_arready;
+	reg [C_S_AXI_DATA_WIDTH-1 : 0] 	axi_rdata;
+	reg		axi_rvalid;
+
+	// Example-specific design signals
+	// local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH
+	// ADDR_LSB is used for addressing 32/64 bit registers/memories
+	// ADDR_LSB = 2 for 32 bits (n downto 2)
+	// ADDR_LSB = 3 for 64 bits (n downto 3)
+	localparam integer ADDR_LSB = 2;
+	localparam integer AW = C_S_AXI_ADDR_WIDTH-2;
+	localparam integer DW = C_S_AXI_DATA_WIDTH;
+	//----------------------------------------------
+	//-- Signals for user logic register space example
+	//------------------------------------------------
+	reg [DW-1:0]	slv_mem	[0:63];
+
+	// I/O Connections assignments
+
+	assign S_AXI_AWREADY	= axi_awready;
+	assign S_AXI_WREADY	= axi_wready;
+	assign S_AXI_BRESP	= 2'b00; // The OKAY response
+	assign S_AXI_BVALID	= axi_bvalid;
+	assign S_AXI_ARREADY	= axi_arready;
+	assign S_AXI_RDATA	= axi_rdata;
+	assign S_AXI_RRESP	= 2'b00; // The OKAY response
+	assign S_AXI_RVALID	= axi_rvalid;
+	// Implement axi_*wready generation
+
+	//////////////////////////////////////
+	//
+	// Read processing
+	//
+	//
+	wire	valid_read_request,
+		read_response_stall;
+
+	assign	valid_read_request  =  S_AXI_ARVALID || !S_AXI_ARREADY;
+	assign	read_response_stall =  S_AXI_RVALID  && !S_AXI_RREADY;
+
+	//
+	// The read response channel valid signal
+	//
+	initial	axi_rvalid = 1'b0;
+	always @(posedge S_AXI_ACLK )
+	if (!S_AXI_ARESETN)
+		axi_rvalid <= 0;
+	else if (read_response_stall)
+		// Need to stay valid as long as the return path is stalled
+		axi_rvalid <= 1'b1;
+	else if (valid_read_request)
+		axi_rvalid <= 1'b1;
+	else
+		// Any stall has cleared, so we can always
+		// clear the valid signal in this case
+		axi_rvalid <= 1'b0;
+
+	reg [C_S_AXI_ADDR_WIDTH-1 : 0] 	pre_raddr, rd_addr;
+
+	// Buffer the address
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARREADY)
+		pre_raddr <= S_AXI_ARADDR;
+
+	always @(*)
+	if (!axi_arready)
+		rd_addr = pre_raddr;
+	else
+		rd_addr = S_AXI_ARADDR;
+
+	//
+	// Read the data
+	//
+	always @(posedge S_AXI_ACLK)
+	if (!read_response_stall
+		&&(!OPT_READ_SIDEEFFECTS || valid_read_request))
+		// If the outgoing channel is not stalled (above)
+		// then read
+		axi_rdata <= slv_mem[rd_addr[AW+ADDR_LSB-1:ADDR_LSB]];
+
+	//
+	// The read address channel ready signal
+	//
+	initial	axi_arready = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_arready <= 1'b1;
+	else if (read_response_stall)
+	begin
+		// Outgoing channel is stalled
+		//    As long as something is already in the buffer,
+		//    axi_arready needs to stay low
+		axi_arready <= !valid_read_request;
+	end else
+		axi_arready <= 1'b1;
+
+	//////////////////////////////////////
+	//
+	// Write processing
+	//
+	//
+	reg [C_S_AXI_ADDR_WIDTH-1 : 0]		pre_waddr, waddr;
+	reg [C_S_AXI_DATA_WIDTH-1 : 0]		pre_wdata, wdata;
+	reg [(C_S_AXI_DATA_WIDTH/8)-1 : 0]	pre_wstrb, wstrb;
+
+	wire	valid_write_address, valid_write_data,
+		write_response_stall;
+
+	assign	valid_write_address = S_AXI_AWVALID || !axi_awready;
+	assign	valid_write_data    = S_AXI_WVALID  || !axi_wready;
+	assign	write_response_stall= S_AXI_BVALID  && !S_AXI_BREADY;
+
+	//
+	// The write address channel ready signal
+	//
+	initial	axi_awready = 1'b1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_awready <= 1'b1;
+	else if (write_response_stall)
+	begin
+		// The output channel is stalled
+		//	If our buffer is full, we need to remain stalled
+		//	Likewise if it is empty, and there's a request,
+		//	  we'll need to stall.
+		axi_awready <= !valid_write_address;
+	end else if (valid_write_data)
+		// The output channel is clear, and write data
+		// are available
+		axi_awready <= 1'b1;
+	else
+		// If we were ready before, then remain ready unless an
+		// address unaccompanied by data shows up
+		axi_awready <= ((axi_awready)&&(!S_AXI_AWVALID));
+		// This is equivalent to
+		// axi_awready <= !valid_write_address
+
+	//
+	// The write data channel ready signal
+	//
+	initial	axi_wready = 1'b1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_wready <= 1'b1;
+	else if (write_response_stall)
+		// The output channel is stalled
+		//	We can remain ready until valid
+		//	write data shows up
+		axi_wready <= !valid_write_data;
+	else if (valid_write_address)
+		// The output channel is clear, and a write address
+		// is available
+		axi_wready <= 1'b1;
+	else
+		// if we were ready before, and there's no new data avaialble
+		// to cause us to stall, remain ready
+		axi_wready <= (axi_wready)&&(!S_AXI_WVALID);
+		// This is equivalent to
+		// axi_wready <= !valid_write_data
+
+
+	// Buffer the address
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_AWREADY)
+		pre_waddr <= S_AXI_AWADDR;
+
+	// Buffer the data
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_WREADY)
+	begin
+		pre_wdata <= S_AXI_WDATA;
+		pre_wstrb <= S_AXI_WSTRB;
+	end
+
+	always @(*)
+	if (!axi_awready)
+		// Read the write address from our "buffer"
+		waddr = pre_waddr;
+	else
+		waddr = S_AXI_AWADDR;
+
+	always @(*)
+	if (!axi_wready)
+	begin
+		// Read the write data from our "buffer"
+		wstrb = pre_wstrb;
+		wdata = pre_wdata;
+	end else begin
+		wstrb = S_AXI_WSTRB;
+		wdata = S_AXI_WDATA;
+	end
+
+	//
+	// Actually (finally) write the data
+	//
+	always @(posedge S_AXI_ACLK )
+	// If the output channel isn't stalled, and
+	if (!write_response_stall
+		// If we have a valid address, and
+		&& valid_write_address
+		// If we have valid data
+		&& valid_write_data)
+	begin
+		if (wstrb[0])
+			slv_mem[waddr[AW+ADDR_LSB-1:ADDR_LSB]][7:0]
+				<= wdata[7:0];
+		if (wstrb[1])
+			slv_mem[waddr[AW+ADDR_LSB-1:ADDR_LSB]][15:8]
+				<= wdata[15:8];
+		if (wstrb[2])
+			slv_mem[waddr[AW+ADDR_LSB-1:ADDR_LSB]][23:16]
+				<= wdata[23:16];
+		if (wstrb[3])
+			slv_mem[waddr[AW+ADDR_LSB-1:ADDR_LSB]][31:24]
+				<= wdata[31:24];
+	end
+
+	//
+	// The write response channel valid signal
+	//
+	initial	axi_bvalid = 1'b0;
+	always @(posedge S_AXI_ACLK )
+	if (!S_AXI_ARESETN)
+		axi_bvalid <= 1'b0;
+	//
+	// The outgoing response channel should indicate a valid write if ...
+		// 1. We have a valid address, and
+	else if (valid_write_address
+			// 2. We had valid data
+			&& valid_write_data)
+		// It doesn't matter here if we are stalled or not
+		// We can keep setting ready as often as we want
+		axi_bvalid <= 1'b1;
+	else if (S_AXI_BREADY)
+		// Otherwise, if BREADY was true, then it was just accepted
+		// and can return to idle now
+		axi_bvalid <= 1'b0;
+
+	// Make Verilator happy
+	// Verilator lint_off UNUSED
+	wire	[4*ADDR_LSB+5:0]	unused;
+	assign	unused = { S_AXI_AWPROT, S_AXI_ARPROT,
+				S_AXI_AWADDR[ADDR_LSB-1:0],
+				rd_addr[ADDR_LSB-1:0],
+				waddr[ADDR_LSB-1:0],
+				S_AXI_ARADDR[ADDR_LSB-1:0] };
+	// Verilator lint_on UNUSED
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	localparam	F_LGDEPTH = 4;
+
+	wire	[(F_LGDEPTH-1):0]	f_axi_awr_outstanding,
+					f_axi_wr_outstanding,
+					f_axi_rd_outstanding;
+
+	faxil_slave #(// .C_AXI_DATA_WIDTH(C_S_AXI_DATA_WIDTH),
+			.C_AXI_ADDR_WIDTH(C_S_AXI_ADDR_WIDTH),
+			// .F_OPT_NO_READS(1'b0),
+			// .F_OPT_NO_WRITES(1'b0),
+			.F_OPT_XILINX(1),
+			.F_LGDEPTH(F_LGDEPTH))
+		properties (
+		.i_clk(S_AXI_ACLK),
+		.i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awaddr(S_AXI_AWADDR),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot(S_AXI_AWPROT),
+		.i_axi_awvalid(S_AXI_AWVALID),
+		.i_axi_awready(S_AXI_AWREADY),
+		//
+		.i_axi_wdata(S_AXI_WDATA),
+		.i_axi_wstrb(S_AXI_WSTRB),
+		.i_axi_wvalid(S_AXI_WVALID),
+		.i_axi_wready(S_AXI_WREADY),
+		//
+		.i_axi_bresp(S_AXI_BRESP),
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+		//
+		.i_axi_araddr(S_AXI_ARADDR),
+		.i_axi_arprot(S_AXI_ARPROT),
+		.i_axi_arcache(4'h0),
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+		//
+		.i_axi_rdata(S_AXI_RDATA),
+		.i_axi_rresp(S_AXI_RRESP),
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rready(S_AXI_RREADY),
+		//
+		.f_axi_rd_outstanding(f_axi_rd_outstanding),
+		.f_axi_wr_outstanding(f_axi_wr_outstanding),
+		.f_axi_awr_outstanding(f_axi_awr_outstanding));
+
+	reg	f_past_valid;
+	initial	f_past_valid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1'b1;
+
+	///////
+	//
+	// Properties necessary to pass induction
+	always @(*)
+	if (S_AXI_ARESETN)
+	begin
+		if (!S_AXI_RVALID)
+			assert(f_axi_rd_outstanding == 0);
+		else if (!S_AXI_ARREADY)
+			assert((f_axi_rd_outstanding == 2)||(f_axi_rd_outstanding == 1));
+		else
+			assert(f_axi_rd_outstanding == 1);
+	end
+
+	always @(*)
+	if (S_AXI_ARESETN)
+	begin
+		if (axi_bvalid)
+		begin
+			assert(f_axi_awr_outstanding == 1+(axi_awready ? 0:1));
+			assert(f_axi_wr_outstanding  == 1+(axi_wready  ? 0:1));
+		end else begin
+			assert(f_axi_awr_outstanding == (axi_awready ? 0:1));
+			assert(f_axi_wr_outstanding  == (axi_wready  ? 0:1));
+		end
+	end
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover properties
+	//
+	// In addition to making sure the design returns a value, any value,
+	// let's cover returning three values on adjacent clocks--just to prove
+	// we can.
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(posedge S_AXI_ACLK )
+	if ((f_past_valid)&&(S_AXI_ARESETN))
+		cover(($past((S_AXI_BVALID && S_AXI_BREADY)))
+			&&($past((S_AXI_BVALID && S_AXI_BREADY),2))
+			&&(S_AXI_BVALID && S_AXI_BREADY));
+
+	always @(posedge S_AXI_ACLK )
+	if ((f_past_valid)&&(S_AXI_ARESETN))
+		cover(($past((S_AXI_RVALID && S_AXI_RREADY)))
+			&&($past((S_AXI_RVALID && S_AXI_RREADY),2))
+			&&(S_AXI_RVALID && S_AXI_RREADY));
+
+	// Let's go just one further, and verify we can do three returns in a
+	// row.  Why?  It might just be possible that one value was waiting
+	// already, and so we haven't yet tested that two requests could be
+	// made in a row.
+	always @(posedge S_AXI_ACLK )
+	if ((f_past_valid)&&(S_AXI_ARESETN))
+		cover(($past((S_AXI_BVALID && S_AXI_BREADY)))
+			&&($past((S_AXI_BVALID && S_AXI_BREADY),2))
+			&&($past((S_AXI_BVALID && S_AXI_BREADY),3))
+			&&(S_AXI_BVALID && S_AXI_BREADY));
+
+	always @(posedge S_AXI_ACLK )
+	if ((f_past_valid)&&(S_AXI_ARESETN))
+		cover(($past((S_AXI_RVALID && S_AXI_RREADY)))
+			&&($past((S_AXI_RVALID && S_AXI_RREADY),2))
+			&&($past((S_AXI_RVALID && S_AXI_RREADY),3))
+			&&(S_AXI_RVALID && S_AXI_RREADY));
+
+	//
+	// Let's create a sophisticated cover statement designed to show off
+	// how our core can handle stalls and non-valids, synchronizing
+	// across multiple scenarios
+	reg	[22:0]	fw_wrdemo_pipe, fr_wrdemo_pipe;
+	always @(*)
+	if (!S_AXI_ARESETN)
+		fw_wrdemo_pipe = 0;
+	else begin
+		fw_wrdemo_pipe[0] = (S_AXI_AWVALID)
+				&&(S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[1] = fr_wrdemo_pipe[0]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[2] = fr_wrdemo_pipe[1]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		//
+		//
+		fw_wrdemo_pipe[3] = fr_wrdemo_pipe[2]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[4] = fr_wrdemo_pipe[3]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[5] = fr_wrdemo_pipe[4]
+				&&(!S_AXI_AWVALID)
+				&&(S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[6] = fr_wrdemo_pipe[5]
+				&&(S_AXI_AWVALID)
+				&&( S_AXI_WVALID)
+				&&( S_AXI_BREADY);
+		fw_wrdemo_pipe[7] = fr_wrdemo_pipe[6]
+				&&(!S_AXI_AWVALID)
+				&&(S_AXI_WVALID)
+				&&( S_AXI_BREADY);
+		fw_wrdemo_pipe[8] = fr_wrdemo_pipe[7]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[9] = fr_wrdemo_pipe[8]
+//				&&(S_AXI_AWVALID)
+//				&&(!S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[10] = fr_wrdemo_pipe[9]
+//				&&(S_AXI_AWVALID)
+//				&&(S_AXI_WVALID)
+				// &&(S_AXI_BREADY);
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[11] = fr_wrdemo_pipe[10]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID)
+				&&(!S_AXI_BREADY);
+		fw_wrdemo_pipe[12] = fr_wrdemo_pipe[11]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[13] = fr_wrdemo_pipe[12]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[14] = fr_wrdemo_pipe[13]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID)
+				&&(f_axi_awr_outstanding == 0)
+				&&(f_axi_wr_outstanding == 0)
+				&&(S_AXI_BREADY);
+		//
+		//
+		//
+		fw_wrdemo_pipe[15] = fr_wrdemo_pipe[14]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[16] = fr_wrdemo_pipe[15]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[17] = fr_wrdemo_pipe[16]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[18] = fr_wrdemo_pipe[17]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID)
+				&&(!S_AXI_BREADY);
+		fw_wrdemo_pipe[19] = fr_wrdemo_pipe[18]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[20] = fr_wrdemo_pipe[19]
+				&&(S_AXI_AWVALID)
+				&&(S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[21] = fr_wrdemo_pipe[20]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+		fw_wrdemo_pipe[22] = fr_wrdemo_pipe[21]
+				&&(!S_AXI_AWVALID)
+				&&(!S_AXI_WVALID)
+				&&(S_AXI_BREADY);
+	end
+
+	always @(posedge S_AXI_ACLK)
+		fr_wrdemo_pipe <= fw_wrdemo_pipe;
+
+	always @(*)
+	if (S_AXI_ARESETN)
+	begin
+		cover(fw_wrdemo_pipe[0]);
+		cover(fw_wrdemo_pipe[1]);
+		cover(fw_wrdemo_pipe[2]);
+		cover(fw_wrdemo_pipe[3]);
+		cover(fw_wrdemo_pipe[4]);
+		cover(fw_wrdemo_pipe[5]);
+		cover(fw_wrdemo_pipe[6]);
+		cover(fw_wrdemo_pipe[7]); //
+		cover(fw_wrdemo_pipe[8]);
+		cover(fw_wrdemo_pipe[9]);
+		cover(fw_wrdemo_pipe[10]);
+		cover(fw_wrdemo_pipe[11]);
+		cover(fw_wrdemo_pipe[12]);
+		cover(fw_wrdemo_pipe[13]);
+		cover(fw_wrdemo_pipe[14]);
+		cover(fw_wrdemo_pipe[15]);
+		cover(fw_wrdemo_pipe[16]);
+		cover(fw_wrdemo_pipe[17]);
+		cover(fw_wrdemo_pipe[18]);
+		cover(fw_wrdemo_pipe[19]);
+		cover(fw_wrdemo_pipe[20]);
+		cover(fw_wrdemo_pipe[21]);
+		cover(fw_wrdemo_pipe[22]);
+	end
+
+	//
+	// Now let's repeat, but for a read demo
+	reg	[10:0]	fw_rddemo_pipe, fr_rddemo_pipe;
+	always @(*)
+	if (!S_AXI_ARESETN)
+		fw_rddemo_pipe = 0;
+	else begin
+		fw_rddemo_pipe[0] = (S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rddemo_pipe[1] = fr_rddemo_pipe[0]
+				&&(!S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rddemo_pipe[2] = fr_rddemo_pipe[1]
+				&&(!S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		//
+		//
+		fw_rddemo_pipe[3] = fr_rddemo_pipe[2]
+				&&(S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rddemo_pipe[4] = fr_rddemo_pipe[3]
+				&&(S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rddemo_pipe[5] = fr_rddemo_pipe[4]
+				&&(S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rddemo_pipe[6] = fr_rddemo_pipe[5]
+				&&(S_AXI_ARVALID)
+				&&(!S_AXI_RREADY);
+		fw_rddemo_pipe[7] = fr_rddemo_pipe[6]
+				&&(S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rddemo_pipe[8] = fr_rddemo_pipe[7]
+				&&(S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rddemo_pipe[9] = fr_rddemo_pipe[8]
+				&&(!S_AXI_ARVALID)
+				&&(S_AXI_RREADY);
+		fw_rddemo_pipe[10] = fr_rddemo_pipe[9]
+				&&(f_axi_rd_outstanding == 0);
+	end
+
+	initial	fr_rddemo_pipe = 0;
+	always @(posedge S_AXI_ACLK)
+		fr_rddemo_pipe <= fw_rddemo_pipe;
+
+	always @(*)
+	begin
+		cover(fw_rddemo_pipe[0]);
+		cover(fw_rddemo_pipe[1]);
+		cover(fw_rddemo_pipe[2]);
+		cover(fw_rddemo_pipe[3]);
+		cover(fw_rddemo_pipe[4]);
+		cover(fw_rddemo_pipe[5]);
+		cover(fw_rddemo_pipe[6]);
+		cover(fw_rddemo_pipe[7]);
+		cover(fw_rddemo_pipe[8]);
+		cover(fw_rddemo_pipe[9]);
+		cover(fw_rddemo_pipe[10]);
+	end
+`endif
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/demofull.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/demofull.v
new file mode 100644
index 0000000..cbd37f5
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/demofull.v
@@ -0,0 +1,752 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	demofull.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Demonstrate a formally verified AXI4 core with a (basic)
+//		interface.  This interface is explained below.
+//
+// Performance: This core has been designed for a total throughput of one beat
+//		per clock cycle.  Both read and write channels can achieve
+//	this.  The write channel will also introduce two clocks of latency,
+//	assuming no other latency from the master.  This means it will take
+//	a minimum of 3+AWLEN clock cycles per transaction of (1+AWLEN) beats,
+//	including both address and acknowledgment cycles.  The read channel
+//	will introduce a single clock of latency, requiring 2+ARLEN cycles
+//	per transaction of 1+ARLEN beats.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module demofull #(
+	parameter integer C_S_AXI_ID_WIDTH	= 2,
+	parameter integer C_S_AXI_DATA_WIDTH	= 32,
+	parameter integer C_S_AXI_ADDR_WIDTH	= 6,
+	// Some useful short-hand definitions
+	localparam	AW = C_S_AXI_ADDR_WIDTH,
+	localparam	DW = C_S_AXI_DATA_WIDTH,
+	localparam	IW = C_S_AXI_ID_WIDTH,
+	localparam	LSB = $clog2(C_S_AXI_DATA_WIDTH)-3,
+
+	parameter [0:0]	OPT_NARROW_BURST = 1
+	) (
+		// Users to add ports here
+
+		// A very basic protocol-independent peripheral interface
+		// 1. A value will be written any time o_we is true
+		// 2. A value will be read any time o_rd is true
+		// 3. Such a slave might just as easily be written as:
+		//
+		//	always @(posedge S_AXI_ACLK)
+		//	if (o_we)
+		//	begin
+		//	    for(k=0; k<C_S_AXI_DATA_WIDTH/8; k=k+1)
+		//	    begin
+		//		if (o_wstrb[k])
+		//		mem[o_waddr[AW-1:LSB]][k*8+:8] <= o_wdata[k*8+:8]
+		//	    end
+		//	end
+		//
+		//	always @(posedge S_AXI_ACLK)
+		//	if (o_rd)
+		//		i_rdata <= mem[o_raddr[AW-1:LSB]];
+		//
+		// 4. The rule on the input is that i_rdata must be registered,
+		//    and that it must only change if o_rd is true.  Violating
+		//    this rule will cause this core to violate the AXI
+		//    protocol standard, as this value is not registered within
+		//    this core
+		output	reg					o_we,
+		output	reg	[C_S_AXI_ADDR_WIDTH-LSB-1:0]	o_waddr,
+		output	reg	[C_S_AXI_DATA_WIDTH-1:0]	o_wdata,
+		output	reg	[C_S_AXI_DATA_WIDTH/8-1:0]	o_wstrb,
+		//
+		output	reg					o_rd,
+		output	reg	[C_S_AXI_ADDR_WIDTH-LSB-1:0]	o_raddr,
+		input	wire	[C_S_AXI_DATA_WIDTH-1:0]	i_rdata,
+		//
+		// User ports ends
+		// Do not modify the ports beyond this line
+
+		// Global Clock Signal
+		input wire  S_AXI_ACLK,
+		// Global Reset Signal. This Signal is Active LOW
+		input wire  S_AXI_ARESETN,
+		// Write Address ID
+		input wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_AWID,
+		// Write address
+		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
+		// Burst length. The burst length gives the exact number of
+		// transfers in a burst
+		input wire [7 : 0] S_AXI_AWLEN,
+		// Burst size. This signal indicates the size of each transfer
+		// in the burst
+		input wire [2 : 0] S_AXI_AWSIZE,
+		// Burst type. The burst type and the size information,
+		// determine how the address for each transfer within the burst
+		// is calculated.
+		input wire [1 : 0] S_AXI_AWBURST,
+		// Lock type. Provides additional information about the
+		// atomic characteristics of the transfer.
+		input wire  S_AXI_AWLOCK,
+		// Memory type. This signal indicates how transactions
+		// are required to progress through a system.
+		input wire [3 : 0] S_AXI_AWCACHE,
+		// Protection type. This signal indicates the privilege
+		// and security level of the transaction, and whether
+		// the transaction is a data access or an instruction access.
+		input wire [2 : 0] S_AXI_AWPROT,
+		// Quality of Service, QoS identifier sent for each
+		// write transaction.
+		input wire [3 : 0] S_AXI_AWQOS,
+		// Region identifier. Permits a single physical interface
+		// on a slave to be used for multiple logical interfaces.
+		// Write address valid. This signal indicates that
+		// the channel is signaling valid write address and
+		// control information.
+		input wire  S_AXI_AWVALID,
+		// Write address ready. This signal indicates that
+		// the slave is ready to accept an address and associated
+		// control signals.
+		output wire  S_AXI_AWREADY,
+		// Write Data
+		input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,
+		// Write strobes. This signal indicates which byte
+		// lanes hold valid data. There is one write strobe
+		// bit for each eight bits of the write data bus.
+		input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,
+		// Write last. This signal indicates the last transfer
+		// in a write burst.
+		input wire  S_AXI_WLAST,
+		// Optional User-defined signal in the write data channel.
+		// Write valid. This signal indicates that valid write
+		// data and strobes are available.
+		input wire  S_AXI_WVALID,
+		// Write ready. This signal indicates that the slave
+		// can accept the write data.
+		output wire  S_AXI_WREADY,
+		// Response ID tag. This signal is the ID tag of the
+		// write response.
+		output wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_BID,
+		// Write response. This signal indicates the status
+		// of the write transaction.
+		output wire [1 : 0] S_AXI_BRESP,
+		// Optional User-defined signal in the write response channel.
+		// Write response valid. This signal indicates that the
+		// channel is signaling a valid write response.
+		output wire  S_AXI_BVALID,
+		// Response ready. This signal indicates that the master
+		// can accept a write response.
+		input wire  S_AXI_BREADY,
+		// Read address ID. This signal is the identification
+		// tag for the read address group of signals.
+		input wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_ARID,
+		// Read address. This signal indicates the initial
+		// address of a read burst transaction.
+		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
+		// Burst length. The burst length gives the exact number of
+		// transfers in a burst
+		input wire [7 : 0] S_AXI_ARLEN,
+		// Burst size. This signal indicates the size of each transfer
+		// in the burst
+		input wire [2 : 0] S_AXI_ARSIZE,
+		// Burst type. The burst type and the size information,
+		// determine how the address for each transfer within the
+		// burst is calculated.
+		input wire [1 : 0] S_AXI_ARBURST,
+		// Lock type. Provides additional information about the
+		// atomic characteristics of the transfer.
+		input wire  S_AXI_ARLOCK,
+		// Memory type. This signal indicates how transactions
+		// are required to progress through a system.
+		input wire [3 : 0] S_AXI_ARCACHE,
+		// Protection type. This signal indicates the privilege
+		// and security level of the transaction, and whether
+		// the transaction is a data access or an instruction access.
+		input wire [2 : 0] S_AXI_ARPROT,
+		// Quality of Service, QoS identifier sent for each
+		// read transaction.
+		input wire [3 : 0] S_AXI_ARQOS,
+		// Region identifier. Permits a single physical interface
+		// on a slave to be used for multiple logical interfaces.
+		// Optional User-defined signal in the read address channel.
+		// Write address valid. This signal indicates that
+		// the channel is signaling valid read address and
+		// control information.
+		input wire  S_AXI_ARVALID,
+		// Read address ready. This signal indicates that
+		// the slave is ready to accept an address and associated
+		// control signals.
+		output wire  S_AXI_ARREADY,
+		// Read ID tag. This signal is the identification tag
+		// for the read data group of signals generated by the slave.
+		output wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_RID,
+		// Read Data
+		output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
+		// Read response. This signal indicates the status of
+		// the read transfer.
+		output wire [1 : 0] S_AXI_RRESP,
+		// Read last. This signal indicates the last transfer
+		// in a read burst.
+		output wire  S_AXI_RLAST,
+		// Optional User-defined signal in the read address channel.
+		// Read valid. This signal indicates that the channel
+		// is signaling the required read data.
+		output wire  S_AXI_RVALID,
+		// Read ready. This signal indicates that the master can
+		// accept the read data and response information.
+		input wire  S_AXI_RREADY
+	);
+
+	// Double buffer the write response channel only
+	reg	[IW-1 : 0]	r_bid;
+	reg			r_bvalid;
+	reg	[IW-1 : 0]	axi_bid;
+	reg			axi_bvalid;
+
+	reg			axi_awready, axi_wready;
+	reg	[AW-1:0]	waddr;
+	wire	[AW-1:0]	next_wr_addr;
+
+	// Vivado will warn about wlen only using 4-bits.  This is
+	// to be expected, since the axi_addr module only needs to use
+	// the bottom four bits of wlen to determine address increments
+	reg	[7:0]		wlen;
+	// Vivado will also warn about the top bit of wsize being unused.
+	// This is also to be expected for a DATA_WIDTH of 32-bits.
+	reg	[2:0]		wsize;
+	reg	[1:0]		wburst;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Skid buffer
+	//
+	wire			m_awvalid;
+	reg			m_awready;
+	wire	[AW-1:0]	m_awaddr;
+	wire	[1:0]		m_awburst;
+	wire	[2:0]		m_awsize;
+	wire	[7:0]		m_awlen;
+	wire	[IW-1:0]	m_awid;
+	//
+	skidbuffer #(.DW(AW+2+3+8+IW), .OPT_OUTREG(1'b0))
+		awbuf(S_AXI_ACLK, !S_AXI_ARESETN,
+		S_AXI_AWVALID, S_AXI_AWREADY,
+			{ S_AXI_AWADDR, S_AXI_AWBURST, S_AXI_AWSIZE,
+					S_AXI_AWLEN, S_AXI_AWID },
+		m_awvalid, m_awready,
+			{ m_awaddr, m_awburst, m_awsize, m_awlen, m_awid });
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write processing
+	//
+
+	wire	[AW-1:0]	next_rd_addr;
+	reg	[IW-1:0]	axi_rid;
+	reg	[DW-1:0]	axi_rdata;
+
+	initial	axi_awready = 1;
+	initial	axi_wready  = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+	begin
+		axi_awready  <= 1;
+		axi_wready   <= 0;
+	end else if (m_awvalid && m_awready)
+	begin
+		axi_awready <= 0;
+		axi_wready  <= 1;
+	end else if (S_AXI_WVALID && S_AXI_WREADY)
+	begin
+		axi_awready <= (S_AXI_WLAST)&&(!S_AXI_BVALID || S_AXI_BREADY);
+		axi_wready  <= (!S_AXI_WLAST);
+	end else if (!axi_awready)
+	begin
+		if (S_AXI_WREADY)
+			axi_awready <= 1'b0;
+		else if (r_bvalid && !S_AXI_BREADY)
+			axi_awready <= 1'b0;
+		else
+			axi_awready <= 1'b1;
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (m_awready)
+	begin
+		waddr    <= m_awaddr;
+		wburst   <= m_awburst;
+		wsize    <= m_awsize;
+		wlen     <= m_awlen;
+	end else if (S_AXI_WVALID)
+		waddr <= next_wr_addr;
+
+	axi_addr #(.AW(AW), .DW(DW))
+		get_next_wr_addr(waddr, wsize, wburst, wlen,
+			next_wr_addr);
+
+	always @(*)
+	begin
+		o_we = (S_AXI_WVALID && S_AXI_WREADY);
+		o_waddr = waddr[AW-1:LSB];
+		o_wdata = S_AXI_WDATA;
+		o_wstrb = S_AXI_WSTRB;
+	end
+
+	initial	r_bvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		r_bvalid <= 1'b0;
+	else if (S_AXI_WVALID && S_AXI_WREADY && S_AXI_WLAST
+			&&(S_AXI_BVALID && !S_AXI_BREADY))
+		r_bvalid <= 1'b1;
+	else if (S_AXI_BREADY)
+		r_bvalid <= 1'b0;
+
+	always @(posedge S_AXI_ACLK)
+	begin
+		if (m_awready)
+			r_bid    <= m_awid;
+
+		if (!S_AXI_BVALID || S_AXI_BREADY)
+			axi_bid <= r_bid;
+	end
+
+	initial	axi_bvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_bvalid <= 0;
+	else if (S_AXI_WVALID && S_AXI_WREADY && S_AXI_WLAST)
+		axi_bvalid <= 1;
+	else if (S_AXI_BREADY)
+		axi_bvalid <= r_bvalid;
+
+	always @(*)
+	begin
+		m_awready = axi_awready;
+		if (S_AXI_WVALID && S_AXI_WREADY && S_AXI_WLAST
+			&& (!S_AXI_BVALID || S_AXI_BREADY))
+			m_awready = 1;
+	end
+
+	// At one time, axi_awready was the same as S_AXI_AWREADY.  Now, though,
+	// with the extra write address skid buffer, this is no longer the case.
+	// S_AXI_AWREADY is handled/created/managed by the skid buffer.
+	//
+	// assign S_AXI_AWREADY = axi_awready;
+	//
+	// The rest of these signals can be set according to their registered
+	// values above.
+	assign	S_AXI_WREADY  = axi_wready;
+	assign	S_AXI_BVALID  = axi_bvalid;
+	assign	S_AXI_BID     = axi_bid;
+	//
+	// This core does not produce any bus errors, nor does it support
+	// exclusive access, so 2'b00 will always be the correct response.
+	assign	S_AXI_BRESP = 0;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read half
+	//
+	// Vivado will warn about rlen only using 4-bits.  This is
+	// to be expected, since for a DATA_WIDTH of 32-bits, the axi_addr
+	// module only uses the bottom four bits of rlen to determine
+	// address increments
+	reg	[7:0]		rlen;
+	// Vivado will also warn about the top bit of wsize being unused.
+	// This is also to be expected for a DATA_WIDTH of 32-bits.
+	reg	[2:0]		rsize;
+	reg	[1:0]		rburst;
+	reg	[IW-1:0]	rid;
+	reg			axi_arready, axi_rlast, axi_rvalid;
+	reg	[8:0]		axi_rlen;
+	reg	[AW-1:0]	raddr;
+
+	initial axi_arready = 1;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_arready <= 1;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY)
+		axi_arready <= (S_AXI_ARLEN==0)&&(o_rd);
+	else if (!S_AXI_RVALID || S_AXI_RREADY)
+	begin
+		if ((!axi_arready)&&(S_AXI_RVALID))
+			axi_arready <= (axi_rlen <= 2);
+	end
+
+	initial	axi_rlen = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_rlen <= 0;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY)
+		axi_rlen <= (S_AXI_ARLEN+1)
+				+ ((S_AXI_RVALID && !S_AXI_RREADY) ? 1:0);
+	else if (S_AXI_RREADY && S_AXI_RVALID)
+		axi_rlen <= axi_rlen - 1;
+
+	always @(posedge S_AXI_ACLK)
+	if (o_rd)
+		raddr <= next_rd_addr;
+	else if (S_AXI_ARREADY)
+		raddr <= S_AXI_ARADDR;
+
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_ARREADY)
+	begin
+		rburst   <= S_AXI_ARBURST;
+		rsize    <= S_AXI_ARSIZE;
+		rlen     <= S_AXI_ARLEN;
+		rid      <= S_AXI_ARID;
+	end
+
+	axi_addr #(.AW(AW), .DW(DW))
+		get_next_rd_addr((S_AXI_ARREADY ? S_AXI_ARADDR : raddr),
+				(S_AXI_ARREADY  ? S_AXI_ARSIZE : rsize),
+				(S_AXI_ARREADY  ? S_AXI_ARBURST: rburst),
+				(S_AXI_ARREADY  ? S_AXI_ARLEN  : rlen),
+				next_rd_addr);
+
+	always @(*)
+	begin
+		o_rd = (S_AXI_ARVALID || !S_AXI_ARREADY);
+		if (S_AXI_RVALID && !S_AXI_RREADY)
+			o_rd = 0;
+		o_raddr = (S_AXI_ARREADY ? S_AXI_ARADDR[AW-1:LSB] : raddr[AW-1:LSB]);
+	end
+
+	initial	axi_rvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		axi_rvalid <= 0;
+	else if (o_rd)
+		axi_rvalid <= 1;
+	else if (S_AXI_RREADY)
+		axi_rvalid <= 0;
+
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_RVALID || S_AXI_RREADY)
+	begin
+		if (S_AXI_ARVALID && S_AXI_ARREADY)
+			axi_rid <= S_AXI_ARID;
+		else
+			axi_rid <= rid;
+	end
+
+	initial axi_rlast   = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_RVALID || S_AXI_RREADY)
+	begin
+		if (S_AXI_ARVALID && S_AXI_ARREADY)
+			axi_rlast <= (S_AXI_ARLEN == 0);
+		else if (S_AXI_RVALID)
+			axi_rlast <= (axi_rlen == 2);
+		else
+			axi_rlast <= (axi_rlen == 1);
+	end
+
+	always @(*)
+		axi_rdata = i_rdata;
+
+	//
+	assign	S_AXI_ARREADY = axi_arready;
+	assign	S_AXI_RVALID  = axi_rvalid;
+	assign	S_AXI_RID     = axi_rid;
+	assign	S_AXI_RDATA   = axi_rdata;
+	assign	S_AXI_RRESP   = 0;
+	assign	S_AXI_RLAST   = axi_rlast;
+	//
+
+	// Make Verilator happy
+	// Verilator lint_off UNUSED
+	wire	[23:0]	unused;
+	assign	unused = { S_AXI_AWLOCK, S_AXI_AWCACHE, S_AXI_AWPROT,
+			S_AXI_AWQOS,
+		S_AXI_ARLOCK, S_AXI_ARCACHE, S_AXI_ARPROT, S_AXI_ARQOS };
+	// Verilator lint_on  UNUSED
+
+`ifdef	FORMAL
+	//
+	// The following properties are only some of the properties used
+	// to verify this core
+	//
+	reg	f_past_valid;
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+
+	always @(*)
+	if (!f_past_valid)
+		assume(!S_AXI_ARESETN);
+
+	faxi_slave	#(
+		// {{{
+		.C_AXI_ID_WIDTH(C_S_AXI_ID_WIDTH),
+		.C_AXI_DATA_WIDTH(C_S_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_S_AXI_ADDR_WIDTH))
+		// ...
+		// }}}
+	f_slave(
+		// {{{
+		.i_clk(S_AXI_ACLK),
+		.i_axi_reset_n(S_AXI_ARESETN),
+		//
+		// Address write channel
+		//
+		.i_axi_awvalid(m_awvalid),
+		.i_axi_awready(m_awready),
+		.i_axi_awid(   m_awid),
+		.i_axi_awaddr( m_awaddr),
+		.i_axi_awlen(  m_awlen),
+		.i_axi_awsize( m_awsize),
+		.i_axi_awburst(m_awburst),
+		.i_axi_awlock( 1'b0),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot( 3'h0),
+		.i_axi_awqos(  4'h0),
+	//
+	//
+		//
+		// Write Data Channel
+		//
+		// Write Data
+		.i_axi_wdata(S_AXI_WDATA),
+		.i_axi_wstrb(S_AXI_WSTRB),
+		.i_axi_wlast(S_AXI_WLAST),
+		.i_axi_wvalid(S_AXI_WVALID),
+		.i_axi_wready(S_AXI_WREADY),
+	//
+	//
+		// Response ID tag. This signal is the ID tag of the
+		// write response.
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+		.i_axi_bid(   S_AXI_BID),
+		.i_axi_bresp( S_AXI_BRESP),
+	//
+	//
+		//
+		// Read address channel
+		//
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+		.i_axi_arid(   S_AXI_ARID),
+		.i_axi_araddr( S_AXI_ARADDR),
+		.i_axi_arlen(  S_AXI_ARLEN),
+		.i_axi_arsize( S_AXI_ARSIZE),
+		.i_axi_arburst(S_AXI_ARBURST),
+		.i_axi_arlock( S_AXI_ARLOCK),
+		.i_axi_arcache(S_AXI_ARCACHE),
+		.i_axi_arprot( S_AXI_ARPROT),
+		.i_axi_arqos(  S_AXI_ARQOS),
+	//
+	//
+		//
+		// Read data return channel
+		//
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rready(S_AXI_RREADY),
+		.i_axi_rid(S_AXI_RID),
+		.i_axi_rdata(S_AXI_RDATA),
+		.i_axi_rresp(S_AXI_RRESP),
+		.i_axi_rlast(S_AXI_RLAST),
+		//
+		// ...
+		// }}}
+	);
+
+	//
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Write induction properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+
+	//
+	// ...
+	//
+
+	always @(*)
+	if (r_bvalid)
+		assert(S_AXI_BVALID);
+
+	always @(*)
+		assert(axi_awready == (!S_AXI_WREADY&& !r_bvalid));
+
+	always @(*)
+	if (axi_awready)
+		assert(!S_AXI_WREADY);
+
+
+	//
+	// ...
+	//
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Read induction properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	//
+	// ...
+	//
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $rose(S_AXI_RLAST))
+		assert(S_AXI_ARREADY);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Contract checking
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	//
+	// ...
+	//
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover properties
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	reg	f_wr_cvr_valid, f_rd_cvr_valid;
+
+	initial	f_wr_cvr_valid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_wr_cvr_valid <= 0;
+	else if (S_AXI_AWVALID && S_AXI_AWREADY && S_AXI_AWLEN > 4)
+		f_wr_cvr_valid <= 1;
+
+	always @(*)
+		cover(!S_AXI_BVALID && axi_awready && !m_awvalid
+			&& f_wr_cvr_valid /* && ... */));
+
+	initial	f_rd_cvr_valid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_rd_cvr_valid <= 0;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY && S_AXI_ARLEN > 4)
+		f_rd_cvr_valid <= 1;
+
+	always @(*)
+		cover(S_AXI_ARREADY && f_rd_cvr_valid /* && ... */);
+
+	//
+	// Generate cover statements associated with multiple successive bursts
+	//
+	// These will be useful for demonstrating the throughput of the core.
+	//
+	reg	[4:0]	f_dbl_rd_count, f_dbl_wr_count;
+
+	initial	f_dbl_wr_count = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_dbl_wr_count = 0;
+	else if (S_AXI_AWVALID && S_AXI_AWREADY && S_AXI_AWLEN == 3)
+	begin
+		if (!(&f_dbl_wr_count))
+			f_dbl_wr_count <= f_dbl_wr_count + 1;
+	end
+
+	always @(*)
+		cover(S_AXI_ARESETN && (f_dbl_wr_count > 1));	//!
+
+	always @(*)
+		cover(S_AXI_ARESETN && (f_dbl_wr_count > 3));	//!
+
+	always @(*)
+		cover(S_AXI_ARESETN && (f_dbl_wr_count > 3) && !m_awvalid
+			&&(!S_AXI_AWVALID && !S_AXI_WVALID && !S_AXI_BVALID)
+			&& (f_axi_awr_nbursts == 0)
+			&& (f_axi_wr_pending == 0));	//!!
+
+	initial	f_dbl_rd_count = 0;
+	always @(posedge S_AXI_ACLK)
+	if (!S_AXI_ARESETN)
+		f_dbl_rd_count = 0;
+	else if (S_AXI_ARVALID && S_AXI_ARREADY && S_AXI_ARLEN == 3)
+	begin
+		if (!(&f_dbl_rd_count))
+			f_dbl_rd_count <= f_dbl_rd_count + 1;
+	end
+
+	always @(*)
+		cover(!S_AXI_ARESETN && (f_dbl_rd_count > 3)
+			/* && ... */
+			&& !S_AXI_ARVALID && !S_AXI_RVALID);
+
+`ifdef	VERIFIC
+	cover property (@(posedge S_AXI_ACLK)
+		disable iff (!S_AXI_ARESETN)
+		// Accept a burst request for 4 beats
+		S_AXI_ARVALID && S_AXI_ARREADY && (S_AXI_ARLEN == 3)
+		// The first three beats
+		##1 S_AXI_RVALID && S_AXI_RREADY [*3]
+		// The last read beat, where we accept the next request
+		##1 S_AXI_ARVALID && S_AXI_ARREADY && (S_AXI_ARLEN == 3)
+			&& S_AXI_RVALID && S_AXI_RDATA && S_AXI_RLAST
+		// The next three beats of data, and
+		##1 S_AXI_RVALID && S_AXI_RREADY [*3]
+		// The final beat of the transaction
+		##1 S_AXI_RVALID && S_AXI_RDATA && S_AXI_RLAST
+		// The return to idle
+		##1 !S_AXI_RVALID && !S_AXI_ARVALID);
+`endif
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Assumptions necessary to pass a formal check
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(posedge S_AXI_ACLK)
+	if (S_AXI_RVALID && !$past(o_rd))
+		assume($stable(i_rdata));
+
+`endif
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/easyaxil.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/easyaxil.v
new file mode 100644
index 0000000..e2e6dbb
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/easyaxil.v
@@ -0,0 +1,441 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	easyaxil
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Demonstrates a simple AXI-Lite interface.
+//
+//	This was written in light of my last demonstrator, for which others
+//	declared that it was much too complicated to understand.  The goal of
+//	this demonstrator is to have logic that's easier to understand, use,
+//	and copy as needed.
+//
+//	Since there are two basic approaches to AXI-lite signaling, both with
+//	and without skidbuffers, this example demonstrates both so that the
+//	differences can be compared and contrasted.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+//
+`default_nettype none
+//
+module	easyaxil #(
+		// {{{
+		//
+		// Size of the AXI-lite bus.  These are fixed, since 1) AXI-lite
+		// is fixed at a width of 32-bits by Xilinx def'n, and 2) since
+		// we only ever have 4 configuration words.
+		parameter	C_AXI_ADDR_WIDTH = 4,
+		localparam	C_AXI_DATA_WIDTH = 32,
+		parameter [0:0]	OPT_SKIDBUFFER = 1'b0,
+		parameter [0:0]	OPT_LOWPOWER = 0,
+		localparam	ADDRLSB = $clog2(C_AXI_DATA_WIDTH)-3
+		// }}}
+	) (
+		// {{{
+		input	wire					S_AXI_ACLK,
+		input	wire					S_AXI_ARESETN,
+		//
+		input	wire					S_AXI_AWVALID,
+		output	wire					S_AXI_AWREADY,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]		S_AXI_AWADDR,
+		input	wire	[2:0]				S_AXI_AWPROT,
+		//
+		input	wire					S_AXI_WVALID,
+		output	wire					S_AXI_WREADY,
+		input	wire	[C_AXI_DATA_WIDTH-1:0]		S_AXI_WDATA,
+		input	wire	[C_AXI_DATA_WIDTH/8-1:0]	S_AXI_WSTRB,
+		//
+		output	wire					S_AXI_BVALID,
+		input	wire					S_AXI_BREADY,
+		output	wire	[1:0]				S_AXI_BRESP,
+		//
+		input	wire					S_AXI_ARVALID,
+		output	wire					S_AXI_ARREADY,
+		input	wire	[C_AXI_ADDR_WIDTH-1:0]		S_AXI_ARADDR,
+		input	wire	[2:0]				S_AXI_ARPROT,
+		//
+		output	wire					S_AXI_RVALID,
+		input	wire					S_AXI_RREADY,
+		output	wire	[C_AXI_DATA_WIDTH-1:0]		S_AXI_RDATA,
+		output	wire	[1:0]				S_AXI_RRESP
+		// }}}
+	);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Register/wire signal declarations
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	wire	i_reset = !S_AXI_ARESETN;
+
+	wire				axil_write_ready;
+	wire	[C_AXI_ADDR_WIDTH-ADDRLSB-1:0]	awskd_addr;
+	//
+	wire	[C_AXI_DATA_WIDTH-1:0]	wskd_data;
+	wire [C_AXI_DATA_WIDTH/8-1:0]	wskd_strb;
+	reg				axil_bvalid;
+	//
+	wire				axil_read_ready;
+	wire	[C_AXI_ADDR_WIDTH-ADDRLSB-1:0]	arskd_addr;
+	reg	[C_AXI_DATA_WIDTH-1:0]	axil_read_data;
+	reg				axil_read_valid;
+
+	reg	[31:0]	r0, r1, r2, r3;
+	wire	[31:0]	wskd_r0, wskd_r1, wskd_r2, wskd_r3;
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite signaling
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	//
+	// Write signaling
+	//
+	// {{{
+
+	generate if (OPT_SKIDBUFFER)
+	begin : SKIDBUFFER_WRITE
+
+		wire	awskd_valid, wskd_valid;
+
+		skidbuffer #(.OPT_OUTREG(0),
+				.OPT_LOWPOWER(OPT_LOWPOWER),
+				.DW(C_AXI_ADDR_WIDTH-ADDRLSB))
+		axilawskid(//
+			.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+			.i_valid(S_AXI_AWVALID), .o_ready(S_AXI_AWREADY),
+			.i_data(S_AXI_AWADDR[C_AXI_ADDR_WIDTH-1:ADDRLSB]),
+			.o_valid(awskd_valid), .i_ready(axil_write_ready),
+			.o_data(awskd_addr));
+
+		skidbuffer #(.OPT_OUTREG(0),
+				.OPT_LOWPOWER(OPT_LOWPOWER),
+				.DW(C_AXI_DATA_WIDTH+C_AXI_DATA_WIDTH/8))
+		axilwskid(//
+			.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+			.i_valid(S_AXI_WVALID), .o_ready(S_AXI_WREADY),
+			.i_data({ S_AXI_WDATA, S_AXI_WSTRB }),
+			.o_valid(wskd_valid), .i_ready(axil_write_ready),
+			.o_data({ wskd_data, wskd_strb }));
+
+		assign	axil_write_ready = awskd_valid && wskd_valid
+				&& (!S_AXI_BVALID || S_AXI_BREADY);
+
+	end else begin : SIMPLE_WRITES
+
+		reg	axil_awready;
+
+		initial	axil_awready = 1'b0;
+		always @(posedge S_AXI_ACLK)
+		if (!S_AXI_ARESETN)
+			axil_awready <= 1'b0;
+		else
+			axil_awready <= !axil_awready
+				&& (S_AXI_AWVALID && S_AXI_WVALID)
+				&& (!S_AXI_BVALID || S_AXI_BREADY);
+
+		assign	S_AXI_AWREADY = axil_awready;
+		assign	S_AXI_WREADY  = axil_awready;
+
+		assign 	awskd_addr = S_AXI_AWADDR[C_AXI_ADDR_WIDTH-1:ADDRLSB];
+		assign	wskd_data  = S_AXI_WDATA;
+		assign	wskd_strb  = S_AXI_WSTRB;
+
+		assign	axil_write_ready = axil_awready;
+
+	end endgenerate
+
+	initial	axil_bvalid = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		axil_bvalid <= 0;
+	else if (axil_write_ready)
+		axil_bvalid <= 1;
+	else if (S_AXI_BREADY)
+		axil_bvalid <= 0;
+
+	assign	S_AXI_BVALID = axil_bvalid;
+	assign	S_AXI_BRESP = 2'b00;
+	// }}}
+
+	//
+	// Read signaling
+	//
+	// {{{
+
+	generate if (OPT_SKIDBUFFER)
+	begin : SKIDBUFFER_READ
+
+		wire	arskd_valid;
+
+		skidbuffer #(.OPT_OUTREG(0),
+				.OPT_LOWPOWER(OPT_LOWPOWER),
+				.DW(C_AXI_ADDR_WIDTH-ADDRLSB))
+		axilarskid(//
+			.i_clk(S_AXI_ACLK), .i_reset(i_reset),
+			.i_valid(S_AXI_ARVALID), .o_ready(S_AXI_ARREADY),
+			.i_data(S_AXI_ARADDR[C_AXI_ADDR_WIDTH-1:ADDRLSB]),
+			.o_valid(arskd_valid), .i_ready(axil_read_ready),
+			.o_data(arskd_addr));
+
+		assign	axil_read_ready = arskd_valid
+				&& (!axil_read_valid || S_AXI_RREADY);
+
+	end else begin : SIMPLE_READS
+
+		reg	axil_arready;
+
+		always @(*)
+			axil_arready = !S_AXI_RVALID;
+
+		assign	arskd_addr = S_AXI_ARADDR[C_AXI_ADDR_WIDTH-1:ADDRLSB];
+		assign	S_AXI_ARREADY = axil_arready;
+		assign	axil_read_ready = (S_AXI_ARVALID && S_AXI_ARREADY);
+
+	end endgenerate
+
+	initial	axil_read_valid = 1'b0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+		axil_read_valid <= 1'b0;
+	else if (axil_read_ready)
+		axil_read_valid <= 1'b1;
+	else if (S_AXI_RREADY)
+		axil_read_valid <= 1'b0;
+
+	assign	S_AXI_RVALID = axil_read_valid;
+	assign	S_AXI_RDATA  = axil_read_data;
+	assign	S_AXI_RRESP = 2'b00;
+	// }}}
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI-lite register logic
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	// apply_wstrb(old_data, new_data, write_strobes)
+	assign	wskd_r0 = apply_wstrb(r0, wskd_data, wskd_strb);
+	assign	wskd_r1 = apply_wstrb(r1, wskd_data, wskd_strb);
+	assign	wskd_r2 = apply_wstrb(r2, wskd_data, wskd_strb);
+	assign	wskd_r3 = apply_wstrb(r3, wskd_data, wskd_strb);
+
+	initial	r0 = 0;
+	initial	r1 = 0;
+	initial	r2 = 0;
+	initial	r3 = 0;
+	always @(posedge S_AXI_ACLK)
+	if (i_reset)
+	begin
+		r0 <= 0;
+		r1 <= 0;
+		r2 <= 0;
+		r3 <= 0;
+	end else if (axil_write_ready)
+	begin
+		case(awskd_addr)
+		2'b00:	r0 <= wskd_r0;
+		2'b01:	r1 <= wskd_r1;
+		2'b10:	r2 <= wskd_r2;
+		2'b11:	r3 <= wskd_r3;
+		endcase
+	end
+
+	initial	axil_read_data = 0;
+	always @(posedge S_AXI_ACLK)
+	if (OPT_LOWPOWER && !S_AXI_ARESETN)
+		axil_read_data <= 0;
+	else if (!S_AXI_RVALID || S_AXI_RREADY)
+	begin
+		case(arskd_addr)
+		2'b00:	axil_read_data	<= r0;
+		2'b01:	axil_read_data	<= r1;
+		2'b10:	axil_read_data	<= r2;
+		2'b11:	axil_read_data	<= r3;
+		endcase
+
+		if (OPT_LOWPOWER && !axil_read_ready)
+			axil_read_data <= 0;
+	end
+
+	function [C_AXI_DATA_WIDTH-1:0]	apply_wstrb;
+		input	[C_AXI_DATA_WIDTH-1:0]		prior_data;
+		input	[C_AXI_DATA_WIDTH-1:0]		new_data;
+		input	[C_AXI_DATA_WIDTH/8-1:0]	wstrb;
+
+		integer	k;
+		for(k=0; k<C_AXI_DATA_WIDTH/8; k=k+1)
+		begin
+			apply_wstrb[k*8 +: 8]
+				= wstrb[k] ? new_data[k*8 +: 8] : prior_data[k*8 +: 8];
+		end
+	endfunction
+	// }}}
+
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, S_AXI_AWPROT, S_AXI_ARPROT,
+			S_AXI_ARADDR[ADDRLSB-1:0],
+			S_AXI_AWADDR[ADDRLSB-1:0] };
+	// Verilator lint_on  UNUSED
+	// }}}
+`ifdef	FORMAL
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Formal properties used in verfiying this core
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	reg	f_past_valid;
+	initial	f_past_valid = 0;
+	always @(posedge S_AXI_ACLK)
+		f_past_valid <= 1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The AXI-lite control interface
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+	localparam	F_AXIL_LGDEPTH = 4;
+	wire	[F_AXIL_LGDEPTH-1:0]	faxil_rd_outstanding,
+					faxil_wr_outstanding,
+					faxil_awr_outstanding;
+
+	faxil_slave #(
+		// {{{
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.F_LGDEPTH(F_AXIL_LGDEPTH),
+		.F_AXI_MAXWAIT(2),
+		.F_AXI_MAXDELAY(2),
+		.F_AXI_MAXRSTALL(3),
+		.F_OPT_COVER_BURST(4)
+		// }}}
+	) faxil(
+		// {{{
+		.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+		//
+		.i_axi_awvalid(S_AXI_AWVALID),
+		.i_axi_awready(S_AXI_AWREADY),
+		.i_axi_awaddr( S_AXI_AWADDR),
+		.i_axi_awcache(4'h0),
+		.i_axi_awprot( S_AXI_AWPROT),
+		//
+		.i_axi_wvalid(S_AXI_WVALID),
+		.i_axi_wready(S_AXI_WREADY),
+		.i_axi_wdata( S_AXI_WDATA),
+		.i_axi_wstrb( S_AXI_WSTRB),
+		//
+		.i_axi_bvalid(S_AXI_BVALID),
+		.i_axi_bready(S_AXI_BREADY),
+		.i_axi_bresp( S_AXI_BRESP),
+		//
+		.i_axi_arvalid(S_AXI_ARVALID),
+		.i_axi_arready(S_AXI_ARREADY),
+		.i_axi_araddr( S_AXI_ARADDR),
+		.i_axi_arcache(4'h0),
+		.i_axi_arprot( S_AXI_ARPROT),
+		//
+		.i_axi_rvalid(S_AXI_RVALID),
+		.i_axi_rready(S_AXI_RREADY),
+		.i_axi_rdata( S_AXI_RDATA),
+		.i_axi_rresp( S_AXI_RRESP),
+		//
+		.f_axi_rd_outstanding(faxil_rd_outstanding),
+		.f_axi_wr_outstanding(faxil_wr_outstanding),
+		.f_axi_awr_outstanding(faxil_awr_outstanding)
+		// }}}
+		);
+
+	always @(*)
+	if (OPT_SKIDBUFFER)
+	begin
+		assert(faxil_awr_outstanding== (S_AXI_BVALID ? 1:0)
+			+(S_AXI_AWREADY ? 0:1));
+		assert(faxil_wr_outstanding == (S_AXI_BVALID ? 1:0)
+			+(S_AXI_WREADY ? 0:1));
+
+		assert(faxil_rd_outstanding == (S_AXI_RVALID ? 1:0)
+			+(S_AXI_ARREADY ? 0:1));
+	end else begin
+		assert(faxil_wr_outstanding == (S_AXI_BVALID ? 1:0));
+		assert(faxil_awr_outstanding == faxil_wr_outstanding);
+
+		assert(faxil_rd_outstanding == (S_AXI_RVALID ? 1:0));
+	end
+
+	always @(posedge S_AXI_ACLK)
+	if (f_past_valid && $past(S_AXI_ARESETN
+			&& axil_read_ready))
+	begin
+		assert(S_AXI_RVALID);
+		case($past(arskd_addr))
+		0: assert(S_AXI_RDATA == $past(r0));
+		1: assert(S_AXI_RDATA == $past(r1));
+		2: assert(S_AXI_RDATA == $past(r2));
+		3: assert(S_AXI_RDATA == $past(r3));
+		endcase
+	end
+
+	//
+	// Check that our low-power only logic works by verifying that anytime
+	// S_AXI_RVALID is inactive, then the outgoing data is also zero.
+	//
+	always @(*)
+	if (OPT_LOWPOWER && !S_AXI_RVALID)
+		assert(S_AXI_RDATA == 0);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// {{{
+
+	// While there are already cover properties in the formal property
+	// set above, you'll probably still want to cover something
+	// application specific here
+
+	// }}}
+	// }}}
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/migsdram.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/migsdram.v
new file mode 100644
index 0000000..843b0ff
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/migsdram.v
@@ -0,0 +1,313 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	migsdram.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	This file isn't really a part of the synthesis implementation 
+//		of the wb2axip project itself, but rather it is an example
+//	of how the wb2axip project can be used to connect a MIG generated
+//	IP component.
+//
+//	This implementation depends upon the existence of a MIG generated
+//	core, named "mig_axis", and illustrates how such a core might be
+//	connected to the wbm2axip bridge.  Specific options of the mig_axis
+//	setup include 6 identifier bits, and a full-sized bus width of 128
+//	bits.   These two settings are both appropriate for driving a DDR3
+//	memory (whose minimum transfer size is 128 bits), but may need to be
+//	adjusted to support other memories.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2015-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module	migsdram(i_clk, i_clk_200mhz, o_sys_clk, i_rst, o_sys_reset,
+	// Wishbone components
+		i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel,
+		o_wb_ack, o_wb_stall, o_wb_data, o_wb_err,
+	// SDRAM connections
+		o_ddr_ck_p, o_ddr_ck_n,
+		o_ddr_reset_n, o_ddr_cke,
+		o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
+		o_ddr_ba, o_ddr_addr, 
+		o_ddr_odt, o_ddr_dm,
+		io_ddr_dqs_p, io_ddr_dqs_n,
+		io_ddr_data
+	);
+	parameter	DDRWIDTH = 16, WBDATAWIDTH=32;
+	parameter	AXIDWIDTH = 6;
+	// The SDRAM address bits (RAMABITS) are a touch more difficult to work
+	// out.  Here we leave them as a fixed parameter, but there are 
+	// consequences to this.  Specifically, the wishbone data width, the
+	// wishbone address width, and this number have interactions not
+	// well captured here.
+	parameter	RAMABITS = 28;
+	// All DDR3 memories have 8 timeslots.  This, if the DDR3 memory
+	// has 16 bits to it (as above), the entire transaction must take
+	// AXIWIDTH bits ...
+	localparam	AXIWIDTH= DDRWIDTH *8;
+	localparam	DW=WBDATAWIDTH;
+	localparam	AW=(WBDATAWIDTH==32)? RAMABITS-2
+				:((WBDATAWIDTH==64) ? RAMABITS-3
+				:((WBDATAWIDTH==128) ? RAMABITS-4
+				: RAMABITS-5)); // (WBDATAWIDTH==256)
+	localparam	SELW= (WBDATAWIDTH/8);
+	//
+	input	wire		i_clk, i_clk_200mhz, i_rst;
+	output	wire		o_sys_clk;
+	output	reg		o_sys_reset;
+	//
+	input	wire		i_wb_cyc, i_wb_stb, i_wb_we;
+	input	wire	[(AW-1):0]	i_wb_addr;
+	input	wire	[(DW-1):0]	i_wb_data;
+	input	wire	[(SELW-1):0]	i_wb_sel;
+	output	wire			o_wb_ack, o_wb_stall;
+	output	wire	[(DW-1):0]	o_wb_data;
+	output	wire			o_wb_err;
+	//
+	output	wire	[0:0]		o_ddr_ck_p, o_ddr_ck_n;
+	output	wire	[0:0]		o_ddr_cke;
+	output	wire			o_ddr_reset_n,
+					o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n;
+	output	wire	[0:0]			o_ddr_cs_n;
+	output	wire	[2:0]			o_ddr_ba;
+	output	wire	[13:0]			o_ddr_addr;
+	output	wire	[0:0]			o_ddr_odt;
+	output	wire	[(DDRWIDTH/8-1):0]	o_ddr_dm;
+	inout	wire	[1:0]			io_ddr_dqs_p, io_ddr_dqs_n;
+	inout	wire	[(DDRWIDTH-1):0]	io_ddr_data;
+
+
+`define	SDRAM_ACCESS
+`ifdef	SDRAM_ACCESS
+
+	wire	aresetn;
+	assign	aresetn = 1'b1; // Never reset
+
+	// Write address channel
+	wire	[(AXIDWIDTH-1):0]	s_axi_awid;
+	wire	[(RAMABITS-1):0]	s_axi_awaddr;
+	wire	[7:0]			s_axi_awlen;
+	wire	[2:0]			s_axi_awsize;
+	wire	[1:0]			s_axi_awburst;
+	wire	[0:0]			s_axi_awlock;
+	wire	[3:0]			s_axi_awcache;
+	wire	[2:0]			s_axi_awprot;
+	wire	[3:0]			s_axi_awqos;
+	wire				s_axi_awvalid;
+	wire				s_axi_awready;
+	// Writei data channel
+	wire	[(AXIWIDTH-1):0]	s_axi_wdata;
+	wire	[(AXIWIDTH/8-1):0]	s_axi_wstrb;
+	wire				s_axi_wlast, s_axi_wvalid, s_axi_wready;
+	// Write response channel
+	wire				s_axi_bready;
+	wire	[(AXIDWIDTH-1):0]	s_axi_bid;
+	wire	[1:0]			s_axi_bresp;
+	wire				s_axi_bvalid;
+
+	// Read address channel
+	wire	[(AXIDWIDTH-1):0]	s_axi_arid;
+	wire	[(RAMABITS-1):0]	s_axi_araddr;
+	wire	[7:0]			s_axi_arlen;
+	wire	[2:0]			s_axi_arsize;
+	wire	[1:0]			s_axi_arburst;
+	wire	[0:0]			s_axi_arlock;
+	wire	[3:0]			s_axi_arcache;
+	wire	[2:0]			s_axi_arprot;
+	wire	[3:0]			s_axi_arqos;
+	wire				s_axi_arvalid;
+	wire				s_axi_arready;
+	// Read response/data channel
+	wire	[(AXIDWIDTH-1):0]	s_axi_rid;
+	wire	[(AXIWIDTH-1):0]	s_axi_rdata;
+	wire	[1:0]			s_axi_rresp;
+	wire				s_axi_rlast;
+	wire				s_axi_rvalid;
+	wire				s_axi_rready;
+
+	// Other wires ...
+	wire		init_calib_complete, mmcm_locked;
+	wire		app_sr_active, app_ref_ack, app_zq_ack;
+	wire		app_sr_req, app_ref_req, app_zq_req;
+	wire		w_sys_reset;
+	wire	[11:0]	w_device_temp;
+
+
+	mig_axis	mig_sdram(
+		.ddr3_ck_p(o_ddr_ck_p),		.ddr3_ck_n(o_ddr_ck_n),
+		.ddr3_reset_n(o_ddr_reset_n),	.ddr3_cke(o_ddr_cke),
+		.ddr3_cs_n(o_ddr_cs_n),		.ddr3_ras_n(o_ddr_ras_n),
+		.ddr3_we_n(o_ddr_we_n),		.ddr3_cas_n(o_ddr_cas_n),
+		.ddr3_ba(o_ddr_ba),		.ddr3_addr(o_ddr_addr),
+		.ddr3_odt(o_ddr_odt),
+		.ddr3_dqs_p(io_ddr_dqs_p),	.ddr3_dqs_n(io_ddr_dqs_n),
+		.ddr3_dq(io_ddr_data),		.ddr3_dm(o_ddr_dm),
+		//
+		.sys_clk_i(i_clk),
+		.clk_ref_i(i_clk_200mhz),
+		.ui_clk(o_sys_clk),
+		.ui_clk_sync_rst(w_sys_reset),
+		.mmcm_locked(mmcm_locked),
+		.aresetn(aresetn),
+		.app_sr_req(1'b0),
+		.app_ref_req(1'b0),
+		.app_zq_req(1'b0),
+		.app_sr_active(app_sr_active),
+		.app_ref_ack(app_ref_ack),
+		.app_zq_ack(app_zq_ack),
+		//
+		.s_axi_awid(s_axi_awid),	.s_axi_awaddr(s_axi_awaddr),
+		.s_axi_awlen(s_axi_awlen),	.s_axi_awsize(s_axi_awsize),
+		.s_axi_awburst(s_axi_awburst),	.s_axi_awlock(s_axi_awlock),
+		.s_axi_awcache(s_axi_awcache),	.s_axi_awprot(s_axi_awprot),
+		.s_axi_awqos(s_axi_awqos),	.s_axi_awvalid(s_axi_awvalid),
+		.s_axi_awready(s_axi_awready),
+		//
+		.s_axi_wready(	s_axi_wready),
+		.s_axi_wdata(	s_axi_wdata),
+		.s_axi_wstrb(	s_axi_wstrb),
+		.s_axi_wlast(	s_axi_wlast),
+		.s_axi_wvalid(	s_axi_wvalid),
+		//
+		.s_axi_bready(s_axi_bready),	.s_axi_bid(s_axi_bid),
+		.s_axi_bresp(s_axi_bresp),	.s_axi_bvalid(s_axi_bvalid),
+		//
+		.s_axi_arid(s_axi_arid),	.s_axi_araddr(s_axi_araddr),
+		.s_axi_arlen(s_axi_arlen),	.s_axi_arsize(s_axi_arsize),
+		.s_axi_arburst(s_axi_arburst),	.s_axi_arlock(s_axi_arlock),
+		.s_axi_arcache(s_axi_arcache),	.s_axi_arprot(s_axi_arprot),
+		.s_axi_arqos(s_axi_arqos),	.s_axi_arvalid(s_axi_arvalid),
+		.s_axi_arready(s_axi_arready),
+		// 
+		.s_axi_rready(s_axi_rready),	.s_axi_rid(s_axi_rid),
+		.s_axi_rdata(s_axi_rdata),	.s_axi_rresp(s_axi_rresp),
+		.s_axi_rlast(s_axi_rlast),	.s_axi_rvalid(s_axi_rvalid),
+		.init_calib_complete(init_calib_complete),
+		.sys_rst(i_rst),
+		.device_temp(w_device_temp)
+		);
+
+	wbm2axisp	#( 
+			.C_AXI_ID_WIDTH(AXIDWIDTH),
+			.C_AXI_DATA_WIDTH(AXIWIDTH),
+			.C_AXI_ADDR_WIDTH(RAMABITS),
+			.AW(AW), .DW(DW)
+			)
+			bus_translator(
+				.i_clk(o_sys_clk),
+				// .i_reset(i_rst), // internally unused
+				// Write address channel signals
+				.o_axi_awvalid(	s_axi_awvalid), 
+				.i_axi_awready(	s_axi_awready), 
+				.o_axi_awid(	s_axi_awid), 
+				.o_axi_awaddr(	s_axi_awaddr), 
+				.o_axi_awlen(	s_axi_awlen), 
+				.o_axi_awsize(	s_axi_awsize), 
+				.o_axi_awburst(	s_axi_awburst), 
+				.o_axi_awlock(	s_axi_awlock), 
+				.o_axi_awcache(	s_axi_awcache), 
+				.o_axi_awprot(	s_axi_awprot),  // s_axi_awqos
+				.o_axi_awqos(	s_axi_awqos),  // s_axi_awqos
+			//
+				.o_axi_wvalid(	s_axi_wvalid),
+				.i_axi_wready(	s_axi_wready),
+				.o_axi_wdata(	s_axi_wdata),
+				.o_axi_wstrb(	s_axi_wstrb),
+				.o_axi_wlast(	s_axi_wlast),
+			//
+				.i_axi_bvalid(	s_axi_bvalid),
+				.o_axi_bready(	s_axi_bready),
+				.i_axi_bid(	s_axi_bid),
+				.i_axi_bresp(	s_axi_bresp),
+			//
+				.o_axi_arvalid(	s_axi_arvalid),
+				.i_axi_arready(	s_axi_arready),
+				.o_axi_arid(	s_axi_arid),
+				.o_axi_araddr(	s_axi_araddr),
+				.o_axi_arlen(	s_axi_arlen),
+				.o_axi_arsize(	s_axi_arsize),
+				.o_axi_arburst(	s_axi_arburst),
+				.o_axi_arlock(	s_axi_arlock),
+				.o_axi_arcache(	s_axi_arcache),
+				.o_axi_arprot(	s_axi_arprot),
+				.o_axi_arqos(	s_axi_arqos),
+			//
+				.i_axi_rvalid(	s_axi_rvalid),
+				.o_axi_rready(	s_axi_rready),
+				.i_axi_rid(	s_axi_rid),
+				.i_axi_rdata(	s_axi_rdata),
+				.i_axi_rresp(	s_axi_rresp),
+				.i_axi_rlast(	s_axi_rlast),
+			//
+				.i_wb_cyc(	i_wb_cyc),
+				.i_wb_stb(	i_wb_stb),
+				.i_wb_we(	i_wb_we),
+				.i_wb_addr(	i_wb_addr),
+				.i_wb_data(	i_wb_data),
+				.i_wb_sel(	i_wb_sel),
+			//
+				.o_wb_stall(	o_wb_stall),
+				.o_wb_ack(	o_wb_ack),
+				.o_wb_data(	o_wb_data),
+				.o_wb_err(	o_wb_err)
+		);
+
+	// Convert from active low to active high, *and* hold the system in
+	// reset until the memory comes up.	
+	initial	o_sys_reset = 1'b1;
+	always @(posedge o_sys_clk)
+		o_sys_reset <= (!w_sys_reset)
+				||(!init_calib_complete)
+				||(!mmcm_locked);
+`else
+	BUFG	sysclk(i_clk, o_sys_clk);
+	initial	o_sys_reset <= 1'b1;
+	always @(posedge i_clk)
+		o_sys_reset <= 1'b1;
+
+	OBUFDS ckobuf(.I(i_clk), .O(o_ddr_ck_p), .OB(o_ddr_ck_n));
+
+	assign	o_ddr_reset_n	= 1'b0;
+	assign	o_ddr_cke[0]	= 1'b0;
+	assign	o_ddr_cs_n[0]	= 1'b1;
+	assign	o_ddr_cas_n	= 1'b1;
+	assign	o_ddr_ras_n	= 1'b1;
+	assign	o_ddr_we_n	= 1'b1;
+	assign	o_ddr_ba	= 3'h0;
+	assign	o_ddr_addr	= 14'h00;
+	assign	o_ddr_dm	= 2'b00;
+	assign	io_ddr_data	= 16'h0;
+
+	OBUFDS	dqsbufa(.I(i_clk), .O(io_ddr_dqs_p[1]), .OB(io_ddr_dqs_n[1]));
+	OBUFDS	dqsbufb(.I(i_clk), .O(io_ddr_dqs_p[0]), .OB(io_ddr_dqs_n[0]));
+
+`endif
+
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/sfifo.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/sfifo.v
new file mode 100644
index 0000000..a7954c7
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/sfifo.v
@@ -0,0 +1,434 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	sfifo.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	A synchronous data FIFO.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Written and distributed by Gisselquist Technology, LLC
+// }}}
+// This program is hereby granted to the public domain.
+// {{{
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// }}}
+module sfifo #(
+		// {{{
+		parameter	BW=8,	// Byte/data width
+		parameter 	LGFLEN=4,
+		parameter [0:0]	OPT_ASYNC_READ = 1'b1,
+		parameter [0:0]	OPT_WRITE_ON_FULL = 1'b0,
+		parameter [0:0]	OPT_READ_ON_EMPTY = 1'b0,
+		localparam	FLEN=(1<<LGFLEN)
+		// }}}
+	) (
+		// {{{
+		input	wire		i_clk,
+		input	wire		i_reset,
+		//
+		// Write interface
+		input	wire		i_wr,
+		input	wire [(BW-1):0]	i_data,
+		output	reg 		o_full,
+		output	reg [LGFLEN:0]	o_fill,
+		//
+		// Read interface
+		input	wire		i_rd,
+		output	reg [(BW-1):0]	o_data,
+		output	reg		o_empty	// True if FIFO is empty
+		// }}}
+	);
+
+	// Register/net declarations
+	// {{{
+	reg			r_full, r_empty;
+	reg	[(BW-1):0]	mem[0:(FLEN-1)];
+	reg	[LGFLEN:0]	wr_addr, rd_addr;
+	reg	[LGFLEN-1:0]	rd_next;
+
+	wire	w_wr = (i_wr && !o_full);
+	wire	w_rd = (i_rd && !o_empty);
+	// }}}
+
+	// o_fill
+	// {{{
+	initial	o_fill = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		o_fill <= 0;
+	else case({ w_wr, w_rd })
+	2'b01: o_fill <= o_fill - 1;
+	2'b10: o_fill <= o_fill + 1;
+	default: o_fill <= wr_addr - rd_addr;
+	endcase
+	// }}}
+
+	// r_full, o_full
+	// {{{
+	initial	r_full = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		r_full <= 0;
+	else case({ w_wr, w_rd})
+	2'b01: r_full <= 1'b0;
+	2'b10: r_full <= (o_fill == { 1'b0, {(LGFLEN){1'b1}} });
+	default: r_full <= (o_fill == { 1'b1, {(LGFLEN){1'b0}} });
+	endcase
+
+	always @(*)
+	if (OPT_WRITE_ON_FULL && i_rd)
+		o_full = 1'b0;
+	else
+		o_full = r_full;
+	// }}}
+		
+	// wr_addr, the write address pointer
+	// {{{
+	initial	wr_addr = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		wr_addr <= 0;
+	else if (w_wr)
+		wr_addr <= wr_addr + 1'b1;
+	// }}}
+
+	// Write to memory
+	// {{{
+	always @(posedge i_clk)
+	if (w_wr)
+		mem[wr_addr[(LGFLEN-1):0]] <= i_data;
+	// }}}
+
+	// rd_addr, the read address pointer
+	// {{{
+	initial	rd_addr = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		rd_addr <= 0;
+	else if (w_rd)
+		rd_addr <= rd_addr + 1;
+	// }}}
+
+	always @(*)
+		rd_next = rd_addr[LGFLEN-1:0] + 1;
+
+	// r_empty, o_empty
+	// {{{
+	initial	r_empty = 1'b1;
+	always @(posedge i_clk)
+	if (i_reset)
+		r_empty <= 1'b1;
+	else case ({ w_wr, w_rd })
+	2'b01: r_empty <= (o_fill <= 1);
+	2'b10: r_empty <= 1'b0;
+	default: begin end
+	endcase
+
+	always @(*)
+	if (OPT_READ_ON_EMPTY && i_wr)
+		o_empty = 1'b0;
+	else
+		o_empty = r_empty;
+	// }}}
+
+	// Read from the FIFO
+	// {{{
+	generate if (OPT_ASYNC_READ && OPT_READ_ON_EMPTY)
+	begin : ASYNCHRONOUS_READ_ON_EMPTY
+		// o_data
+		// {{{
+		always @(*)
+		begin
+			o_data = mem[rd_addr[LGFLEN-1:0]];
+			if (r_empty)
+				o_data = i_data;
+		end
+		// }}}
+	end else if (OPT_ASYNC_READ)
+	begin : ASYNCHRONOUS_READ
+		// o_data
+		// {{{
+		always @(*)
+			o_data = mem[rd_addr[LGFLEN-1:0]];
+		// }}}
+	end else begin : REGISTERED_READ
+		// {{{
+		reg		bypass_valid;
+		reg [BW-1:0]	bypass_data, rd_data;
+
+		// Memory read, bypassing it if we must
+		// {{{
+		initial bypass_valid = 0;
+		always @(posedge i_clk)
+		if (i_reset)
+			bypass_valid <= 0;
+		else begin
+			bypass_valid <= 1'b0;
+			if (!i_wr)
+				bypass_valid <= 1'b0;
+			else if (r_empty || (i_rd && (o_fill == 1)))
+				bypass_valid <= 1'b1;
+		end
+
+		always @(posedge i_clk)
+			bypass_data <= i_data;
+
+		initial mem[0] = 0;
+		initial rd_data = 0;
+		always @(posedge i_clk)
+			rd_data <= mem[(w_rd)?rd_next : rd_addr[LGFLEN-1:0]];
+
+		always @(*)
+		if (OPT_READ_ON_EMPTY && r_empty)
+			o_data = i_data;
+		else if (bypass_valid)
+			o_data = bypass_data;
+		else
+			o_data = rd_data;
+		// }}}
+		// }}}
+	end endgenerate
+	// }}}
+
+	// Make Verilator happy
+	// verilator lint_off UNUSED
+	wire	[LGFLEN-1:0]	unused;
+	assign	unused = rd_next;
+	// verilator lint_on  UNUSED
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// FORMAL METHODS
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+`ifdef	FORMAL
+
+//
+// Assumptions about our input(s)
+//
+//
+`ifdef	SFIFO
+`define	ASSUME	assume
+`else
+`define	ASSUME	assert
+`endif
+
+	reg			f_past_valid;
+	wire	[LGFLEN:0]	f_fill, f_next, f_empty;
+
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Assertions about our flags and counters
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	assign	f_fill = wr_addr - rd_addr;
+	assign	f_empty = (wr_addr == rd_addr);
+	assign	f_next = rd_addr + 1'b1;
+
+	always @(*)
+	begin
+		assert(f_fill <= { 1'b1, {(LGFLEN){1'b0}} });
+		assert(o_fill == f_fill);
+
+		assert(r_full  == (f_fill == {1'b1, {(LGFLEN){1'b0}} }));
+		assert(r_empty == (f_fill == 0));
+		assert(rd_next == f_next[LGFLEN-1:0]);
+
+		if (!OPT_WRITE_ON_FULL)
+			assert(o_full == r_full);
+		else
+			assert(o_full == (r_full && !i_rd));
+
+		if (!OPT_READ_ON_EMPTY)
+			assert(o_empty == r_empty);
+		else
+			assert(o_empty == (r_empty && !i_wr));
+	end
+
+	always @(posedge i_clk)
+	if (!OPT_ASYNC_READ && f_past_valid)
+	begin
+		if (f_fill == 0)
+		begin
+			assert(r_empty);
+			assert(o_empty || (OPT_READ_ON_EMPTY && i_wr));
+		end else if ($past(f_fill)>1)
+			assert(!r_empty);
+		else if ($past(!i_rd && f_fill > 0))
+			assert(!r_empty);
+	end
+
+	always @(*)
+	if (!r_empty)
+		// This also applies for the registered read case
+		assert(mem[rd_addr] == o_data);
+	else if (OPT_READ_ON_EMPTY)
+		assert(o_data == i_data);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Formal contract: (Twin write test)
+	// {{{
+	// If you write two values in succession, you should be able to read
+	// those same two values in succession some time later.
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	(* anyconst *)	reg	[LGFLEN:0]	f_first_addr;
+			reg	[LGFLEN:0]	f_second_addr;
+			reg	[BW-1:0]	f_first_data, f_second_data;
+
+	reg	f_first_addr_in_fifo,  f_first_in_fifo;
+	reg	f_second_addr_in_fifo, f_second_in_fifo;
+	reg	[LGFLEN:0]	f_distance_to_first, f_distance_to_second;
+
+	always @(*)
+		f_second_addr = f_first_addr + 1;
+
+	always @(*)
+	begin
+		f_distance_to_first = (f_first_addr - rd_addr);
+		f_first_addr_in_fifo = 0;
+		if ((f_fill != 0) && (f_distance_to_first < f_fill))
+			f_first_addr_in_fifo = 1;
+	end
+
+	always @(*)
+	begin
+		f_distance_to_second = (f_second_addr - rd_addr);
+		f_second_addr_in_fifo = 0;
+		if ((f_fill != 0) && (f_distance_to_second < f_fill))
+			f_second_addr_in_fifo = 1;
+	end
+
+	always @(posedge i_clk)
+	if (w_wr && wr_addr == f_first_addr)
+		f_first_data <= i_data;
+
+	always @(posedge i_clk)
+	if (w_wr && wr_addr == f_second_addr)
+		f_second_data <= i_data;
+
+	always @(*)
+	if (f_first_addr_in_fifo)
+		assert(mem[f_first_addr] == f_first_data);
+	always @(*)
+		f_first_in_fifo = (f_first_addr_in_fifo && (mem[f_first_addr] == f_first_data));
+
+	always @(*)
+	if (f_second_addr_in_fifo)
+		assert(mem[f_second_addr] == f_second_data);
+
+	always @(*)
+		f_second_in_fifo = (f_second_addr_in_fifo && (mem[f_second_addr] == f_second_data));
+
+	always @(posedge i_clk)
+	if (f_past_valid && !$past(i_reset))
+	begin
+		case({$past(f_first_in_fifo), $past(f_second_in_fifo)})
+		2'b00: begin
+				if ($past(w_wr && (!w_rd || !r_empty))
+					&&($past(wr_addr == f_first_addr)))
+					assert(f_first_in_fifo);
+				else
+					assert(!f_first_in_fifo);
+				//
+				// The second could be in the FIFO, since
+				// one might write other data than f_first_data
+				//
+				// assert(!f_second_in_fifo);
+			end
+		2'b01: begin
+				assert(!f_first_in_fifo);
+				if ($past(w_rd && (rd_addr==f_second_addr)))
+					assert((o_empty&&!OPT_ASYNC_READ)||!f_second_in_fifo);
+				else
+					assert(f_second_in_fifo);
+			end
+		2'b10: begin
+				if ($past(w_wr)
+					&&($past(wr_addr == f_second_addr)))
+					assert(f_second_in_fifo);
+				else
+					assert(!f_second_in_fifo);
+				if ($past(!w_rd ||(rd_addr != f_first_addr)))
+					assert(f_first_in_fifo);
+			end
+		2'b11: begin
+				assert(f_second_in_fifo);
+				if ($past(!w_rd ||(rd_addr != f_first_addr)))
+				begin
+					assert(f_first_in_fifo);
+					if (rd_addr == f_first_addr)
+						assert(o_data == f_first_data);
+				end else begin
+					assert(!f_first_in_fifo);
+					assert(o_data == f_second_data);
+				end
+			end
+		endcase
+	end
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	//	Cover properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	f_was_full;
+	initial	f_was_full = 0;
+	always @(posedge i_clk)
+	if (o_full)
+		f_was_full <= 1;
+
+`ifdef	SFIFO
+	always @(posedge i_clk)
+		cover($fell(f_empty));
+
+	always @(posedge i_clk)
+		cover($fell(o_empty));
+
+	always @(posedge i_clk)
+		cover(f_was_full && f_empty);
+
+	always @(posedge i_clk)
+		cover($past(o_full,2)&&(!$past(o_full))&&(o_full));
+
+	always @(posedge i_clk)
+	if (f_past_valid)
+		cover($past(o_empty,2)&&(!$past(o_empty))&& o_empty);
+`endif
+	// }}}
+`endif // FORMAL
+// }}}
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/sfifothresh.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/sfifothresh.v
new file mode 100644
index 0000000..7a010cf
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/sfifothresh.v
@@ -0,0 +1,97 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	sfifothresh.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	A synchronous data FIFO, generated from sfifo.v.  This
+//		particular version extends the FIFO interface with a threshold
+//	calculator, to create an interrupt/signal when the FIFO has greater
+//	than the threshold elements within it.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module sfifothresh(i_clk, i_reset,
+		i_wr, i_data, o_full, o_fill,
+		i_rd, o_data, o_empty,
+		i_threshold, o_int);
+	parameter	BW=8;	// Byte/data width
+	parameter 	LGFLEN=4;
+	parameter [0:0]	OPT_ASYNC_READ = 1'b1;
+	localparam	FLEN=(1<<LGFLEN);
+
+	//
+	//
+	input	wire		i_clk;
+	input	wire		i_reset;
+	//
+	// Write interface
+	input	wire		i_wr;
+	input	wire [(BW-1):0]	i_data;
+	output	wire 		o_full;
+	output	wire [LGFLEN:0]	o_fill;
+	//
+	// Read interface
+	input	wire		i_rd;
+	output	wire [(BW-1):0]	o_data;
+	output	wire		o_empty;	// True if FIFO is empty
+	// 
+	input	wire [LGFLEN:0]	i_threshold;
+	output	reg		o_int;
+
+	wire	w_wr = (i_wr && !o_full);
+	wire	w_rd = (i_rd && !o_empty);
+
+	sfifo #(.BW(BW), .LGFLEN(LGFLEN), .OPT_ASYNC_READ(OPT_ASYNC_READ))
+	sfifoi(i_clk, i_reset, i_wr, i_data, o_full, o_fill, i_rd,
+		o_data, o_empty);
+
+	initial	o_int = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		o_int <= 0;
+	else case({ w_wr, w_rd })
+	2'b01: o_int <= (o_fill-1 >= i_threshold);
+	2'b10: o_int <= (o_fill+1 >= i_threshold);
+	default: o_int <= o_fill >= i_threshold;
+	endcase
+
+`ifdef	FORMAL
+	reg	f_past_valid;
+
+	initial	f_past_valid = 0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+
+	always @(posedge i_clk)
+	if (!f_past_valid || $past(i_reset))
+		assert(!o_int);
+	else
+		assert(o_int == (o_fill >= $past(i_threshold)));
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/skidbuffer.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/skidbuffer.v
new file mode 100644
index 0000000..d3c03d1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/skidbuffer.v
@@ -0,0 +1,341 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	skidbuffer.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	A basic SKID buffer.
+//
+//	Skid buffers are required for high throughput AXI code, since the AXI
+//	specification requires that all outputs be registered.  This means
+//	that, if there are any stall conditions calculated, it will take a clock
+//	cycle before the stall can be propagated up stream.  This means that
+//	the data will need to be buffered for a cycle until the stall signal
+//	can make it to the output.
+//
+//	Handling that buffer is the purpose of this core.
+//
+//	On one end of this core, you have the i_valid and i_data inputs to
+//	connect to your bus interface.  There's also a registered o_ready
+//	signal to signal stalls for the bus interface.
+//
+//	The other end of the core has the same basic interface, but it isn't
+//	registered.  This allows you to interact with the bus interfaces
+//	as though they were combinatorial logic, by interacting with this half
+//	of the core.
+//
+//	If at any time the incoming !stall signal, i_ready, signals a stall,
+//	the incoming data is placed into a buffer.  Internally, that buffer
+//	is held in r_data with the r_valid flag used to indicate that valid
+//	data is within it.
+//
+// Parameters:
+//	DW or data width
+//		In order to make this core generic, the width of the data in the
+//		skid buffer is parameterized
+//
+//	OPT_LOWPOWER
+//		Forces both o_data and r_data to zero if the respective *VALID
+//		signal is also low.  While this costs extra logic, it can also
+//		be used to guarantee that any unused values aren't toggling and
+//		therefore unnecessarily using power.
+//
+//		This excess toggling can be particularly problematic if the
+//		bus signals have a high fanout rate, or a long signal path
+//		across an FPGA.
+//
+//	OPT_OUTREG
+//		Causes the outputs to be registered
+//
+//	OPT_PASSTHROUGH
+//		Turns the skid buffer into a passthrough.  Used for formal
+//		verification only.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+// }}}
+module skidbuffer #(
+		// {{{
+		parameter	[0:0]	OPT_LOWPOWER = 0,
+		parameter	[0:0]	OPT_OUTREG = 1,
+		//
+		parameter	[0:0]	OPT_PASSTHROUGH = 0,
+		parameter		DW = 8
+		// }}}
+	) (
+		// {{{
+		input	wire			i_clk, i_reset,
+		input	wire			i_valid,
+		output	reg			o_ready,
+		input	wire	[DW-1:0]	i_data,
+		output	reg			o_valid,
+		input	wire			i_ready,
+		output	reg	[DW-1:0]	o_data
+		// }}}
+	);
+
+	reg	[DW-1:0]	r_data;
+
+	generate if (OPT_PASSTHROUGH)
+	begin : PASSTHROUGH
+		// {{{
+		always @(*)
+			o_ready = i_ready;
+		always @(*)
+			o_valid = i_valid;
+		always @(*)
+		if (!i_valid && OPT_LOWPOWER)
+			o_data = 0;
+		else
+			o_data = i_data;
+
+		always @(*)
+			r_data = 0;
+		// }}}
+	end else begin : LOGIC
+		// We'll start with skid buffer itself
+		// {{{
+		reg			r_valid;
+
+		// r_valid
+		// {{{
+		initial	r_valid = 0;
+		always @(posedge i_clk)
+		if (i_reset)
+			r_valid <= 0;
+		else if ((i_valid && o_ready) && (o_valid && !i_ready))
+			// We have incoming data, but the output is stalled
+			r_valid <= 1;
+		else if (i_ready)
+			r_valid <= 0;
+		// }}}
+
+		// r_data
+		// {{{
+		initial	r_data = 0;
+		always @(posedge i_clk)
+		if (OPT_LOWPOWER && i_reset)
+			r_data <= 0;
+		else if (OPT_LOWPOWER && (!o_valid || i_ready))
+			r_data <= 0;
+		else if ((!OPT_LOWPOWER || !OPT_OUTREG || i_valid) && o_ready)
+			r_data <= i_data;
+		// }}}
+
+		// o_ready
+		// {{{
+		always @(*)
+			o_ready = !r_valid;
+		// }}}
+
+		//
+		// And then move on to the output port
+		//
+		if (!OPT_OUTREG)
+		begin : NET_OUTPUT
+			// Outputs are combinatorially determined from inputs
+			// {{{
+			// o_valid
+			// {{{
+			always @(*)
+				o_valid = !i_reset && (i_valid || r_valid);
+			// }}}
+
+			// o_data
+			// {{{
+			always @(*)
+			if (r_valid)
+				o_data = r_data;
+			else if (!OPT_LOWPOWER || i_valid)
+				o_data = i_data;
+			else
+				o_data = 0;
+			// }}}
+			// }}}
+		end else begin : REG_OUTPUT
+			// Register our outputs
+			// {{{
+			// o_valid
+			// {{{
+			initial	o_valid = 0;
+			always @(posedge i_clk)
+			if (i_reset)
+				o_valid <= 0;
+			else if (!o_valid || i_ready)
+				o_valid <= (i_valid || r_valid);
+			// }}}
+
+			// o_data
+			// {{{
+			initial	o_data = 0;
+			always @(posedge i_clk)
+			if (OPT_LOWPOWER && i_reset)
+				o_data <= 0;
+			else if (!o_valid || i_ready)
+			begin
+
+				if (r_valid)
+					o_data <= r_data;
+				else if (!OPT_LOWPOWER || i_valid)
+					o_data <= i_data;
+				else
+					o_data <= 0;
+			end
+			// }}}
+
+			// }}}
+		end
+		// }}}
+	end endgenerate
+
+`ifdef	FORMAL
+`ifdef	VERIFIC
+`define	FORMAL_VERIFIC
+`endif
+`endif
+//
+`ifdef	FORMAL_VERIFIC
+	// Reset properties
+	property RESET_CLEARS_IVALID;
+		@(posedge i_clk) i_reset |=> !i_valid;
+	endproperty
+
+	property IDATA_HELD_WHEN_NOT_READY;
+		@(posedge i_clk) disable iff (i_reset)
+		i_valid && !o_ready |=> i_valid && $stable(i_data);
+	endproperty
+
+`ifdef	SKIDBUFFER
+	assume	property (IDATA_HELD_WHEN_NOT_READY);
+`else
+	assert	property (IDATA_HELD_WHEN_NOT_READY);
+`endif
+
+	generate if (!OPT_PASSTHROUGH)
+	begin
+
+		assert property (@(posedge i_clk)
+			OPT_OUTREG && i_reset |=> o_ready && !o_valid);
+
+		assert property (@(posedge i_clk)
+			!OPT_OUTREG && i_reset |-> !o_valid);
+
+		// Rule #1:
+		//	Once o_valid goes high, the data cannot change until the
+		//	clock after i_ready
+		assert property (@(posedge i_clk)
+			disable iff (i_reset)
+			o_valid && !i_ready
+			|=> (o_valid && $stable(o_data)));
+
+		// Rule #2:
+		//	All incoming data must either go directly to the
+		//	output port, or into the skid buffer
+		assert property (@(posedge i_clk)
+			disable iff (i_reset)
+			(i_valid && o_ready
+				&& (!OPT_OUTREG || o_valid) && !i_ready)
+				|=> (!o_ready && r_data == $past(i_data)));
+
+		// Rule #3:
+		//	After the last transaction, o_valid should become idle
+		if (!OPT_OUTREG)
+		begin
+
+			assert property (@(posedge i_clk)
+				disable iff (i_reset)
+				i_ready |=> (o_valid == i_valid));
+
+		end else begin
+
+			assert property (@(posedge i_clk)
+				disable iff (i_reset)
+				i_valid && o_ready |=> o_valid);
+
+			assert property (@(posedge i_clk)
+				disable iff (i_reset)
+				!i_valid && o_ready && i_ready |=> !o_valid);
+
+		end
+
+		// Rule #4
+		//	Same thing, but this time for r_valid
+		assert property (@(posedge i_clk)
+			!o_ready && i_ready |=> o_ready);
+
+
+		if (OPT_LOWPOWER)
+		begin
+			//
+			// If OPT_LOWPOWER is set, o_data and r_data both need
+			// to be zero any time !o_valid or !r_valid respectively
+			assert property (@(posedge i_clk)
+				(OPT_OUTREG || !i_reset) && !o_valid |-> o_data == 0);
+
+			assert property (@(posedge i_clk)
+				o_ready |-> r_data == 0);
+
+			// else
+			//	if OPT_LOWPOWER isn't set, we can lower our
+			//	logic count by not forcing these values to zero.
+		end
+
+`ifdef	SKIDBUFFER
+		reg	f_changed_data;
+
+		// Cover test
+		cover property (@(posedge i_clk)
+			disable iff (i_reset)
+			(!o_valid && !i_valid)
+			##1 i_valid &&  i_ready [*3]
+			##1 i_valid && !i_ready
+			##1 i_valid &&  i_ready [*2]
+			##1 i_valid && !i_ready [*2]
+			##1 i_valid &&  i_ready [*3]
+			// Wait for the design to clear
+			##1 o_valid && i_ready [*0:5]
+			##1 (!o_valid && !i_valid && f_changed_data));
+
+		initial	f_changed_data = 0;
+		always @(posedge i_clk)
+		if (i_reset)
+			f_changed_data <= 1;
+		else if (i_valid && $past(!i_valid || o_ready))
+		begin
+			if (i_data != $past(i_data + 1))
+				f_changed_data <= 0;
+		end else if (!i_valid && i_data != 0)
+			f_changed_data <= 0;
+
+`endif	// SKIDCOVER
+	end endgenerate
+
+`endif	// FORMAL_VERIFIC
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/wbarbiter.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbarbiter.v
new file mode 100644
index 0000000..9a834aa
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbarbiter.v
@@ -0,0 +1,360 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	wbarbiter.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	This is a priority bus arbiter.  It allows two separate wishbone
+//		masters to connect to the same bus, while also guaranteeing
+//	that the last master can have the bus with no delay any time it is
+//	idle.  The goal is to minimize the combinatorial logic required in this
+//	process, while still minimizing access time.
+//
+//	The core logic works like this:
+//
+//		1. If 'A' or 'B' asserts the o_cyc line, a bus cycle will begin,
+//			with acccess granted to whomever requested it.
+//		2. If both 'A' and 'B' assert o_cyc at the same time, only 'A'
+//			will be granted the bus.  (If the alternating parameter 
+//			is set, A and B will alternate who gets the bus in
+//			this case.)
+//		3. The bus will remain owned by whomever the bus was granted to
+//			until they deassert the o_cyc line.
+//		4. At the end of a bus cycle, o_cyc is guaranteed to be
+//			deasserted (low) for one clock.
+//		5. On the next clock, bus arbitration takes place again.  If
+//			'A' requests the bus, no matter how long 'B' was
+//			waiting, 'A' will then be granted the bus.  (Unless
+//			again the alternating parameter is set, then the
+//			access is guaranteed to switch to B.)
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2015-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+`define	WBA_ALTERNATING
+//
+module	wbarbiter(i_clk, i_reset,
+	// Bus A -- the priority bus
+	i_a_cyc, i_a_stb, i_a_we, i_a_adr, i_a_dat, i_a_sel,
+		o_a_ack, o_a_stall, o_a_err,
+	// Bus B
+	i_b_cyc, i_b_stb, i_b_we, i_b_adr, i_b_dat, i_b_sel,
+		o_b_ack, o_b_stall, o_b_err,
+	// Combined/arbitrated bus
+	o_cyc, o_stb, o_we, o_adr, o_dat, o_sel, i_ack, i_stall, i_err
+`ifdef	FORMAL
+	,
+	f_a_nreqs, f_a_nacks, f_a_outstanding,
+	f_b_nreqs, f_b_nacks, f_b_outstanding,
+	f_nreqs,   f_nacks,   f_outstanding
+`endif
+	);
+	parameter			DW=32, AW=32;
+	parameter			SCHEME="ALTERNATING";
+	parameter	[0:0]		OPT_ZERO_ON_IDLE = 1'b0;
+	parameter			F_MAX_STALL = 3;
+	parameter			F_MAX_ACK_DELAY = 3;
+	parameter			F_LGDEPTH=3;
+
+	//
+	input	wire			i_clk, i_reset;
+	// Bus A
+	input	wire			i_a_cyc, i_a_stb, i_a_we;
+	input	wire	[(AW-1):0]	i_a_adr;
+	input	wire	[(DW-1):0]	i_a_dat;
+	input	wire	[(DW/8-1):0]	i_a_sel;
+	output	wire			o_a_ack, o_a_stall, o_a_err;
+	// Bus B
+	input	wire			i_b_cyc, i_b_stb, i_b_we;
+	input	wire	[(AW-1):0]	i_b_adr;
+	input	wire	[(DW-1):0]	i_b_dat;
+	input	wire	[(DW/8-1):0]	i_b_sel;
+	output	wire			o_b_ack, o_b_stall, o_b_err;
+	//
+	output	wire			o_cyc, o_stb, o_we;
+	output	wire	[(AW-1):0]	o_adr;
+	output	wire	[(DW-1):0]	o_dat;
+	output	wire	[(DW/8-1):0]	o_sel;
+	input	wire			i_ack, i_stall, i_err;
+	//
+`ifdef	FORMAL
+	output	wire	[(F_LGDEPTH-1):0] f_nreqs, f_nacks, f_outstanding,
+			f_a_nreqs, f_a_nacks, f_a_outstanding,
+			f_b_nreqs, f_b_nacks, f_b_outstanding;
+`endif
+
+	// Go high immediately (new cycle) if ...
+	//	Previous cycle was low and *someone* is requesting a bus cycle
+	// Go low immadiately if ...
+	//	We were just high and the owner no longer wants the bus
+	// WISHBONE Spec recommends no logic between a FF and the o_cyc
+	//	This violates that spec.  (Rec 3.15, p35)
+	reg	r_a_owner;
+
+	assign o_cyc = (r_a_owner) ? i_a_cyc : i_b_cyc;
+	initial	r_a_owner = 1'b1;
+
+	generate if (SCHEME == "PRIORITY")
+	begin : PRI
+
+		always @(posedge i_clk)
+			if (!i_b_cyc)
+				r_a_owner <= 1'b1;
+			// Allow B to set its CYC line w/o activating this
+			// interface
+			else if ((i_b_stb)&&(!i_a_cyc))
+				r_a_owner <= 1'b0;
+
+	end else if (SCHEME == "ALTERNATING")
+	begin : ALT
+
+		reg	last_owner;
+		initial	last_owner = 1'b0;
+		always @(posedge i_clk)
+			if ((i_a_cyc)&&(r_a_owner))
+				last_owner <= 1'b1;
+			else if ((i_b_cyc)&&(!r_a_owner))
+				last_owner <= 1'b0;
+
+		always @(posedge i_clk)
+			if ((!i_a_cyc)&&(!i_b_cyc))
+				r_a_owner <= !last_owner;
+			else if ((r_a_owner)&&(!i_a_cyc))
+			begin
+
+				if (i_b_stb)
+					r_a_owner <= 1'b0;
+
+			end else if ((!r_a_owner)&&(!i_b_cyc))
+			begin
+
+				if (i_a_stb)
+					r_a_owner <= 1'b1;
+
+			end
+
+	end else // if (SCHEME == "LAST")
+	begin : LST
+		always @(posedge i_clk)
+			if ((!i_a_cyc)&&(i_b_stb))
+				r_a_owner <= 1'b0;
+			else if ((!i_b_cyc)&&(i_a_stb))
+				r_a_owner <= 1'b1;
+	end endgenerate
+
+
+	// Realistically, if neither master owns the bus, the output is a
+	// don't care.  Thus we trigger off whether or not 'A' owns the bus.
+	// If 'B' owns it all we care is that 'A' does not.  Likewise, if
+	// neither owns the bus than the values on the various lines are
+	// irrelevant.
+	assign o_we  = (r_a_owner) ? i_a_we  : i_b_we;
+
+	generate if (OPT_ZERO_ON_IDLE)
+	begin
+		//
+		// OPT_ZERO_ON_IDLE will use up more logic and may even slow
+		// down the master clock if set.  However, it may also reduce
+		// the power used by the FPGA by preventing things from toggling
+		// when the bus isn't in use.  The option is here because it
+		// also makes it a lot easier to look for when things happen
+		// on the bus via VERILATOR when timing and logic counts
+		// don't matter.
+		//
+		assign o_stb     = (o_cyc)? ((r_a_owner) ? i_a_stb : i_b_stb):0;
+		assign o_adr     = (o_stb)? ((r_a_owner) ? i_a_adr : i_b_adr):0;
+		assign o_dat     = (o_stb)? ((r_a_owner) ? i_a_dat : i_b_dat):0;
+		assign o_sel     = (o_stb)? ((r_a_owner) ? i_a_sel : i_b_sel):0;
+		assign o_a_ack   = (o_cyc)&&( r_a_owner) ? i_ack   : 1'b0;
+		assign o_b_ack   = (o_cyc)&&(!r_a_owner) ? i_ack   : 1'b0;
+		assign o_a_stall = (o_cyc)&&( r_a_owner) ? i_stall : 1'b1;
+		assign o_b_stall = (o_cyc)&&(!r_a_owner) ? i_stall : 1'b1;
+		assign o_a_err   = (o_cyc)&&( r_a_owner) ? i_err : 1'b0;
+		assign o_b_err   = (o_cyc)&&(!r_a_owner) ? i_err : 1'b0;
+	end else begin
+
+		assign o_stb = (r_a_owner) ? i_a_stb : i_b_stb;
+		assign o_adr = (r_a_owner) ? i_a_adr : i_b_adr;
+		assign o_dat = (r_a_owner) ? i_a_dat : i_b_dat;
+		assign o_sel = (r_a_owner) ? i_a_sel : i_b_sel;
+
+		// We cannot allow the return acknowledgement to ever go high if
+		// the master in question does not own the bus.  Hence we force
+		// it low if the particular master doesn't own the bus.
+		assign	o_a_ack   = ( r_a_owner) ? i_ack   : 1'b0;
+		assign	o_b_ack   = (!r_a_owner) ? i_ack   : 1'b0;
+
+		// Stall must be asserted on the same cycle the input master
+		// asserts the bus, if the bus isn't granted to him.
+		assign	o_a_stall = ( r_a_owner) ? i_stall : 1'b1;
+		assign	o_b_stall = (!r_a_owner) ? i_stall : 1'b1;
+
+		//
+		//
+		assign	o_a_err = ( r_a_owner) ? i_err : 1'b0;
+		assign	o_b_err = (!r_a_owner) ? i_err : 1'b0;
+	end endgenerate
+
+	// Make Verilator happy
+	// verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = i_reset;
+	// verilator lint_on  UNUSED
+
+`ifdef	FORMAL
+
+`ifdef	WBARBITER
+
+`define	ASSUME	assume
+`else
+`define	ASSUME	assert
+`endif
+
+	reg	f_past_valid;
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+
+	initial	`ASSUME(!i_a_cyc);
+	initial	`ASSUME(!i_a_stb);
+
+	initial	`ASSUME(!i_b_cyc);
+	initial	`ASSUME(!i_b_stb);
+
+	initial	`ASSUME(!i_ack);
+	initial	`ASSUME(!i_err);
+
+	always @(*)
+	if (!f_past_valid)
+		`ASSUME(i_reset);
+
+	always @(posedge i_clk)
+	begin
+		if (o_cyc)
+			assert((i_a_cyc)||(i_b_cyc));
+		if ((f_past_valid)&&($past(o_cyc))&&(o_cyc))
+			assert($past(r_a_owner) == r_a_owner);
+	end
+
+	fwb_master #(.DW(DW), .AW(AW),
+			.F_MAX_STALL(F_MAX_STALL),
+			.F_LGDEPTH(F_LGDEPTH),
+			.F_MAX_ACK_DELAY(F_MAX_ACK_DELAY),
+			.F_OPT_RMW_BUS_OPTION(1),
+			.F_OPT_DISCONTINUOUS(1))
+		f_wbm(i_clk, i_reset,
+			o_cyc, o_stb, o_we, o_adr, o_dat, o_sel,
+			i_ack, i_stall, 32'h0, i_err,
+			f_nreqs, f_nacks, f_outstanding);
+
+	fwb_slave  #(.DW(DW), .AW(AW),
+			.F_MAX_STALL(0),
+			.F_LGDEPTH(F_LGDEPTH),
+			.F_MAX_ACK_DELAY(0),
+			.F_OPT_RMW_BUS_OPTION(1),
+			.F_OPT_DISCONTINUOUS(1))
+		f_wba(i_clk, i_reset,
+			i_a_cyc, i_a_stb, i_a_we, i_a_adr, i_a_dat, i_a_sel, 
+			o_a_ack, o_a_stall, 32'h0, o_a_err,
+			f_a_nreqs, f_a_nacks, f_a_outstanding);
+
+	fwb_slave  #(.DW(DW), .AW(AW),
+			.F_MAX_STALL(0),
+			.F_LGDEPTH(F_LGDEPTH),
+			.F_MAX_ACK_DELAY(0),
+			.F_OPT_RMW_BUS_OPTION(1),
+			.F_OPT_DISCONTINUOUS(1))
+		f_wbb(i_clk, i_reset,
+			i_b_cyc, i_b_stb, i_b_we, i_b_adr, i_b_dat, i_b_sel,
+			o_b_ack, o_b_stall, 32'h0, o_b_err,
+			f_b_nreqs, f_b_nacks, f_b_outstanding);
+
+	always @(posedge i_clk)
+		if (r_a_owner)
+		begin
+			assert(f_b_nreqs == 0);
+			assert(f_b_nacks == 0);
+			assert(f_a_outstanding == f_outstanding);
+		end else begin
+			assert(f_a_nreqs == 0);
+			assert(f_a_nacks == 0);
+			assert(f_b_outstanding == f_outstanding);
+		end
+
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_reset))
+			&&($past(i_a_stb))&&(!$past(i_b_cyc)))
+		assert(r_a_owner);
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_reset))
+			&&(!$past(i_a_cyc))&&($past(i_b_stb)))
+		assert(!r_a_owner);
+
+	always @(posedge i_clk)
+		if ((f_past_valid)&&(r_a_owner != $past(r_a_owner)))
+			assert(!$past(o_cyc));
+
+	reg	f_prior_a_ack, f_prior_b_ack;
+
+	initial	f_prior_a_ack = 1'b0;
+	always @(posedge i_clk)
+	if ((i_reset)||(o_a_err)||(o_b_err))
+		f_prior_a_ack = 1'b0;
+	else if ((o_cyc)&&(o_a_ack))
+		f_prior_a_ack <= 1'b1;
+
+	initial	f_prior_b_ack = 1'b0;
+	always @(posedge i_clk)
+	if ((i_reset)||(o_a_err)||(o_b_err))
+		f_prior_b_ack = 1'b0;
+	else if ((o_cyc)&&(o_b_ack))
+		f_prior_b_ack <= 1'b1;
+
+	always @(posedge i_clk)
+	begin
+		cover(f_prior_b_ack && o_cyc && o_a_ack);
+
+		cover((o_cyc && o_a_ack)
+			&&($past(o_cyc && o_a_ack))
+			&&($past(o_cyc && o_a_ack,2)));
+
+
+		cover(f_prior_a_ack && o_cyc && o_b_ack);
+
+		cover((o_cyc && o_b_ack)
+			&&($past(o_cyc && o_b_ack))
+			&&($past(o_cyc && o_b_ack,2)));
+	end
+
+	always @(*)
+		cover(o_cyc && o_b_ack);
+`endif
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/wbc2pipeline.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbc2pipeline.v
new file mode 100644
index 0000000..1ed0e00
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbc2pipeline.v
@@ -0,0 +1,154 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	wbc2pipeline.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Takes a WB classic connection from a master, and converts it
+//		to WB pipelined for the slave.
+//
+//	If you don't see an `ifdef FORMAL section below, then this core hasn't
+//	(yet) been formally verified.  Use it at your own risk.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module	wbc2pipeline(i_clk, i_reset,
+		i_mcyc, i_mstb, i_mwe, i_maddr, i_mdata, i_msel,
+			o_mack, o_mdata, o_merr,
+			i_mcti, i_mbte,
+		o_scyc, o_sstb, o_swe, o_saddr, o_sdata, o_ssel,
+			i_sstall, i_sack, i_sdata, i_serr);
+	parameter	AW = 12,
+			DW = 32;
+	//
+	input	wire			i_clk, i_reset;
+	//
+	// Incoming WB classic port
+	input	wire			i_mcyc, i_mstb, i_mwe;
+	input	wire	[AW-1:0]	i_maddr;
+	input	wire	[DW-1:0]	i_mdata;
+	input	wire	[DW/8-1:0]	i_msel;
+	output	reg			o_mack;
+	output	reg	[DW-1:0]	o_mdata;
+	output	reg			o_merr;
+	input	wire	[3-1:0]		i_mcti;
+	input	wire	[2-1:0]		i_mbte;
+	//
+	// Outgoing WB pipelined port
+	output	reg			o_scyc, o_sstb, o_swe;
+	output	reg	[AW-1:0]	o_saddr;
+	output	reg	[DW-1:0]	o_sdata;
+	output	reg	[DW/8-1:0]	o_ssel;
+	input	wire			i_sstall;
+	input	wire			i_sack;
+	input	wire	[DW-1:0]	i_sdata;
+	input	wire			i_serr;
+
+	reg	last_stb;
+
+	initial	last_stb = 0;
+	always @(posedge i_clk)
+	if (i_reset || !i_mstb || o_mack || o_merr)
+		last_stb <= 0;
+	else if (!i_sstall)
+		last_stb <= 1;
+
+	always @(*)
+	begin
+		o_scyc  = i_mcyc && (!o_merr);
+		o_sstb  = i_mstb & !last_stb && (!o_merr);
+		o_swe   = i_mwe;
+		o_saddr = i_maddr;
+		o_sdata = i_mdata;
+		o_ssel  = i_msel;
+	end
+	
+	initial	o_mack = 0;
+	initial	o_merr = 0;
+	always @(posedge i_clk)
+	if (i_reset || !i_mstb || o_mack || o_merr)
+	begin
+		o_mack <= 0;
+		o_merr <= 0;
+	end else begin
+		if (i_sack)
+			o_mack <= 1;
+		if (i_serr)
+			o_merr <= 1;
+	end
+
+	always @(posedge i_clk)
+	if (i_sack)
+		o_mdata <= i_sdata;
+
+
+	// Verilator lint_off UNUSED
+	wire	[4:0]	unused;
+	assign	unused = { i_mcti, i_mbte };
+	// Verilator lint_on  UNUSED
+`ifdef	FORMAL
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	localparam	F_LGDEPTH = 1;
+	reg	[F_LGDEPTH-1:0]	f_nreqs, f_nacks, f_outstanding;
+
+	reg	f_past_valid;
+	initial	f_past_valid = 0;
+	always @(posedge i_clk)
+		f_past_valid = 1;
+
+	always @(*)
+	if (!f_past_valid)
+		assume(i_reset);
+
+	fwbc_slave #(.AW(AW), .DW(DW)) incoming (i_clk, i_reset,
+		i_mcyc, i_mstb, i_mwe, i_maddr, i_mdata, i_msel,
+			i_mcti, i_mbte,
+			o_mack, o_mdata, o_merr, 1'b0);
+
+	fwb_master #(.AW(AW), .DW(DW),
+			.F_MAX_STALL(3),
+			.F_MAX_ACK_DELAY(3),
+			.F_LGDEPTH(1)) pipelined (i_clk, i_reset,
+		o_scyc, o_sstb, o_swe, o_saddr, o_sdata, o_ssel,
+			i_sack, i_sstall, i_sdata, i_serr,
+			f_nreqs, f_nacks, f_outstanding);
+
+//	always @(*)
+//	if (f_outstanding)
+//		assert(returned);
+`endif
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/wbm2axilite.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbm2axilite.v
new file mode 100644
index 0000000..f3d63e2
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbm2axilite.v
@@ -0,0 +1,623 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	wbm2axilite.v (Wishbone master to AXI slave, pipelined)
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Convert from a wishbone master to an AXI lite interface.  The
+//		big difference is that AXI lite doesn't support bursting,
+//	or transaction ID's.  This actually makes the task a *LOT* easier.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2018-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module wbm2axilite #(
+	parameter C_AXI_ADDR_WIDTH	=  28,// AXI Address width
+	localparam C_AXI_DATA_WIDTH	=  32,// Width of the AXI R&W data
+	localparam DW			=  C_AXI_DATA_WIDTH,// Wishbone data width
+	localparam AW			=  C_AXI_ADDR_WIDTH-2// WB addr width (log wordsize)
+	) (
+	input	wire			i_clk,
+	input	wire			i_reset,
+	//
+	// We'll share the clock and the reset
+	input	wire			i_wb_cyc,
+	input	wire			i_wb_stb,
+	input	wire			i_wb_we,
+	input	wire	[(AW-1):0]	i_wb_addr,
+	input	wire	[(DW-1):0]	i_wb_data,
+	input	wire	[(DW/8-1):0]	i_wb_sel,
+	output	wire			o_wb_stall,
+	output	reg			o_wb_ack,
+	output	reg	[(DW-1):0]	o_wb_data,
+	output	reg			o_wb_err,
+	//
+	// AXI write address channel signals
+	output	reg			o_axi_awvalid,
+	input	wire			i_axi_awready,
+	output	reg	[C_AXI_ADDR_WIDTH-1:0]	o_axi_awaddr,
+	output	wire	[2:0]		o_axi_awprot,
+	//
+	// AXI write data channel signals
+	output	reg			o_axi_wvalid,
+	input	wire			i_axi_wready,
+	output	reg	[C_AXI_DATA_WIDTH-1:0]	o_axi_wdata,
+	output	reg	[C_AXI_DATA_WIDTH/8-1:0] o_axi_wstrb,
+	//
+	// AXI write response channel signals
+	input	wire			i_axi_bvalid,
+	output	wire			o_axi_bready,
+	input	wire [1:0]		i_axi_bresp,
+	//
+	// AXI read address channel signals
+	output	reg			o_axi_arvalid,
+	input	wire			i_axi_arready,
+	output	reg	[C_AXI_ADDR_WIDTH-1:0]	o_axi_araddr,
+	output	wire	[2:0]		o_axi_arprot,
+	//
+	// AXI read data channel signals   
+	input	wire			i_axi_rvalid,
+	output	wire			o_axi_rready,
+	input wire [C_AXI_DATA_WIDTH-1:0] i_axi_rdata,
+	input	wire	[1:0]		i_axi_rresp
+	);
+
+//*****************************************************************************
+// Local Parameter declarations
+//*****************************************************************************
+
+	localparam	LG_AXI_DW	= ( C_AXI_DATA_WIDTH ==   8) ? 3
+					: ((C_AXI_DATA_WIDTH ==  16) ? 4
+					: ((C_AXI_DATA_WIDTH ==  32) ? 5
+					: ((C_AXI_DATA_WIDTH ==  64) ? 6
+					: ((C_AXI_DATA_WIDTH == 128) ? 7
+					: 8))));
+
+	localparam	LG_WB_DW	= ( DW ==   8) ? 3
+					: ((DW ==  16) ? 4
+					: ((DW ==  32) ? 5
+					: ((DW ==  64) ? 6
+					: ((DW == 128) ? 7
+					: 8))));
+	//
+	// LGIFOFLN: The log (based two) of the size of our FIFO.  This is a
+	// localparam since 1) 32-bit distributed memories nearly come for
+	// free, and 2) because there is no performance gain to be had in larger
+	// memories.  2^32 entries is the perfect size for this application.
+	// Any smaller, and the core will not be able to maintain 100%
+	// throughput.
+	localparam	LGFIFOLN = 5;
+	localparam	FIFOLN = (1<<LGFIFOLN);
+
+
+//*****************************************************************************
+// Internal register and wire declarations
+//*****************************************************************************
+
+// Things we're not changing ...
+	assign o_axi_awprot  = 3'b000;	// Unpriviledged, unsecure, data access
+	assign o_axi_arprot  = 3'b000;	// Unpriviledged, unsecure, data access
+
+	reg	full_fifo, err_state, axi_reset_state, wb_we;
+	reg	[3:0]	reset_count;
+	reg			pending;
+	reg	[LGFIFOLN-1:0]	outstanding, err_pending;
+
+
+// Master bridge logic
+	assign	o_wb_stall = (full_fifo)
+			||((!i_wb_we)&&( wb_we)&&(pending))
+			||(( i_wb_we)&&(!wb_we)&&(pending))
+			||(err_state)||(axi_reset_state)
+			||(o_axi_arvalid)&&(!i_axi_arready)
+			||(o_axi_awvalid)&&(!i_axi_awready)
+			||(o_axi_wvalid)&&(!i_axi_wready);
+
+	initial	axi_reset_state = 1'b1;
+	initial	reset_count = 4'hf;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		axi_reset_state <= 1'b1;
+		if (reset_count > 0)
+			reset_count <= reset_count - 1'b1;
+	end else if ((axi_reset_state)&&(reset_count > 0))
+		reset_count <= reset_count - 1'b1;
+	else begin
+		axi_reset_state <= 1'b0;
+		reset_count <= 4'hf;
+	end
+
+	// Count outstanding transactions
+	initial	pending = 0;
+	initial	outstanding = 0;
+	always @(posedge i_clk)
+	if ((i_reset)||(axi_reset_state))
+	begin
+		pending <= 0;
+		outstanding <= 0;
+		full_fifo <= 0;
+	end else if ((err_state)||(!i_wb_cyc))
+	begin
+		pending <= 0;
+		outstanding <= 0;
+		full_fifo <= 0;
+	end else case({ ((i_wb_stb)&&(!o_wb_stall)), (o_wb_ack) })
+	2'b01: begin
+		outstanding <= outstanding - 1'b1;
+		pending <= (outstanding >= 2);
+		full_fifo <= 1'b0;
+		end
+	2'b10: begin
+		outstanding <= outstanding + 1'b1;
+		pending <= 1'b1;
+		full_fifo <= (outstanding >= {{(LGFIFOLN-2){1'b1}},2'b01});
+		end
+	default: begin end
+	endcase
+
+	always @(posedge i_clk)
+	if ((i_wb_stb)&&(!o_wb_stall))
+		wb_we <= i_wb_we;
+
+	//
+	//
+	// Write address logic
+	//
+	initial	o_axi_awvalid = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		o_axi_awvalid <= 0;
+	else
+		o_axi_awvalid <= (!o_wb_stall)&&(i_wb_stb)&&(i_wb_we)
+			||(o_axi_awvalid)&&(!i_axi_awready);
+
+	always @(posedge i_clk)
+	if (!o_wb_stall)
+		o_axi_awaddr <= { i_wb_addr, 2'b00 };
+
+	//
+	//
+	// Read address logic
+	//
+	initial	o_axi_arvalid = 1'b0;
+	always @(posedge i_clk)
+	if (i_reset)
+		o_axi_arvalid <= 1'b0;
+	else
+		o_axi_arvalid <= (!o_wb_stall)&&(i_wb_stb)&&(!i_wb_we)
+			||((o_axi_arvalid)&&(!i_axi_arready));
+	always @(posedge i_clk)
+	if (!o_wb_stall)
+		o_axi_araddr <= { i_wb_addr, 2'b00 };
+
+	//
+	//
+	// Write data logic
+	//
+	always @(posedge i_clk)
+	if (!o_wb_stall)
+	begin
+		o_axi_wdata <= i_wb_data;
+		o_axi_wstrb <= i_wb_sel;
+	end
+
+	initial	o_axi_wvalid = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		o_axi_wvalid <= 0;
+	else
+		o_axi_wvalid <= ((!o_wb_stall)&&(i_wb_stb)&&(i_wb_we))
+			||((o_axi_wvalid)&&(!i_axi_wready));
+
+	initial	o_wb_ack = 1'b0;
+	always @(posedge i_clk)
+	if ((i_reset)||(!i_wb_cyc)||(err_state))
+		o_wb_ack <= 1'b0;
+	else if (err_state)
+		o_wb_ack <= 1'b0;
+	else if ((i_axi_bvalid)&&(!i_axi_bresp[1]))
+		o_wb_ack <= 1'b1;
+	else if ((i_axi_rvalid)&&(!i_axi_rresp[1]))
+		o_wb_ack <= 1'b1;
+	else
+		o_wb_ack <= 1'b0;
+
+	always @(posedge i_clk)
+		o_wb_data <= i_axi_rdata;
+
+	// Read data channel / response logic
+	assign	o_axi_rready = 1'b1;
+	assign	o_axi_bready = 1'b1;
+
+	initial	o_wb_err = 1'b0;
+	always @(posedge i_clk)
+	if ((i_reset)||(!i_wb_cyc)||(err_state))
+		o_wb_err <= 1'b0;
+	else if ((i_axi_bvalid)&&(i_axi_bresp[1]))
+		o_wb_err <= 1'b1;
+	else if ((i_axi_rvalid)&&(i_axi_rresp[1]))
+		o_wb_err <= 1'b1;
+	else
+		o_wb_err <= 1'b0;
+
+	initial	err_state = 1'b0;
+	always @(posedge i_clk)
+	if (i_reset)
+		err_state <= 0;
+	else if ((i_axi_bvalid)&&(i_axi_bresp[1]))
+		err_state <= 1'b1;
+	else if ((i_axi_rvalid)&&(i_axi_rresp[1]))
+		err_state <= 1'b1;
+	else if ((pending)&&(!i_wb_cyc))
+		err_state <= 1'b1;
+	else if (err_pending == 0)
+		err_state <= 0;
+
+	initial	err_pending = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		err_pending <= 0;
+	else case({ ((i_wb_stb)&&(!o_wb_stall)),
+					((i_axi_bvalid)||(i_axi_rvalid)) })
+	2'b01: err_pending <= err_pending - 1'b1;
+	2'b10: err_pending <= err_pending + 1'b1;
+	default: begin end
+	endcase
+
+	// Make verilator happy
+	// verilator lint_off UNUSED
+	wire	[2:0]	unused;
+	assign	unused = { i_wb_cyc, i_axi_bresp[0], i_axi_rresp[0] };
+	// verilator lint_on  UNUSED
+
+/////////////////////////////////////////////////////////////////////////
+//
+//
+//
+// Formal methods section
+//
+// These are only relevant when *proving* that this translator works
+//
+//
+//
+/////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	reg	f_past_valid;
+//
+`define	ASSUME	assume
+`define	ASSERT	assert
+
+	// Parameters
+	initial	assert(DW == 32);
+	initial	assert(C_AXI_ADDR_WIDTH == AW+2);
+	//
+
+	//
+	// Setup
+	//
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+
+	always @(*)
+	if (!f_past_valid)
+		`ASSUME(i_reset);
+
+	//////////////////////////////////////////////
+	//
+	//
+	// Assumptions about the WISHBONE inputs
+	//
+	//
+	//////////////////////////////////////////////
+	always @(*)
+		assume(f_past_valid || i_reset);
+
+	wire	[(LGFIFOLN-1):0]	f_wb_nreqs, f_wb_nacks,f_wb_outstanding;
+	fwb_slave #(.DW(DW),.AW(AW),
+			.F_MAX_STALL(0),
+			.F_MAX_ACK_DELAY(0),
+			.F_LGDEPTH(LGFIFOLN),
+			.F_MAX_REQUESTS(FIFOLN-2))
+		f_wb(i_clk, i_reset, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr,
+					i_wb_data, i_wb_sel,
+				o_wb_ack, o_wb_stall, o_wb_data, o_wb_err,
+			f_wb_nreqs, f_wb_nacks, f_wb_outstanding);
+
+	wire	[(LGFIFOLN-1):0]	f_axi_rd_outstanding,
+					f_axi_wr_outstanding,
+					f_axi_awr_outstanding;
+
+	faxil_master #(
+		// .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+		.F_LGDEPTH(LGFIFOLN),
+		.F_AXI_MAXWAIT(3),
+		.F_OPT_HAS_CACHE(1'b0),
+		.F_AXI_MAXDELAY(3))
+		f_axil(.i_clk(i_clk),
+			.i_axi_reset_n((!i_reset)&&(!axi_reset_state)),
+			// Write address channel
+			.i_axi_awready(i_axi_awready), 
+			.i_axi_awaddr( o_axi_awaddr), 
+			.i_axi_awcache(4'h0), 
+			.i_axi_awprot( o_axi_awprot), 
+			.i_axi_awvalid(o_axi_awvalid), 
+			// Write data channel
+			.i_axi_wready( i_axi_wready),
+			.i_axi_wdata(  o_axi_wdata),
+			.i_axi_wstrb(  o_axi_wstrb),
+			.i_axi_wvalid( o_axi_wvalid),
+			// Write response channel
+			.i_axi_bresp(  i_axi_bresp),
+			.i_axi_bvalid( i_axi_bvalid),
+			.i_axi_bready( o_axi_bready),
+			// Read address channel
+			.i_axi_arready(i_axi_arready),
+			.i_axi_araddr( o_axi_araddr),
+			.i_axi_arcache(4'h0),
+			.i_axi_arprot( o_axi_arprot),
+			.i_axi_arvalid(o_axi_arvalid),
+			// Read data channel
+			.i_axi_rresp(  i_axi_rresp),
+			.i_axi_rvalid( i_axi_rvalid),
+			.i_axi_rdata(  i_axi_rdata),
+			.i_axi_rready( o_axi_rready),
+			// Counts
+			.f_axi_rd_outstanding( f_axi_rd_outstanding),
+			.f_axi_wr_outstanding( f_axi_wr_outstanding),
+			.f_axi_awr_outstanding( f_axi_awr_outstanding)
+		);
+
+	//////////////////////////////////////////////
+	//
+	//
+	// Assumptions about the AXI inputs
+	//
+	//
+	//////////////////////////////////////////////
+
+
+	//////////////////////////////////////////////
+	//
+	//
+	// Assertions about the AXI4 ouputs
+	//
+	//
+	//////////////////////////////////////////////
+
+	// Write response channel
+	always @(posedge i_clk)
+		// We keep bready high, so the other condition doesn't
+		// need to be checked
+		assert(o_axi_bready);
+
+	// AXI read data channel signals
+	always @(posedge i_clk)
+		// We keep o_axi_rready high, so the other condition's
+		// don't need to be checked here
+		assert(o_axi_rready);
+
+	//
+	// Let's look into write requests
+	//
+	initial	assert(!o_axi_awvalid);
+	initial	assert(!o_axi_wvalid);
+	always @(posedge i_clk)
+	if ((!f_past_valid)||($past(i_reset))||($past(axi_reset_state)))
+	begin
+		assert(!o_axi_awvalid);
+		assert(!o_axi_wvalid);
+	end
+
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_reset))
+		&&($past((i_wb_stb)&&(i_wb_we)&&(!o_wb_stall))))
+	begin
+		// Following any write request that we accept, awvalid
+		// and wvalid should both be true
+		assert(o_axi_awvalid);
+		assert(o_axi_wvalid);
+		assert(wb_we);
+	end else if ((f_past_valid)&&($past(i_reset)))
+	begin
+		if ($past(i_axi_awready))
+			assert(!o_axi_awvalid);
+		if ($past(i_axi_wready))
+			assert(!o_axi_wvalid);
+	end
+
+	//
+	// AXI write address channel
+	//
+	always @(posedge i_clk)
+	if ((f_past_valid)&&($past((i_wb_stb)&&(i_wb_we)&&(!o_wb_stall))))
+		assert(o_axi_awaddr == { $past(i_wb_addr[AW-1:0]), 2'b00 });
+
+	//
+	// AXI write data channel
+	//
+	always @(posedge i_clk)
+	if ((f_past_valid)&&($past(i_wb_stb)&&(i_wb_we)&&(!$past(o_wb_stall))))
+	begin
+		assert(o_axi_wdata == $past(i_wb_data));
+		assert(o_axi_wstrb == $past(i_wb_sel));
+	end
+
+	//
+	// AXI read address channel
+	//
+	initial	assert(!o_axi_arvalid);
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(!$past(i_reset))
+		&&($past((i_wb_stb)&&(!i_wb_we)&&(!o_wb_stall))))
+	begin
+		assert(o_axi_arvalid);
+		assert(o_axi_araddr == { $past(i_wb_addr), 2'b00 });
+	end
+	//
+
+	//
+	// AXI write response channel
+	//
+
+	//
+	// AXI read data channel signals
+	//
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(($past(i_reset))||($past(axi_reset_state))))
+	begin
+		// Relate err_pending to outstanding
+		assert(outstanding == 0);
+		assert(err_pending == 0);
+	end else if (!err_state)
+		assert(err_pending == outstanding - ((o_wb_ack)||(o_wb_err)));
+
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(($past(i_reset))||($past(axi_reset_state))))
+	begin
+		assert(f_axi_awr_outstanding == 0);
+		assert(f_axi_wr_outstanding == 0);
+		assert(f_axi_rd_outstanding == 0);
+
+		assert(f_wb_outstanding == 0);
+		assert(!pending);
+		assert(outstanding == 0);
+		assert(err_pending == 0);
+	end else if (wb_we)
+	begin
+		case({o_axi_awvalid,o_axi_wvalid})
+		2'b00: begin
+			`ASSERT(f_axi_awr_outstanding   == err_pending);
+			`ASSERT(f_axi_wr_outstanding    == err_pending);
+			end
+		2'b01: begin
+			`ASSERT(f_axi_awr_outstanding   == err_pending);
+			`ASSERT(f_axi_wr_outstanding +1 == err_pending);
+			end
+		2'b10: begin
+			`ASSERT(f_axi_awr_outstanding+1 == err_pending);
+			`ASSERT(f_axi_wr_outstanding    == err_pending);
+			end
+		2'b11: begin
+			`ASSERT(f_axi_awr_outstanding+1 == err_pending);
+			`ASSERT(f_axi_wr_outstanding +1 == err_pending);
+			end
+		endcase
+
+		//
+		`ASSERT(!o_axi_arvalid);
+		`ASSERT(f_axi_rd_outstanding == 0);
+	end else begin
+		if (!o_axi_arvalid)
+			`ASSERT(f_axi_rd_outstanding == err_pending);
+		else
+			`ASSERT(f_axi_rd_outstanding+1 == err_pending);
+
+		`ASSERT(!o_axi_awvalid);
+		`ASSERT(!o_axi_wvalid);
+		`ASSERT(f_axi_awr_outstanding == 0);
+		`ASSERT(f_axi_wr_outstanding == 0);
+	end
+
+	always @(*)
+	if ((!i_reset)&&(i_wb_cyc)&&(!err_state))
+		`ASSERT(f_wb_outstanding == outstanding);
+
+	always @(posedge i_clk)
+	if ((f_past_valid)&&(err_state))
+		`ASSERT((o_wb_err)||(f_wb_outstanding == 0));
+
+	always @(posedge i_clk)
+		`ASSERT(pending == (outstanding != 0));
+	//
+	// Make sure we only create one request at a time
+	always @(posedge i_clk)
+		`ASSERT((!o_axi_arvalid)||(!o_axi_wvalid));
+	always @(posedge i_clk)
+		`ASSERT((!o_axi_arvalid)||(!o_axi_awvalid));
+	always @(posedge i_clk)
+	if (wb_we)
+		`ASSERT(!o_axi_arvalid);
+	else
+		`ASSERT((!o_axi_awvalid)&&(!o_axi_wvalid));
+
+	always @(*)
+	if (&outstanding[LGFIFOLN-1:1])
+		`ASSERT(full_fifo);
+	always @(*)
+		assert(outstanding < {(LGFIFOLN){1'b1}});
+
+	// AXI cover results
+	always @(*)
+		cover(i_axi_bvalid && o_axi_bready);
+	always @(*)
+		cover(i_axi_rvalid && o_axi_rready);
+
+	always @(posedge i_clk)
+		cover(i_axi_bvalid && o_axi_bready
+			&& $past(i_axi_bvalid && o_axi_bready)
+			&& $past(i_axi_bvalid && o_axi_bready,2));
+
+	always @(posedge i_clk)
+		cover(i_axi_rvalid && o_axi_rready
+			&& $past(i_axi_rvalid && o_axi_rready)
+			&& $past(i_axi_rvalid && o_axi_rready,2));
+
+	// AXI cover requests
+	always @(posedge i_clk)
+		cover(o_axi_arvalid && i_axi_arready
+			&& $past(o_axi_arvalid && i_axi_arready)
+			&& $past(o_axi_arvalid && i_axi_arready,2));
+
+	always @(posedge i_clk)
+		cover(o_axi_awvalid && i_axi_awready
+			&& $past(o_axi_awvalid && i_axi_awready)
+			&& $past(o_axi_awvalid && i_axi_awready,2));
+
+	always @(posedge i_clk)
+		cover(o_axi_wvalid && i_axi_wready
+			&& $past(o_axi_wvalid && i_axi_wready)
+			&& $past(o_axi_wvalid && i_axi_wready,2));
+
+	always @(*)
+		cover(i_axi_rvalid && o_axi_rready);
+
+	// Wishbone cover results
+	always @(*)
+		cover(i_wb_cyc && o_wb_ack);
+
+	always @(posedge i_clk)
+		cover(i_wb_cyc && o_wb_ack
+			&& $past(o_wb_ack)&&$past(o_wb_ack,2));
+
+`endif
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/wbm2axisp.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbm2axisp.v
new file mode 100644
index 0000000..cac5652
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbm2axisp.v
@@ -0,0 +1,1147 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	wbm2axisp.v (Wishbone master to AXI slave, pipelined)
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	The B4 Wishbone SPEC allows transactions at a speed as fast as
+//		one per clock.  The AXI bus allows transactions at a speed of
+//	one read and one write transaction per clock.  These capabilities work
+//	by allowing requests to take place prior to responses, such that the
+//	requests might go out at once per clock and take several clocks, and
+//	the responses may start coming back several clocks later.  In other
+//	words, both protocols allow multiple transactions to be "in flight" at
+//	the same time.  Current wishbone to AXI converters, however, handle only
+//	one transaction at a time: initiating the transaction, and then waiting
+//	for the transaction to complete before initiating the next.
+//
+//	The purpose of this core is to maintain the speed of both buses, while
+//	transiting from the Wishbone (as master) to the AXI bus (as slave) and
+//	back again.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2016-2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// }}}
+module wbm2axisp #(
+	// {{{
+	parameter C_AXI_DATA_WIDTH	= 128,// Width of the AXI R&W data
+	parameter C_AXI_ADDR_WIDTH	=  28,	// AXI Address width (log wordsize)
+	parameter C_AXI_ID_WIDTH	=   1,
+	parameter DW			=  32,	// Wishbone data width
+	parameter AW			=  26,	// Wishbone address width (log wordsize)
+	parameter [C_AXI_ID_WIDTH-1:0] AXI_WRITE_ID = 1'b0,
+	parameter [C_AXI_ID_WIDTH-1:0] AXI_READ_ID  = 1'b1,
+	//
+	// OPT_LITTLE_ENDIAN controls which word has the greatest address
+	// when the bus size is adjusted.  If OPT_LITTLE_ENDIAN is true,
+	// the biggest address is in the most significant word(s), otherwise
+	// the least significant word(s).  This parameter is ignored if
+	// C_AXI_DATA_WIDTH == DW.
+	parameter [0:0]			OPT_LITTLE_ENDIAN = 1'b1,
+	parameter LGFIFO		=   6
+	// }}}
+	) (
+	// {{{
+	input	wire			i_clk,	// System clock
+	input	wire			i_reset,// Reset signal,drives AXI rst
+
+	// AXI write address channel signals
+	output	reg			o_axi_awvalid,	// Write address valid
+	input	wire			i_axi_awready, // Slave is ready to accept
+	output	wire	[C_AXI_ID_WIDTH-1:0]	o_axi_awid,	// Write ID
+	output	reg	[C_AXI_ADDR_WIDTH-1:0]	o_axi_awaddr,	// Write address
+	output	wire	[7:0]		o_axi_awlen,	// Write Burst Length
+	output	wire	[2:0]		o_axi_awsize,	// Write Burst size
+	output	wire	[1:0]		o_axi_awburst,	// Write Burst type
+	output	wire	[0:0]		o_axi_awlock,	// Write lock type
+	output	wire	[3:0]		o_axi_awcache,	// Write Cache type
+	output	wire	[2:0]		o_axi_awprot,	// Write Protection type
+	output	wire	[3:0]		o_axi_awqos,	// Write Quality of Svc
+
+// AXI write data channel signals
+	output	reg			o_axi_wvalid,	// Write valid
+	input	wire			i_axi_wready,  // Write data ready
+	output	reg	[C_AXI_DATA_WIDTH-1:0]	o_axi_wdata,	// Write data
+	output	reg	[C_AXI_DATA_WIDTH/8-1:0] o_axi_wstrb,	// Write strobes
+	output	wire			o_axi_wlast,	// Last write transaction
+
+// AXI write response channel signals
+	input	wire			i_axi_bvalid,  // Write reponse valid
+	output	wire			o_axi_bready,  // Response ready
+	input wire [C_AXI_ID_WIDTH-1:0]	i_axi_bid,	// Response ID
+	input	wire [1:0]		i_axi_bresp,	// Write response
+
+// AXI read address channel signals
+	output	reg			o_axi_arvalid,	// Read address valid
+	input	wire			i_axi_arready,	// Read address ready
+	output	wire	[C_AXI_ID_WIDTH-1:0]	o_axi_arid,	// Read ID
+	output	reg	[C_AXI_ADDR_WIDTH-1:0]	o_axi_araddr,	// Read address
+	output	wire	[7:0]		o_axi_arlen,	// Read Burst Length
+	output	wire	[2:0]		o_axi_arsize,	// Read Burst size
+	output	wire	[1:0]		o_axi_arburst,	// Read Burst type
+	output	wire	[0:0]		o_axi_arlock,	// Read lock type
+	output	wire	[3:0]		o_axi_arcache,	// Read Cache type
+	output	wire	[2:0]		o_axi_arprot,	// Read Protection type
+	output	wire	[3:0]		o_axi_arqos,	// Read Protection type
+
+// AXI read data channel signals
+	input	wire			i_axi_rvalid,  // Read reponse valid
+	output	wire			o_axi_rready,  // Read Response ready
+	input wire [C_AXI_ID_WIDTH-1:0]	i_axi_rid,     // Response ID
+	input wire [C_AXI_DATA_WIDTH-1:0] i_axi_rdata,    // Read data
+	input	wire	[1:0]		i_axi_rresp,   // Read response
+	input	wire			i_axi_rlast,    // Read last
+
+	// We'll share the clock and the reset
+	input	wire			i_wb_cyc,
+	input	wire			i_wb_stb,
+	input	wire			i_wb_we,
+	input	wire	[(AW-1):0]	i_wb_addr,
+	input	wire	[(DW-1):0]	i_wb_data,
+	input	wire	[(DW/8-1):0]	i_wb_sel,
+	output	reg			o_wb_stall,
+	output	reg			o_wb_ack,
+	output	reg	[(DW-1):0]	o_wb_data,
+	output	reg			o_wb_err
+	// }}}
+);
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Localparameter declarations, initial parameter consistency check
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	localparam	LG_AXI_DW	= $clog2(C_AXI_DATA_WIDTH);
+	localparam	LG_WB_DW	= $clog2(DW);
+	localparam	FIFOLN = (1<<LGFIFO);
+	localparam	SUBW = LG_AXI_DW-LG_WB_DW;
+
+	// The various address widths must be properly related.  We'll insist
+	// upon that relationship here.
+	initial begin
+		// This design can't (currently) handle WB widths wider than
+		// the AXI width it is driving.  It can only handle widths
+		// mismatches in the other direction
+		if (C_AXI_DATA_WIDTH < DW)
+			$stop;
+		if (DW == 8 && AW != C_AXI_ADDR_WIDTH)
+			$stop;
+
+		// There must be a definitive relationship between the address
+		// widths of the AXI and WB, and that width is dependent upon
+		// the WB data width
+		if (C_AXI_ADDR_WIDTH != AW + $clog2(DW)-3)
+			$stop;
+		if (	  (C_AXI_DATA_WIDTH / DW !=32)
+			&&(C_AXI_DATA_WIDTH / DW !=16)
+			&&(C_AXI_DATA_WIDTH / DW != 8)
+			&&(C_AXI_DATA_WIDTH / DW != 4)
+			&&(C_AXI_DATA_WIDTH / DW != 2)
+			&&(C_AXI_DATA_WIDTH      != DW))
+			$stop;
+	end
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Internal register and wire declarations
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// Things we're not changing ...
+	localparam	DWSIZE = $clog2(DW)-3;
+	assign o_axi_awid    = AXI_WRITE_ID;
+	assign o_axi_awlen   = 8'h0;	// Burst length is one
+	assign o_axi_awsize  = DWSIZE[2:0];
+	assign o_axi_wlast   = 1;
+	assign o_axi_awburst = 2'b01;	// Incrementing address (ignored)
+	assign o_axi_awlock  = 1'b0;	// Normal signaling
+	assign o_axi_arlock  = 1'b0;	// Normal signaling
+	assign o_axi_awcache = 4'h3;	// Normal: no cache, modifiable
+	//
+	assign o_axi_arid    = AXI_READ_ID;
+	assign o_axi_arlen   = 8'h0;	// Burst length is one
+	assign o_axi_arsize  = DWSIZE[2:0];
+	assign o_axi_arburst = 2'b01;	// Incrementing address (ignored)
+	assign o_axi_arcache = 4'h3;	// Normal: no cache, modifiable
+	assign o_axi_awprot  = 3'b010;	// Unpriviledged, unsecure, data access
+	assign o_axi_arprot  = 3'b010;	// Unpriviledged, unsecure, data access
+	assign o_axi_awqos   = 4'h0;	// Lowest quality of service (unused)
+	assign o_axi_arqos   = 4'h0;	// Lowest quality of service (unused)
+
+	reg			direction, full, empty, flushing, nearfull;
+	reg	[LGFIFO:0]	npending;
+	//
+	wire			skid_ready, m_valid, m_we;
+	reg			m_ready;
+	wire	[AW-1:0]	m_addr;
+	wire	[DW-1:0]	m_data;
+	wire	[DW/8-1:0]	m_sel;
+
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Overarching command logic
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	initial	direction = 0;
+	always @(posedge i_clk)
+	if (empty)
+		direction <= m_we;
+
+	initial	npending = 0;
+	initial	empty    = 1;
+	initial	full     = 0;
+	initial	nearfull = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		npending <= 0;
+		empty    <= 1;
+		full     <= 0;
+		nearfull <= 0;
+	end else case ({m_valid && m_ready, i_axi_bvalid||i_axi_rvalid})
+	2'b10: begin
+		npending <= npending + 1;
+		empty <= 0;
+		nearfull <= &(npending[LGFIFO-1:1]);
+		full <= &(npending[LGFIFO-1:0]);
+		end
+	2'b01: begin
+		nearfull <= full;
+		npending <= npending - 1;
+		empty <= (npending == 1);
+		full <= 0;
+		end
+	default: begin end
+	endcase
+
+	initial	flushing = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		flushing <= 0;
+	else if ((i_axi_rvalid && i_axi_rresp[1])
+		||(i_axi_bvalid && i_axi_bresp[1])
+		||(!i_wb_cyc && !empty))
+		flushing <= 1'b1;
+	else if (empty)
+		flushing <= 1'b0;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Wishbone input skidbuffer
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	skidbuffer #(.DW(1+AW+DW+(DW/8)),
+		.OPT_OUTREG(1'b0))
+	skid (i_clk, i_reset || !i_wb_cyc,
+		i_wb_stb, skid_ready,
+			{ i_wb_we, i_wb_addr, i_wb_data, i_wb_sel },
+		m_valid, m_ready,
+			{ m_we, m_addr, m_data, m_sel });
+
+	always @(*)
+		o_wb_stall = !skid_ready;
+
+	always @(*)
+	begin
+		m_ready = 1;
+
+		if (flushing || nearfull || ((m_we != direction)&&(!empty)))
+			m_ready = 1'b0;
+		if (o_axi_awvalid && !i_axi_awready)
+			m_ready = 1'b0;
+		if (o_axi_wvalid && !i_axi_wready)
+			m_ready = 1'b0;
+		if (o_axi_arvalid && !i_axi_arready)
+			m_ready = 1'b0;
+	end
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// AXI Signaling
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// Write transactions
+	//
+
+	// awvalid, wvalid
+	// {{{
+	// Send write transactions
+	initial	o_axi_awvalid = 0;
+	initial	o_axi_wvalid = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		o_axi_awvalid <= 0;
+		o_axi_wvalid  <= 0;
+	end else if (m_valid && m_we && m_ready)
+	begin
+		o_axi_awvalid <= 1;
+		o_axi_wvalid  <= 1;
+	end else begin
+		if (i_axi_awready)
+			o_axi_awvalid <= 0;
+		if (i_axi_wready)
+			o_axi_wvalid <= 0;
+	end
+	// }}}
+
+	// wdata
+	// {{{
+	always @(posedge i_clk)
+	if (!o_axi_wvalid || i_axi_wready)
+		o_axi_wdata   <= {(C_AXI_DATA_WIDTH/DW){m_data}};
+	// }}}
+
+	// wstrb
+	// {{{
+	generate if (DW == C_AXI_DATA_WIDTH)
+	begin : NO_WSTRB_ADJUSTMENT
+		// {{{
+		always @(posedge i_clk)
+		if (!o_axi_wvalid || i_axi_wready)
+			o_axi_wstrb   <= m_sel;
+		// }}}
+	end else if (OPT_LITTLE_ENDIAN)
+	begin : LITTLE_ENDIAN_WSTRB
+		// {{{
+		always @(posedge i_clk)
+		if (!o_axi_wvalid || i_axi_wready)
+			// Verilator lint_off WIDTH
+			o_axi_wstrb   <= m_sel << ((DW/8) * m_addr[SUBW-1:0]);
+			// Verilator lint_on WIDTH
+		// }}}
+	end else begin : BIG_ENDIAN_WSTRB
+		// {{{
+		reg	[SUBW-1:0]	neg_addr;
+
+		always @(*)
+			neg_addr = ~m_addr[SUBW-1:0];
+
+		always @(posedge i_clk)
+		if (!o_axi_wvalid || i_axi_wready)
+			// Verilator lint_off WIDTH
+			o_axi_wstrb   <= m_sel << ((DW/8)* neg_addr);
+			// Verilator lint_on WIDTH
+		// }}}
+	end endgenerate
+	// }}}
+
+	//
+	// Read transactions
+	//
+
+	// arvalid
+	// {{{
+	initial	o_axi_arvalid = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		o_axi_arvalid <= 0;
+	else if (m_valid && !m_we && m_ready)
+		o_axi_arvalid <= 1;
+	else if (i_axi_arready)
+	begin
+		o_axi_arvalid <= 0;
+	end
+	// }}}
+
+	// awaddr, araddr
+	// {{{
+	generate if (OPT_LITTLE_ENDIAN || DW == C_AXI_DATA_WIDTH)
+	begin
+		// {{{
+		always @(posedge i_clk)
+		if (!o_axi_awvalid || i_axi_awready)
+			o_axi_awaddr  <= { m_addr, {($clog2(DW)-3){1'b0}} };
+
+		always @(posedge i_clk)
+		if (!o_axi_arvalid || i_axi_arready)
+			o_axi_araddr  <= { m_addr, {($clog2(DW)-3){1'b0}} };
+		// }}}
+	end else begin : OPT_BIG_ENDIAN
+		// {{{
+		reg	[SUBW-1:0]	neg_addr;
+
+		always @(*)
+			neg_addr = ~m_addr[SUBW-1:0];
+
+		always @(posedge i_clk)
+		if (!o_axi_awvalid || i_axi_awready)
+		begin
+			o_axi_awaddr <= 0;
+			o_axi_awaddr <= m_addr << ($clog2(DW)-3);
+			o_axi_awaddr[$clog2(DW)-3 +: SUBW] <= neg_addr;
+		end
+
+		always @(posedge i_clk)
+		if (!o_axi_arvalid || i_axi_arready)
+		begin
+			o_axi_araddr <= 0;
+			o_axi_araddr <= m_addr << ($clog2(DW)-3);
+			o_axi_araddr[$clog2(DW)-3 +: SUBW] <= neg_addr;
+		end
+		// }}}
+	end endgenerate
+	// }}}
+
+	// rdata, and returned o_wb_data, o_wb_ack, o_wb_err
+	// {{{
+	generate if (DW == C_AXI_DATA_WIDTH)
+	begin : NO_READ_DATA_SELECT_NECESSARY
+		// {{{
+		always @(*)
+			o_wb_data = i_axi_rdata;
+
+		always @(*)
+			o_wb_ack = !flushing&&((i_axi_rvalid && !i_axi_rresp[1])
+				||(i_axi_bvalid && !i_axi_bresp[1]));
+
+		always @(*)
+			o_wb_err = !flushing&&((i_axi_rvalid && i_axi_rresp[1])
+				||(i_axi_bvalid && i_axi_bresp[1]));
+		// }}}
+	end else begin : READ_FIFO_DATA_SELECT
+	// {{{
+
+		reg	[SUBW-1:0]	addr_fifo	[0:(1<<LGFIFO)-1];
+		reg	[SUBW-1:0]	fifo_value;
+		reg	[LGFIFO:0]	wr_addr, rd_addr;
+		wire	[C_AXI_DATA_WIDTH-1:0]	return_data;
+
+		initial	o_wb_ack = 0;
+		always @(posedge i_clk)
+		if (i_reset || !i_wb_cyc || flushing)
+			o_wb_ack <= 0;
+		else
+			o_wb_ack <= ((i_axi_rvalid && !i_axi_rresp[1])
+				||(i_axi_bvalid && !i_axi_bresp[1]));
+
+		initial	o_wb_err = 0;
+		always @(posedge i_clk)
+		if (i_reset || !i_wb_cyc || flushing)
+			o_wb_err <= 0;
+		else
+			o_wb_err <= ((i_axi_rvalid && i_axi_rresp[1])
+				||(i_axi_bvalid && i_axi_bresp[1]));
+
+
+		initial	wr_addr = 0;
+		always @(posedge i_clk)
+		if (i_reset)
+			wr_addr <= 0;
+		else if (m_valid && m_ready)
+			wr_addr <= wr_addr + 1;
+
+		always @(posedge i_clk)
+		if (m_valid && m_ready)
+			addr_fifo[wr_addr[LGFIFO-1:0]] <= m_addr[SUBW-1:0];
+
+		initial	rd_addr = 0;
+		always @(posedge i_clk)
+		if (i_reset)
+			rd_addr <= 0;
+		else if (i_axi_bvalid || i_axi_rvalid)
+			rd_addr <= rd_addr + 1;
+
+		always @(*)
+			fifo_value = addr_fifo[rd_addr[LGFIFO-1:0]];
+
+		if (OPT_LITTLE_ENDIAN)
+		begin : LITTLE_ENDIAN_RDATA
+
+			assign	return_data = i_axi_rdata >> (fifo_value * DW);
+
+		end else begin : BIG_ENDIAN_RDATA
+
+			reg	[SUBW-1:0]	neg_fifo_value;
+
+			always @(*)
+				neg_fifo_value = ~fifo_value;
+
+			assign	return_data = i_axi_rdata
+						>> (neg_fifo_value * DW);
+
+		end
+
+		always @(posedge i_clk)
+			o_wb_data <= return_data[DW-1:0];
+
+		// Make Verilator happy here
+		if (C_AXI_DATA_WIDTH > DW)
+		begin : UNUSED_DATA
+			// verilator lint_off UNUSED
+			wire	unused_data;
+			assign	unused_data = &{ 1'b0,
+					return_data[C_AXI_DATA_WIDTH-1:DW] };
+		end
+		// verilator lint_on  UNUSED
+`ifdef	FORMAL
+		always @(*)
+			assert(wr_addr - rd_addr == npending);
+
+		always @(*)
+			assert(empty == (wr_addr == rd_addr));
+
+
+		//
+		// ...
+		//
+`endif
+	// }}}
+	end endgenerate
+	// }}}
+
+	// Read data channel / response logic
+	assign	o_axi_rready = 1'b1;
+	assign	o_axi_bready = 1'b1;
+	// }}}
+
+	// Make verilator's -Wall happy
+	// {{{
+	// verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, full, i_axi_bid, i_axi_bresp[0], i_axi_rid, i_axi_rresp[0], i_axi_rlast, m_data, m_sel };
+	generate if (C_AXI_DATA_WIDTH > DW)
+	begin
+		wire	[C_AXI_DATA_WIDTH-1:DW] unused_data;
+		assign	unused_data = i_axi_rdata[C_AXI_DATA_WIDTH-1:DW];
+	end endgenerate
+	// verilator lint_on  UNUSED
+	// }}}
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+//
+// Formal methods section
+// {{{
+// Below are a scattering of the formal properties used.  They are not the
+// complete set of properties.  Those are maintained elsewhere.
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	//
+	// ...
+	//
+
+	// Parameters
+	initial	assert(	  (C_AXI_DATA_WIDTH / DW ==32)
+			||(C_AXI_DATA_WIDTH / DW ==16)
+			||(C_AXI_DATA_WIDTH / DW == 8)
+			||(C_AXI_DATA_WIDTH / DW == 4)
+			||(C_AXI_DATA_WIDTH / DW == 2)
+			||(C_AXI_DATA_WIDTH      == DW));
+	//
+	initial	assert( C_AXI_ADDR_WIDTH == AW + (LG_WB_DW-3));
+
+
+	initial begin
+		assert(C_AXI_DATA_WIDTH >= DW);
+		assert(DW == 8 && AW == C_AXI_ADDR_WIDTH);
+		assert(C_AXI_ADDR_WIDTH == AW + $clog2(DW)-3);
+	end
+	// }}}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Setup / f_past_valid
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	initial	f_past_valid = 1'b0;
+	always @(posedge i_clk)
+		f_past_valid <= 1'b1;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Assumptions about the WISHBONE inputs
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(*)
+	if (!f_past_valid)
+		assume(i_reset);
+
+	fwb_slave #(.DW(DW),.AW(AW),
+			.F_MAX_STALL(0),
+			.F_MAX_ACK_DELAY(0),
+			.F_LGDEPTH(F_LGDEPTH),
+			.F_MAX_REQUESTS(0))
+		f_wb(i_clk, i_reset, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr,
+					i_wb_data, i_wb_sel,
+				o_wb_ack, o_wb_stall, o_wb_data, o_wb_err,
+			f_wb_nreqs, f_wb_nacks, f_wb_outstanding);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Assumptions about the AXI inputs
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	faxi_master #(
+		// {{{
+		.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH)
+		// ...
+		// }}}
+	) f_axi(.i_clk(i_clk), .i_axi_reset_n(!i_reset),
+			// {{{
+			// Write address channel
+			.i_axi_awready(i_axi_awready),
+			.i_axi_awid(   o_axi_awid),
+			.i_axi_awaddr( o_axi_awaddr),
+			.i_axi_awlen(  o_axi_awlen),
+			.i_axi_awsize( o_axi_awsize),
+			.i_axi_awburst(o_axi_awburst),
+			.i_axi_awlock( o_axi_awlock),
+			.i_axi_awcache(o_axi_awcache),
+			.i_axi_awprot( o_axi_awprot),
+			.i_axi_awqos(  o_axi_awqos),
+			.i_axi_awvalid(o_axi_awvalid),
+			// Write data channel
+			.i_axi_wready( i_axi_wready),
+			.i_axi_wdata(  o_axi_wdata),
+			.i_axi_wstrb(  o_axi_wstrb),
+			.i_axi_wlast(  o_axi_wlast),
+			.i_axi_wvalid( o_axi_wvalid),
+			// Write response channel
+			.i_axi_bid(    i_axi_bid),
+			.i_axi_bresp(  i_axi_bresp),
+			.i_axi_bvalid( i_axi_bvalid),
+			.i_axi_bready( o_axi_bready),
+			// Read address channel
+			.i_axi_arready(i_axi_arready),
+			.i_axi_arid(   o_axi_arid),
+			.i_axi_araddr( o_axi_araddr),
+			.i_axi_arlen(  o_axi_arlen),
+			.i_axi_arsize( o_axi_arsize),
+			.i_axi_arburst(o_axi_arburst),
+			.i_axi_arlock( o_axi_arlock),
+			.i_axi_arcache(o_axi_arcache),
+			.i_axi_arprot( o_axi_arprot),
+			.i_axi_arqos(  o_axi_arqos),
+			.i_axi_arvalid(o_axi_arvalid),
+			// Read data channel
+			.i_axi_rid(    i_axi_rid),
+			.i_axi_rresp(  i_axi_rresp),
+			.i_axi_rvalid( i_axi_rvalid),
+			.i_axi_rdata(  i_axi_rdata),
+			.i_axi_rlast(  i_axi_rlast),
+			.i_axi_rready( o_axi_rready),
+			// Counts
+			.f_axi_awr_nbursts(f_axi_awr_nbursts),
+			.f_axi_wr_pending(f_axi_wr_pending),
+			.f_axi_rd_nbursts(f_axi_rd_nbursts),
+			.f_axi_rd_outstanding(f_axi_rd_outstanding)
+			//
+			// ...
+			//
+			// }}}
+	);
+
+	always @(*)
+	if (!flushing && i_wb_cyc)
+		assert(f_wb_outstanding == npending + (r_stb ? 1:0)
+			+ ( ((C_AXI_DATA_WIDTH != DW)
+				&& (o_wb_ack|o_wb_err))? 1:0));
+	else if (flushing && i_wb_cyc && !o_wb_err)
+		assert(f_wb_outstanding == (r_stb ? 1:0));
+
+	always @(*)
+	if (f_axi_awr_nbursts > 0)
+	begin
+		assert(direction);
+		assert(f_axi_rd_nbursts == 0);
+		assert(f_axi_awr_nbursts + (o_axi_awvalid ? 1:0) == npending);
+		assert(f_axi_wr_pending == (o_axi_wvalid&&!o_axi_awvalid ? 1:0));
+
+		//
+		// ...
+		//
+	end
+	always @(*)
+	if (o_axi_awvalid)
+		assert(o_axi_wvalid);
+
+	// Some quick read checks
+	always @(*)
+	if (f_axi_rd_nbursts > 0)
+	begin
+		assert(!direction);
+		assert(f_axi_rd_nbursts+(o_axi_arvalid ? 1:0)
+				== npending);
+		assert(f_axi_awr_nbursts == 0);
+
+		//
+		// ...
+		//
+	end
+
+	always @(*)
+	if (direction)
+	begin
+		assert(npending == (o_axi_awvalid ? 1:0) + f_axi_awr_nbursts);
+		assert(!o_axi_arvalid);
+		assert(f_axi_rd_nbursts == 0);
+		assert(!i_axi_rvalid);
+	end else begin
+		assert(npending == (o_axi_arvalid ? 1:0) + f_axi_rd_nbursts);
+		assert(!o_axi_awvalid);
+		assert(!o_axi_wvalid);
+		assert(f_axi_awr_nbursts == 0);
+	end
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Pending counter properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	always @(*)
+	begin
+		assert(npending <= { 1'b1, {(LGFIFO){1'b0}} });
+		assert(empty == (npending == 0));
+		assert(full == (npending == {1'b1, {(LGFIFO){1'b0}}}));
+		assert(nearfull == (npending >= {1'b0, {(LGFIFO){1'b1}}}));
+		if (full)
+			assert(o_wb_stall);
+	end
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Assertions about the AXI4 ouputs
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// Write response channel
+	always @(posedge i_clk)
+		// We keep bready high, so the other condition doesn't
+		// need to be checked
+		assert(o_axi_bready);
+
+	// AXI read data channel signals
+	always @(posedge i_clk)
+		// We keep o_axi_rready high, so the other condition's
+		// don't need to be checked here
+		assert(o_axi_rready);
+
+	//
+	// AXI write address channel
+	//
+	//
+	always @(*)
+	begin
+		if (o_axi_awvalid || o_axi_wvalid || f_axi_awr_nbursts>0)
+			assert(direction);
+		//
+		// ...
+		//
+	end
+	//
+	// AXI read address channel
+	//
+	always @(*)
+	begin
+		if (o_axi_arvalid || i_axi_rvalid || f_axi_rd_nbursts > 0)
+			assert(!direction);
+		//
+		// ...
+		//
+	end
+
+	//
+	// AXI write response channel
+	//
+
+
+	//
+	// AXI read data channel signals
+	//
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Formal contract check
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Prove that a write to this address will change this value
+	//
+
+	// Some extra register declarations
+	// {{{
+	(* anyconst *) reg [C_AXI_ADDR_WIDTH-1:0]	f_const_addr;
+	reg		[C_AXI_DATA_WIDTH-1:0]		f_data;
+	// }}}
+
+	//
+	// Assume a basic bus response to the given data and address
+	//
+	integer	iN;
+
+	// f_data
+	// {{{
+	initial	f_data = 0;
+	always @(posedge i_clk)
+	if (o_axi_wvalid && i_axi_wready && o_axi_awaddr == f_const_addr)
+	begin
+		for(iN=0; iN<C_AXI_DATA_WIDTH/8; iN=iN+1)
+		begin
+			if (o_axi_wstrb[iN])
+				f_data[8*iN +: 8] <= o_axi_wdata[8*iN +: 8];
+		end
+	end
+	// }}}
+
+	// Assume RDATA == f_data if appropriate
+	// {{{
+	always @(*)
+	if (i_axi_rvalid && o_axi_rready && f_axi_rd_ckvalid
+			&& (f_axi_rd_ckaddr == f_const_addr))
+		assume(i_axi_rdata == f_data);
+	// }}}
+
+	// f_wb_addr -- A WB address designed to match f_const_addr (AXI addr)
+	// {{{
+	always @(*)
+	begin
+		f_wb_addr = f_const_addr[C_AXI_ADDR_WIDTH-1:DWSIZE];
+		if (!OPT_LITTLE_ENDIAN && SUBW > 0)
+			f_wb_addr[0 +: SUBW] = ~f_wb_addr[0 +: SUBW];
+	end
+	// }}}
+
+	// Assume the address is Wishbone word aligned
+	// {{{
+	generate if (DW > 8)
+	begin
+		always @(*)
+			assume(f_const_addr[$clog2(DW)-4:0] == 0);
+	end endgenerate
+	// }}}
+
+	// f_axi_data -- Replicate f_wb_data across the whole word
+	// {{{
+	always @(*)
+		f_axi_data = {(C_AXI_DATA_WIDTH/DW){f_wb_data}};
+	// }}}
+
+	//
+	// ...
+	//
+
+	always @(*)
+	begin
+		f_valid_wb_response = 1;
+		for(iN=0; iN<DW/8; iN=iN+1)
+		begin
+			if (f_wb_strb[iN] && (o_wb_data[iN*8 +: 8] != f_wb_data[iN*8 +: 8]))
+				f_valid_wb_response = 0;
+		end
+	end
+	// }}}
+
+	// f_valid_axi_data
+	// {{{
+	always @(*)
+	begin
+		f_valid_axi_data = 1;
+		for(iN=0; iN<C_AXI_DATA_WIDTH/8; iN=iN+1)
+		begin
+			if (f_axi_strb[iN] && (f_axi_data[iN*8 +: 8] != f_data[iN*8 +: 8]))
+				f_valid_axi_data = 0;
+		end
+	end
+	// }}}
+
+	// f_valid_axi_response
+	// {{{
+	always @(*)
+	begin
+		f_valid_axi_response = 1;
+		for(iN=0; iN<C_AXI_DATA_WIDTH/8; iN=iN+1)
+		begin
+			if (f_axi_strb[iN] && (i_axi_rdata[iN*8 +: 8] != f_data[iN*8 +: 8]))
+				f_valid_axi_response = 0;
+		end
+	end
+	// }}}
+
+	//
+	// ...
+	//
+
+	generate if (DW == C_AXI_DATA_WIDTH)
+	begin
+
+		always @(*)
+			f_axi_strb = f_wb_strb;
+
+	end else if (OPT_LITTLE_ENDIAN)
+	begin
+
+		always @(*)
+			f_axi_strb   <= f_wb_strb << ( (DW/8) *
+				f_wb_addr[SUBW-1:0]);
+
+	end else // if (!OPT_LITTLE_ENDIAN)
+	begin
+		reg	[SUBW-1:0]	f_neg_addr;
+
+		always @(*)
+			f_neg_addr = ~f_wb_addr[SUBW-1:0];
+
+		always @(*)
+			f_axi_strb   <= f_wb_strb << ( (DW/8) * f_neg_addr );
+
+	end endgenerate
+	// }}}
+
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Ad-hoc assertions
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	generate if (DW > 8)
+	begin
+		always @(*)
+		if (o_axi_awvalid)
+			assert(o_axi_awaddr[$clog2(DW)-4:0] == 0);
+
+		always @(*)
+		if (o_axi_arvalid)
+			assert(o_axi_araddr[$clog2(DW)-4:0] == 0);
+
+	end endgenerate
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg	[F_LGDEPTH-1:0]	r_hit_reads, r_hit_writes,
+				r_check_fault, check_fault,
+				cvr_nreads, cvr_nwrites;
+	reg			cvr_flushed, cvr_read2write, cvr_write2read;
+
+	initial	r_hit_reads = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		r_hit_writes <= 0;
+	else if (f_axi_awr_nbursts > 3)
+		r_hit_writes <= 1;
+
+	initial	r_hit_reads = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		r_hit_reads <= 0;
+	else if (f_axi_rd_nbursts > 3)
+		r_hit_reads <= 1;
+
+	always @(*)
+	begin
+		check_fault = 0;
+		if (!i_wb_cyc && o_axi_awvalid)
+			check_fault = 1;
+		if (!i_wb_cyc && o_axi_wvalid)
+			check_fault = 1;
+		if (!i_wb_cyc && f_axi_awr_nbursts > 0)
+			check_fault = 1;
+		if (!i_wb_cyc && i_axi_bvalid)
+			check_fault = 1;
+		//
+		if (!i_wb_cyc && o_axi_arvalid)
+			check_fault = 1;
+		if (!i_wb_cyc && f_axi_rd_outstanding > 0)
+			check_fault = 1;
+		if (!i_wb_cyc && i_axi_rvalid)
+			check_fault = 1;
+		if (!i_wb_cyc && (o_wb_ack | o_wb_err))
+			check_fault = 1;
+
+		if (flushing)
+			check_fault = 1;
+	end
+
+	initial	r_check_fault = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		r_check_fault <= 0;
+	else if (check_fault)
+		r_check_fault <= 1;
+
+	always @(*)
+		cover(r_hit_writes && r_hit_reads && f_axi_rd_nbursts == 0
+			&& f_axi_awr_nbursts == 0
+			&& !o_axi_awvalid && !o_axi_arvalid && !o_axi_wvalid
+			&& !i_axi_bvalid && !i_axi_rvalid
+			&& !o_wb_ack && !o_wb_stall && !i_wb_stb
+			&& !check_fault && !r_check_fault);
+
+	//
+	// ...
+	//
+
+	initial	cvr_flushed = 1'b0;
+	always @(posedge i_clk)
+	if (i_reset)
+		cvr_flushed <= 1'b0;
+	else if (flushing)
+		cvr_flushed <= 1'b1;
+
+	always @(*)
+	begin
+		cover(!i_reset && cvr_flushed && !flushing);
+		cover(!i_reset && cvr_flushed && !flushing && !o_wb_stall);
+	end
+
+	//
+	// Let's cover our ability to turn around, from reads to writes or from
+	// writes to reads.
+	//
+	// Note that without the RMW option above, switching direction requires
+	// dropping i_wb_cyc.  Let's just make certain here, that if we do so,
+	// we don't drop it until after all of the returns come back.
+	//
+	initial	cvr_read2write = 0;
+	always @(posedge i_clk)
+	if (i_reset || (!i_wb_cyc && f_wb_nreqs != f_wb_nacks))
+		cvr_read2write <= 0;
+	else if (!direction && !empty && m_we)
+		cvr_read2write <= 1;
+
+	initial	cvr_write2read = 0;
+	always @(posedge i_clk)
+	if (i_reset || (!i_wb_cyc && f_wb_nreqs != f_wb_nacks))
+		cvr_write2read <= 0;
+	else if (direction && !empty && !m_we)
+		cvr_write2read <= 1;
+
+	always @(*)
+	begin
+		cover(cvr_read2write &&  direction && o_wb_ack && f_wb_outstanding == 1);
+		cover(cvr_write2read && !direction && o_wb_ack && f_wb_outstanding == 1);
+	end
+
+	reg	[2:0]	cvr_ack_after_abort;
+
+	initial	cvr_ack_after_abort = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		cvr_ack_after_abort <= 0;
+	else begin
+		if (!i_wb_cyc)
+			cvr_ack_after_abort[2:0] <= (empty) ? 0 : 3'b01;
+		if (cvr_ack_after_abort[0] && i_wb_cyc && r_stb && flushing)
+			cvr_ack_after_abort[1] <= 1;
+		if (o_wb_ack && &cvr_ack_after_abort[1:0])
+			cvr_ack_after_abort[2] <= 1;
+	end
+
+	always @(*)
+		cover(&cvr_ack_after_abort[1:0]);
+	always @(*)
+		cover(!flushing && (&cvr_ack_after_abort[1:0]));
+	always @(*)
+		cover(&cvr_ack_after_abort[2:0]);
+	always @(*)
+		cover(!i_wb_cyc && &cvr_ack_after_abort[2:0]);
+
+	initial	cvr_nwrites = 0;
+	always @(posedge i_clk)
+	if (i_reset || flushing || !i_wb_cyc || !i_wb_we || o_wb_err)
+		cvr_nwrites <= 0;
+	else if (i_axi_bvalid && o_axi_bready)
+		cvr_nwrites <= cvr_nwrites + 1;
+
+	initial	cvr_nreads = 0;
+	always @(posedge i_clk)
+	if (i_reset || flushing || !i_wb_cyc || i_wb_we || o_wb_err)
+		cvr_nreads <= 0;
+	else if (i_axi_rvalid && o_axi_rready)
+		cvr_nreads <= cvr_nreads + 1;
+
+	always @(*)
+		cover(cvr_nwrites == 3 && !o_wb_ack && !o_wb_err && !i_wb_cyc);
+
+	always @(*)
+		cover(cvr_nreads == 3 && !o_wb_ack && !o_wb_err && !i_wb_cyc);
+
+	//
+	// Generate a cover that doesn't include an abort
+	// {{{
+	(* anyconst *) reg f_never_abort;
+
+	always @(*)
+	if (f_never_abort && f_wb_nacks != f_wb_nreqs)
+		assume(!i_reset && i_wb_cyc && !o_wb_err);
+
+	always @(posedge i_clk)
+	if (f_never_abort && $past(o_wb_ack) && o_wb_ack)
+		assume($changed(o_wb_data));
+
+	always @(*)
+		cover(cvr_nreads == 3 && !o_wb_ack && !o_wb_err && !i_wb_cyc
+			&& f_never_abort);
+	// }}}
+
+	// }}}
+`endif // FORMAL
+// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/wbp2classic.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbp2classic.v
new file mode 100644
index 0000000..0e465f1
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbp2classic.v
@@ -0,0 +1,164 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	wbp2classic.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	Takes a WB pipelined connection from a master, and converts it
+//		to WB classic for the slave.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module	wbp2classic(i_clk, i_reset,
+		i_mcyc, i_mstb, i_mwe, i_maddr, i_mdata, i_msel,
+			o_mstall, o_mack, o_mdata, o_merr,
+		o_scyc, o_sstb, o_swe, o_saddr, o_sdata, o_ssel,
+			i_sack, i_sdata, i_serr,
+			o_scti, o_sbte);
+	parameter	AW = 12,
+			DW = 32;
+	//
+	input	wire	i_clk, i_reset;
+	//
+	// Incoming WB pipelined port
+	input	wire			i_mcyc, i_mstb, i_mwe;
+	input	wire	[AW-1:0]	i_maddr;
+	input	wire	[DW-1:0]	i_mdata;
+	input	wire	[DW/8-1:0]	i_msel;
+	output	reg			o_mstall, o_mack;
+	output	reg	[DW-1:0]	o_mdata;
+	output	reg			o_merr;
+	//
+	// Outgoing WB classic port
+	output	reg			o_scyc, o_sstb, o_swe;
+	output	reg	[AW-1:0]	o_saddr;
+	output	reg	[DW-1:0]	o_sdata;
+	output	reg	[DW/8-1:0]	o_ssel;
+	input	wire			i_sack;
+	input	wire	[DW-1:0]	i_sdata;
+	input	wire			i_serr;
+	// Extra wires, not necessarily necessary for WB/B3
+	output	reg	[2:0]		o_scti;
+	output	reg	[1:0]		o_sbte;
+
+	//
+	// returned = whether we've received our return value or not.
+	reg	returned;
+
+	always @(*)
+	begin
+		o_scyc  = i_mcyc;
+		o_sstb  = i_mstb && !returned;
+		o_swe   = i_mwe;
+		o_saddr = i_maddr;
+		o_sdata = i_mdata;
+		o_ssel  = i_msel;
+
+		// Cycle type indicator: Classic
+		o_scti = 3'b000;
+		// Burst type indicator--ignored for single transaction cycle
+		// types, such as the classic type above
+		o_sbte = 2'b00; // Linear burst
+	end
+
+	initial	returned = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+		returned <= 0;
+	else if (!i_mstb || returned)
+		returned <= 0;
+	else if (i_sack || i_serr)
+		returned <= 1;
+
+	always @(*)
+		o_mstall = !returned;
+
+	initial	o_mack = 0;
+	initial	o_merr = 0;
+	always @(posedge i_clk)
+	if (i_reset)
+	begin
+		o_mack <= 0;
+		o_merr <= 0;
+	end else begin
+		o_mack <= (i_mcyc) && i_sack;
+		o_merr <= (i_mcyc) && i_serr;
+	end
+
+	always @(posedge i_clk)
+	if (i_sack || i_serr)
+		o_mdata <= i_sdata;
+
+
+`ifdef	FORMAL
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	localparam	F_LGDEPTH = 1;
+	reg	[F_LGDEPTH-1:0]	f_nreqs, f_nacks, f_outstanding;
+
+	reg	f_past_valid;
+	initial	f_past_valid = 0;
+	always @(posedge i_clk)
+		f_past_valid = 1;
+
+	always @(*)
+	if (!f_past_valid)
+		assume(i_reset);
+
+	fwb_slave #(.AW(AW), .DW(DW),
+			.F_MAX_STALL(4),
+			.F_MAX_ACK_DELAY(15),
+			.F_LGDEPTH(1)) incoming (i_clk, i_reset,
+		i_mcyc, i_mstb, i_mwe, i_maddr, i_mdata, i_msel,
+			o_mack, o_mstall, o_mdata, o_merr,
+			f_nreqs, f_nacks, f_outstanding);
+
+	fwbc_master #(.AW(AW), .DW(DW), .F_MAX_DELAY(3))
+	classic (i_clk, i_reset,
+		o_scyc, o_sstb, o_swe, o_saddr, o_sdata, o_ssel, o_scti, o_sbte,
+			i_sack, i_sdata, i_serr, 1'b0);
+
+	//
+	// Disallow bus aborts
+	reg	f_ongoing;
+	always @(posedge i_clk)
+		f_ongoing <= (!i_reset && i_mstb && !(o_mack | o_merr));
+
+	always @(*)
+	if (f_ongoing)
+		assume(i_mstb);
+`endif
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/wbsafety.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbsafety.v
new file mode 100644
index 0000000..3699a89
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbsafety.v
@@ -0,0 +1,525 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	wbsafety.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	A WB bus fault isolator.  This core will isolate any downstream
+//		WB slave faults from the upstream channel.  It sits as a bump
+//	in the wire between upstream and downstream channels, and so it will
+//	consume two clocks--slowing down the slave, but potentially allowing
+//	the developer to recover in case of a fault.
+//
+//	This core is configured by a couple parameters, which are key to its
+//	functionality.
+//
+//	OPT_TIMEOUT	Set this to a number to be roughly the longest time
+//		period you expect the slave to stall the bus, or likewise
+//		the longest time period you expect it to wait for a response.
+//		If the slave takes longer for either task, a fault will be
+//		detected and reported.
+//
+//	OPT_SELF_RESET	If set, this will send a reset signal to the downstream
+//		core so that you can attempt to restart it without reloading
+//		the FPGA.  If set, the o_reset signal will be used to reset
+//		the downstream core.
+//
+//	A second key feature of this core is the outgoing fault detector,
+//	o_fault.  If this signal is ever raised, the slave has (somehow)
+//	violated protocol.  Such a violation may (or may not) return an
+//	error upstream.  For example, if the slave returns a response
+//	following no requests from the master, then no error will be returned
+//	up stream (doing so would be a protocol violation), but a fault will
+//	be detected.  Use this line to trigger any internal logic analyzers.
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+//
+module wbsafety(i_clk, i_reset,
+		//
+		// The incoming WB interface from the (trusted) master
+		// This interface is guaranteed to follow the protocol.
+		i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel,
+			o_wb_stall, o_wb_ack, o_wb_idata, o_wb_err,
+		//
+		// The outgoing interface to the untrusted slave
+		// This interface may or may not follow the WB protocol
+		o_reset, o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data,
+			o_wb_sel,
+		i_wb_stall, i_wb_ack, i_wb_idata, i_wb_err,
+		//
+		// The fault signal, indicating the downstream slave was
+		// misbehaving
+		o_fault);
+	parameter	AW = 28, DW = 32;
+	parameter	OPT_TIMEOUT = 12;
+	parameter	MAX_DEPTH = (OPT_TIMEOUT);
+	localparam	LGTIMEOUT = $clog2(OPT_TIMEOUT+1);
+	localparam	LGDEPTH   = $clog2(MAX_DEPTH+1);
+	parameter [0:0]	OPT_SELF_RESET = 1'b1;
+	parameter [0:0]	F_OPT_FAULTLESS = 1'b1;
+	//
+	input	wire	i_clk, i_reset;
+	//
+	input	wire			i_wb_cyc, i_wb_stb, i_wb_we;
+	input	wire	[AW-1:0]	i_wb_addr;
+	input	wire	[DW-1:0]	i_wb_data;
+	input	wire	[DW/8-1:0]	i_wb_sel;
+	output	reg			o_wb_ack, o_wb_err, o_wb_stall;
+	output	reg	[DW-1:0]	o_wb_idata;
+	//
+	output	reg			o_reset;
+	output	reg			o_wb_cyc, o_wb_stb, o_wb_we;
+	output	reg	[AW-1:0]	o_wb_addr;
+	output	reg	[DW-1:0]	o_wb_data;
+	output	reg	[DW/8-1:0]	o_wb_sel;
+	input	wire			i_wb_ack, i_wb_err, i_wb_stall;
+	input	wire	[DW-1:0]	i_wb_idata;
+	//
+	output	reg			o_fault;
+
+	reg			none_expected;
+	reg	[LGDEPTH-1:0]	expected_returns;
+	reg	[LGTIMEOUT-1:0]	stall_timer, wait_timer;
+	reg			timeout;
+	reg			faulty_return;
+
+	wire			skd_stb, skd_o_ready, skd_we;
+	reg			skd_stall;
+	wire	[AW-1:0]	skd_addr;
+	wire	[DW-1:0]	skd_data;
+	wire	[DW/8-1:0]	skd_sel;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Start with a skid buffer on all incoming signals
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+`ifdef	FORMAL
+	//
+	// We know the skid buffer works.  It's irrelevant to our proof.
+	// Therefore, remove it during formal testing, lest we need to
+	// check it as well.  Further, we make this a parameter--but only
+	// when FORMAL is defined--so that it may be overridden in that case.
+	//
+	parameter	[0:0]	SKID_PASSTHROUGH = 1'b1;
+`else
+	localparam	[0:0]	SKID_PASSTHROUGH = 1'b0;
+`endif
+
+	skidbuffer #(.DW(1+AW+DW+(DW/8)),
+		.OPT_PASSTHROUGH(SKID_PASSTHROUGH))
+	skd(i_clk, i_reset || !i_wb_cyc, i_wb_stb, skd_o_ready,
+		{ i_wb_we, i_wb_addr, i_wb_data, i_wb_sel },
+		skd_stb, !skd_stall, { skd_we, skd_addr, skd_data, skd_sel });
+
+	always @(*)
+		o_wb_stall = !skd_o_ready;
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Timeout checking
+	//
+
+
+	//
+	// Insist on a maximum number of downstream stalls
+	//
+	initial	stall_timer = 0;
+	always @(posedge i_clk)
+	if (!i_reset && o_wb_stb && i_wb_stall)
+	begin
+		if (stall_timer <= OPT_TIMEOUT)
+			stall_timer <= stall_timer + 1;
+	end else 
+		stall_timer <= 0;
+
+	//
+	// Insist on a maximum number cyles waiting for an acknowledgment
+	//
+	initial	wait_timer = 0;
+	always @(posedge i_clk)
+	if (!i_reset && o_wb_cyc && !o_wb_stb && !i_wb_ack && !i_wb_err
+		&& !none_expected)
+	begin
+		if (wait_timer <= OPT_TIMEOUT)
+			wait_timer <= wait_timer + 1;
+	end else
+		wait_timer <= 0;
+
+	//
+	// Generate a timeout signal on any error
+	//
+	initial	timeout = 0;
+	always @(posedge i_clk)
+	if (timeout && o_wb_err)
+		timeout <= 0;
+	else
+		timeout <= (i_wb_stall)&&(stall_timer >= OPT_TIMEOUT)
+			|| ((!i_wb_ack && !i_wb_err)&&(wait_timer >= OPT_TIMEOUT));
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Return counting
+	//
+
+	initial	none_expected = 1;
+	initial	expected_returns = 0;
+	always @(posedge i_clk)
+	if (i_reset || o_reset || o_wb_err || !i_wb_cyc)
+	begin
+		expected_returns <= 0;
+		none_expected    <= 1;
+	end else case({skd_stb && !skd_stall, o_wb_ack })
+	2'b10: begin
+		expected_returns <= expected_returns + 1;
+		none_expected <= 1'b0;
+		end
+	2'b01: begin
+		expected_returns <= expected_returns - 1;
+		none_expected <= (expected_returns == 1);
+		end
+	default: begin end
+	endcase
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Downstream reset generation
+	//
+	generate if (OPT_SELF_RESET)
+	begin
+
+		initial	o_reset = 1;
+		always @(posedge i_clk)
+		if (i_reset || o_fault)
+			o_reset <= 1;
+		else begin
+			o_reset <= 0;
+			if (o_wb_cyc && none_expected
+					&&(i_wb_ack || i_wb_err))
+				o_reset <= 1;
+			if (timeout)
+				o_reset <= 1;
+		end
+	end else begin
+
+		always @(*)
+			o_reset = i_reset || o_fault;
+
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Fault detection
+	//
+
+	//
+	// A faulty return is a response from the slave at a time, or in
+	// a fashion that it unexpected and violates protocol
+	//
+	always @(*)
+	begin
+		faulty_return = 0;
+		if (expected_returns <= ((o_wb_stb && i_wb_stall) ? 1:0)
+				+ ((o_wb_ack || o_wb_err) ? 1:0))
+			faulty_return = i_wb_ack || i_wb_err;
+		if (i_wb_ack && i_wb_err)
+			faulty_return = 1;
+		if (!i_wb_cyc || !o_wb_cyc)
+			faulty_return = 0;
+	end
+
+	initial	o_fault = 0;
+	always @(posedge i_clk)
+	if (o_reset && !i_wb_cyc)
+		o_fault <= 0;
+	else begin
+		if (o_wb_cyc && faulty_return)
+			o_fault <= 1;
+		if (i_wb_cyc && timeout)
+			o_fault <= 1;
+	end
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Downstream bus signal generation
+	//
+
+	initial	o_wb_cyc = 1'b0;
+	always @(posedge i_clk)
+	if (i_reset || (o_wb_cyc && i_wb_err) || o_reset || o_fault
+			|| (i_wb_cyc && o_wb_err))
+		o_wb_cyc <= 1'b0;
+	else
+		o_wb_cyc  <= i_wb_cyc && (o_wb_cyc || i_wb_stb);
+
+	initial	o_wb_stb = 1'b0;
+	always @(posedge i_clk)
+	if (i_reset || (o_wb_cyc && i_wb_err) || o_reset || o_fault || !i_wb_cyc
+			|| (i_wb_cyc && o_wb_err))
+		o_wb_stb <= 1'b0;
+	else if (!o_wb_stb || !i_wb_stall)
+		o_wb_stb  <= skd_stb;
+
+	always @(posedge i_clk)
+	if (!o_wb_stb || !i_wb_stall)
+	begin
+		o_wb_we   <= skd_we;
+		o_wb_addr <= skd_addr;
+		o_wb_data <= skd_data;
+		o_wb_sel  <= skd_sel;
+	end
+
+	always @(posedge i_clk)
+		o_wb_idata <= i_wb_idata;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Return signal generation
+	//
+
+	always @(*)
+	begin
+		skd_stall = (o_wb_stb && i_wb_stall);
+		if (i_reset)
+			skd_stall = 1'b1;
+		if (o_fault)
+			skd_stall = 1'b0;
+		else if (o_reset)
+			skd_stall = 1'b1;
+	end
+
+	initial	o_wb_ack   = 0;
+	initial	o_wb_err   = 0;
+	always @(posedge i_clk)
+	if (i_reset || !i_wb_cyc)
+	begin
+		o_wb_ack   <= 1'b0;
+		o_wb_err   <= 1'b0;
+	end else if (!o_reset && !o_fault)
+	begin
+		if (timeout || faulty_return || i_wb_err)
+		begin
+			o_wb_ack <= 1'b0;
+			o_wb_err <= (expected_returns > ((o_wb_ack||o_wb_err) ? 1:0));
+		end else begin
+			o_wb_ack <= o_wb_cyc && i_wb_ack && !i_wb_err;
+			o_wb_err <= 1'b0;
+		end
+	end else begin
+		o_wb_ack   <= 1'b0;
+		o_wb_err   <= (i_wb_stb && !skd_stall);
+	end
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal property section
+//
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	//
+	// The following proof comes in several parts.
+	//
+	// 1. PROVE that the upstream properties will hold independent of
+	//	what the downstream slave ever does.
+	//
+	// 2. PROVE that if the downstream slave follows protocol, then
+	//	o_fault will never get raised.
+	//
+	// We then repeat these proofs again with both OPT_SELF_RESET set and
+	// clear.  Which of the four proofs is accomplished is dependent upon
+	// parameters set by the formal engine. 
+	//
+	//
+	localparam	DOWNSTREAM_ACK_DELAY = OPT_TIMEOUT/2-1;
+	localparam	UPSTREAM_ACK_DELAY = OPT_TIMEOUT + 3;
+	wire	[LGDEPTH-1:0]	fwbs_nreqs, fwbs_nacks, fwbs_outstanding;
+
+	reg	f_past_valid;
+	initial	f_past_valid = 0;
+	always @(posedge i_clk)
+		f_past_valid <= 1;
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Upstream master Bus properties
+	//
+	always @(*)
+	if (!f_past_valid)
+		assume(i_reset);
+
+	fwb_slave #(.AW(AW), .DW(DW),
+		// .F_MAX_ACK_DELAY(UPSTREAM_ACK_DELAY),
+		.F_LGDEPTH(LGDEPTH),
+		.F_OPT_DISCONTINUOUS(1),
+		.F_OPT_MINCLOCK_DELAY(0)
+	) wbs (i_clk, i_reset,
+		i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel,
+			o_wb_ack, o_wb_stall, o_wb_idata, o_wb_err,
+		fwbs_nreqs, fwbs_nacks, fwbs_outstanding
+	);
+
+	always @(*)
+		assert(none_expected == (expected_returns == 0));
+
+	// Just so we pass the skid buffer's assumptions ...
+	always @(posedge i_clk)
+	if (f_past_valid && $past(i_wb_stb && o_wb_stall))
+		assume($stable(i_wb_data));
+
+	always @(*)
+	if (i_wb_cyc && !o_wb_err && !o_fault)
+		assert(expected_returns == fwbs_outstanding);
+
+	generate if (F_OPT_FAULTLESS)
+	begin
+		////////////////////////////////////////////////////////////////
+		//
+		// Assume the downstream core is protocol compliant, and
+		// prove that o_fault stays low.
+		//
+		wire	[LGDEPTH-1:0]	fwbm_nreqs, fwbm_nacks,fwbm_outstanding;
+		reg	[LGDEPTH-1:0]	mreqs, sacks;
+
+
+		fwb_master #(.AW(AW), .DW(DW),
+			.F_MAX_ACK_DELAY(DOWNSTREAM_ACK_DELAY),
+			.F_MAX_STALL(DOWNSTREAM_ACK_DELAY),
+			.F_LGDEPTH(LGDEPTH),
+			.F_OPT_DISCONTINUOUS(1),
+			.F_OPT_MINCLOCK_DELAY(0)
+		) wbm (i_clk, o_reset,
+			o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data,
+				o_wb_sel,
+			i_wb_ack, i_wb_stall, i_wb_idata, i_wb_err,
+			fwbm_nreqs, fwbm_nacks, fwbm_outstanding);
+
+		//
+		// Here's the big proof
+		always @(*)
+			assert(!o_fault);
+
+		////////////////////////////////////////////////////////////////
+		//
+		// The following properties are necessary for passing induction
+		//
+		always @(*)
+		if (!i_reset && i_wb_cyc && o_wb_cyc)
+			assert(expected_returns == fwbm_outstanding
+				+ (o_wb_stb ? 1:0)
+				+ ((o_wb_ack|o_wb_err) ? 1:0));
+
+		always @(*)
+			assert(!timeout);
+
+		always @(*)
+		if (o_wb_err)
+			assert(!o_wb_cyc);
+
+		always @(*)
+			sacks = fwbs_nacks + (o_wb_ack ? 1:0);
+
+		always @(*)
+		if (!o_wb_err && i_wb_cyc && o_wb_cyc)
+			assert(sacks == fwbm_nacks);
+
+		always @(posedge i_clk)
+		if (!i_reset && i_wb_cyc && expected_returns > 0)
+			assert(o_wb_cyc || o_wb_err);
+
+		always @(*)
+			mreqs = fwbm_nreqs + (o_wb_stb ? 1:0);
+
+		always @(*)
+		if (!o_wb_err && i_wb_cyc && o_wb_cyc)
+			assert(fwbs_nreqs == mreqs);
+
+		always @(*)
+		if (i_wb_cyc && o_wb_cyc && fwbs_outstanding > 0)
+			assert(i_wb_we == o_wb_we);
+
+		always @(*)
+		if (fwbs_nacks != 0 && i_wb_cyc)
+			assert(o_wb_cyc || o_wb_err);
+
+	end else begin
+		////////////////////////////////////////////////////////////////
+		//
+		// cover() checks, checks that only make sense if faults are
+		// possible
+		//
+
+		always @(posedge i_clk)
+			cover(o_fault);
+
+		always @(posedge i_clk)
+		if (f_past_valid && $past(faulty_return))
+			cover(o_fault);
+
+		always @(posedge i_clk)
+		if (f_past_valid && $past(timeout))
+			cover(o_fault);
+
+		if (OPT_SELF_RESET)
+		begin
+			////////////////////////////////////////////////////////
+			//
+			// Prove that we can actually reset the downstream
+			// bus/core as desired
+			//
+			reg	faulted;
+
+			initial	faulted = 0;
+			always @(posedge i_clk)
+			if (i_reset)
+				faulted <= 0;
+			else if (o_fault)
+				faulted <= 1;
+
+
+			always @(posedge i_clk)
+				cover(faulted && $fell(o_reset));
+
+			always @(posedge i_clk)
+				cover(faulted && !o_reset && o_wb_ack);
+
+		end
+
+	end endgenerate
+
+	always @(*)
+		cover(!i_reset && fwbs_nacks > 4);
+
+`endif
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/wbxbar.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbxbar.v
new file mode 100644
index 0000000..bb155ea
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbxbar.v
@@ -0,0 +1,1638 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	wbxbar.v
+//
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	A Configurable wishbone cross-bar interconnect, conforming
+//		to the WB-B4 pipeline specification, as described on the
+//	ZipCPU blog.
+//
+// Performance:
+//	Throughput: One transaction per clock
+//	Latency: One clock to get access to an unused channel, another to
+//	place the results on the slave bus, and another to return, or a minimum
+//	of three clocks.
+//
+// Usage: To use, you'll need to set NM and NS to the number of masters
+//	(input ports) and the number of slaves respectively.  You'll then
+//	want to set the addresses for the slaves in the SLAVE_ADDR array,
+//	together with the SLAVE_MASK array indicating which SLAVE_ADDRs
+//	are valid.  Address and data widths should be adjusted at the same
+//	time.
+//
+//	Voila, you are now set up!
+//
+//	Now let's fine tune this:
+//
+//	LGMAXBURST can be set to control the maximum number of outstanding
+//	transactions.  An LGMAXBURST of 6 will allow 63 outstanding
+//	transactions.
+//
+//	OPT_TIMEOUT, if set to a non-zero value, is a number of clock periods
+//	to wait for a slave to respond.  Should the timeout expire and the
+//	slave not respond, a bus error will be returned and the slave will
+//	be issued a bus abort signal (CYC will be dropped).
+//
+//	OPT_STARVATION_TIMEOUT, if set, applies the OPT_TIMEOUT counter to
+//	how long a particular master waits for arbitration.  If the master is
+//	"starved", a bus error will be returned.
+//
+//	OPT_DBLBUFFER is used to increase clock speed by registering all
+//	outputs.
+//
+//	OPT_LOWPOWER is an experimental feature that, if set, will cause any
+//	unused FFs to be set to zero rather than flopping in the electronic
+//	wind, in an effort to minimize transitions over bus wires.  This will
+//	cost some extra logic, for ... an uncertain power savings.
+//
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2019-2020, Gisselquist Technology, LLC
+//
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+module	wbxbar(i_clk, i_reset,
+	i_mcyc, i_mstb, i_mwe, i_maddr, i_mdata, i_msel,
+		o_mstall, o_mack, o_mdata, o_merr,
+	o_scyc, o_sstb, o_swe, o_saddr, o_sdata, o_ssel,
+		i_sstall, i_sack, i_sdata, i_serr);
+	parameter	NM = 4, NS=8;
+	parameter	AW = 32, DW=32;
+	parameter	[NS*AW-1:0]	SLAVE_ADDR = {
+				{ 3'b111, {(AW-3){1'b0}}},
+				{ 3'b110, {(AW-3){1'b0}}},
+				{ 3'b101, {(AW-3){1'b0}}},
+				{ 3'b100, {(AW-3){1'b0}}},
+				{ 3'b011, {(AW-3){1'b0}}},
+				{ 3'b010, {(AW-3){1'b0}}},
+				{ 4'b0010, {(AW-4){1'b0}}},
+				{ 4'b0000, {(AW-4){1'b0}}} };
+	parameter	[NS*AW-1:0]	SLAVE_MASK = (NS <= 1) ? 0
+		: { {(NS-2){ 3'b111, {(AW-3){1'b0}}}},
+			{(2){ 4'b1111, {(AW-4){1'b0}} }} };
+	//
+	// LGMAXBURST is the log_2 of the length of the longest burst that
+	// might be seen.  It's used to set the size of the internal
+	// counters that are used to make certain that the cross bar doesn't
+	// switch while still waiting on a response.
+	parameter	LGMAXBURST=6;
+	//
+	// OPT_TIMEOUT is used to help recover from a misbehaving slave.  If
+	// set, this value will determine the number of clock cycles to wait
+	// for a misbehaving slave before returning a bus error.  Alternatively,
+	// if set to zero, this functionality will be removed.
+	parameter	OPT_TIMEOUT = 0; // 1023;
+	//
+	// If OPT_TIMEOUT is set, then OPT_STARVATION_TIMEOUT may also be set.
+	// The starvation timeout adds to the bus error timeout generation
+	// the possibility that a master will wait OPT_TIMEOUT counts without
+	// receiving the bus.  This may be the case, for example, if one
+	// bus master is consuming a peripheral to such an extent that there's
+	// no time/room for another bus master to use it.  In that case, when
+	// the timeout runs out, the waiting bus master will be given a bus
+	// error.
+	parameter [0:0]	OPT_STARVATION_TIMEOUT = 1'b0 && (OPT_TIMEOUT > 0);
+	//
+	// TIMEOUT_WIDTH is the number of bits in counter used to check on a
+	// timeout.
+	localparam	TIMEOUT_WIDTH = $clog2(OPT_TIMEOUT);
+	//
+	// OPT_DBLBUFFER is used to register all of the outputs, and thus
+	// avoid adding additional combinational latency through the core
+	// that might require a slower clock speed.
+	parameter [0:0]	OPT_DBLBUFFER = 1'b0;
+	//
+	// OPT_LOWPOWER adds logic to try to force unused values to zero,
+	// rather than to allow a variety of logic optimizations that could
+	// be used to reduce the logic count of the device.  Hence, OPT_LOWPOWER
+	// will use more logic, but it won't drive bus wires unless there's a
+	// value to drive onto them.
+	parameter [0:0]	OPT_LOWPOWER = 1'b1;
+	//
+	// LGNM is the log (base two) of the number of bus masters connecting
+	// to this crossbar
+	localparam	LGNM = (NM>1) ? $clog2(NM) : 1;
+	//
+	// LGNM is the log (base two) of the number of slaves plus one come
+	// out of the system.  The extra "plus one" is used for a pseudo slave
+	// representing the case where the given address doesn't connect to
+	// any of the slaves.  This address will generate a bus error.
+	localparam	LGNS = $clog2(NS+1);
+	//
+	//
+	input	wire			i_clk, i_reset;
+	//
+	// Here are the bus inputs from each of the WB bus masters
+	input	wire	[NM-1:0]	i_mcyc, i_mstb, i_mwe;
+	input	wire	[NM*AW-1:0]	i_maddr;
+	input	wire	[NM*DW-1:0]	i_mdata;
+	input	wire	[NM*DW/8-1:0]	i_msel;
+	//
+	// .... and their return data
+	output	reg	[NM-1:0]	o_mstall, o_mack, o_merr;
+	output	reg	[NM*DW-1:0]	o_mdata;
+	//
+	//
+	// Here are the output ports, used to control each of the various
+	// slave ports that we are connected to
+	output	reg	[NS-1:0]	o_scyc, o_sstb, o_swe;
+	output	reg	[NS*AW-1:0]	o_saddr;
+	output	reg	[NS*DW-1:0]	o_sdata;
+	output	reg	[NS*DW/8-1:0]	o_ssel;
+	//
+	// ... and their return data back to us.
+	input	wire	[NS-1:0]	i_sstall, i_sack, i_serr;
+	input	wire	[NS*DW-1:0]	i_sdata;
+	//
+	//
+
+	// At one time I used o_macc and o_sacc to put into the outgoing
+	// trace file, just enough logic to tell me if a transaction was
+	// taking place on the given clock.
+	//
+	// assign	o_macc = (i_mstb & ~o_mstall);
+	// assign	o_sacc = (o_sstb & ~i_sstall);
+	//
+	// These definitions work with Veri1ator, just not with Yosys
+	// reg	[NM-1:0][NS:0]		request;
+	// reg	[NM-1:0][NS-1:0]	requested;
+	// reg	[NM-1:0][NS:0]		grant;
+	//
+	// These definitions work with both
+	wire	[NS:0]			request		[0:NM-1];
+	reg	[NS-1:0]		requested	[0:NM-1];
+	reg	[NS:0]			grant		[0:NM-1];
+	reg	[NM-1:0]		mgrant;
+	reg	[NS-1:0]		sgrant;
+
+	// Verilator lint_off UNUSED
+	wire	[LGMAXBURST-1:0]	w_mpending [0:NM-1];
+	// Verilator lint_on  UNUSED
+	reg	[NM-1:0]		mfull, mnearfull, mempty, timed_out;
+
+	localparam	NMFULL = (NM > 1) ? (1<<LGNM) : 1;
+	localparam	NSFULL = (1<<LGNS);
+
+	reg	[LGNS-1:0]	mindex		[0:NMFULL-1];
+	reg	[LGNM-1:0]	sindex		[0:NSFULL-1];
+
+	reg	[NMFULL-1:0]	m_cyc;
+	reg	[NMFULL-1:0]	m_stb;
+	wire	[NMFULL-1:0]	m_we;
+	wire	[AW-1:0]	m_addr		[0:NMFULL-1];
+	wire	[DW-1:0]	m_data		[0:NMFULL-1];
+	wire	[DW/8-1:0]	m_sel		[0:NMFULL-1];
+	reg	[NM-1:0]	m_stall;
+	//
+	reg	[NSFULL-1:0]	s_stall;
+	reg	[DW-1:0]	s_data		[0:NSFULL-1];
+	reg	[NSFULL-1:0]	s_ack;
+	reg	[NSFULL-1:0]	s_err;
+	wire	[NM-1:0]	dcd_stb;
+
+	localparam [0:0]	OPT_BUFFER_DECODER = (NS != 1 || SLAVE_MASK != 0);
+
+	genvar	N, M;
+	integer	iN, iM;
+	generate for(N=0; N<NM; N=N+1)
+	begin : DECODE_REQUEST
+		wire			skd_stb, skd_stall;
+		wire			skd_we;
+		wire	[AW-1:0]	skd_addr;
+		wire	[DW-1:0]	skd_data;
+		wire	[DW/8-1:0]	skd_sel;
+		wire	[NS:0]		decoded;
+		wire			iskd_ready;
+
+		skidbuffer #(
+			//
+			// Can't run OPT_LOWPOWER here, less we mess up the
+			// consistency in skd_we following
+			//
+			// .OPT_LOWPOWER(OPT_LOWPOWER),
+			.DW(1+AW+DW+DW/8),
+`ifdef	FORMAL
+			.OPT_PASSTHROUGH(1),
+`endif
+			.OPT_OUTREG(0))
+		iskid(i_clk, i_reset || !i_mcyc[N], i_mstb[N], iskd_ready,
+			{ i_mwe[N], i_maddr[N*AW +: AW], i_mdata[N*DW +: DW],
+					i_msel[N*DW/8 +: DW/8] },
+			skd_stb, !skd_stall,
+				{ skd_we, skd_addr, skd_data, skd_sel });
+
+		always @(*)
+			o_mstall[N] = !iskd_ready;
+
+		addrdecode #(
+			//
+			// Can't run OPT_LOWPOWER here, less we mess up the
+			// consistency in m_we following
+			//
+			// .OPT_LOWPOWER(OPT_LOWPOWER),
+			.NS(NS), .AW(AW), .DW(DW+DW/8+1),
+			.SLAVE_ADDR(SLAVE_ADDR),
+			.SLAVE_MASK(SLAVE_MASK),
+			.OPT_REGISTERED(OPT_BUFFER_DECODER)
+		) adcd(i_clk, i_reset, skd_stb && i_mcyc[N], skd_stall,
+			skd_addr, { skd_we, skd_data, skd_sel },
+			dcd_stb[N], (m_stall[N]&&i_mcyc[N]),decoded, m_addr[N],
+				{ m_we[N], m_data[N], m_sel[N] });
+
+		assign	request[N] = (m_cyc[N] && dcd_stb[N]) ? decoded : 0;
+
+		always @(*)
+			m_cyc[N] = i_mcyc[N];
+		always @(*)
+		if (mfull[N])
+			m_stb[N] = 1'b0;
+		else
+			m_stb[N] = i_mcyc[N] && dcd_stb[N];
+
+	end for(N=NM; N<NMFULL; N=N+1)
+	begin
+		// in case NM isn't one less than a power of two, complete
+		// the set
+		always @(*)
+		begin
+			m_cyc[N]  = 0;
+			m_stb[N]  = 0;
+		end
+
+
+		assign	m_we[N]   = 0;
+		assign	m_addr[N] = 0;
+		assign	m_data[N] = 0;
+		assign	m_sel[N]  = 0;
+
+	end endgenerate
+
+	always @(*)
+	begin
+		for(iM=0; iM<NS; iM=iM+1)
+		begin
+			// For each slave
+			requested[0][iM] = 0;
+			for(iN=1; iN<NM; iN=iN+1)
+			begin
+				// This slave has been requested if a prior
+				// master has requested it
+				//
+				// This includes any master before the last one
+				requested[iN][iM] = requested[iN-1][iM];
+				//
+				// As well as if the last master has requested
+				// this slave.  Only count this request, though,
+				// if this master could act upon it.
+				if (request[iN-1][iM] &&
+					(grant[iN-1][iM]
+					|| (!mgrant[iN-1]||mempty[iN-1])))
+					requested[iN][iM] = 1;
+			end
+		end
+	end
+
+	generate for(M=0; M<NS; M=M+1)
+	begin : SLAVE_GRANT
+
+`define	REGISTERED_SGRANT
+`ifdef	REGISTERED_SGRANT
+		reg	drop_sgrant;
+		always @(*)
+		begin
+			drop_sgrant = !m_cyc[sindex[M]];
+			if (!request[sindex[M]][M] && m_stb[sindex[M]]
+				&& mempty[sindex[M]])
+				drop_sgrant = 1;
+			if (!sgrant[M])
+				drop_sgrant = 0;
+			if (i_reset)
+				drop_sgrant = 1;
+		end
+
+		initial	sgrant[M] = 0;
+		always @(posedge i_clk)
+		begin
+			sgrant[M] <= sgrant[M];
+			for(iN=0; iN<NM; iN=iN+1)
+			if (request[iN][M] && (!mgrant[iN] || mempty[iN]))
+				sgrant[M] <= 1;
+			if (drop_sgrant)
+				sgrant[M] <= 0;
+		end
+`else
+		always @(*)
+		begin
+			sgrant[M] = 0;
+			for(iN=0; iN<NM; iN=iN+1)
+				if (grant[iN][M])
+					sgrant[M] = 1;
+		end
+`endif
+
+		always @(*)
+			s_data[M]  = i_sdata[M*DW +: DW];
+		always @(*)
+			s_stall[M] = o_sstb[M] && i_sstall[M];
+		always @(*)
+			s_ack[M]   = o_scyc[M] && i_sack[M];
+		always @(*)
+			s_err[M]   = o_scyc[M] && i_serr[M];
+	end for(M=NS; M<NSFULL; M=M+1)
+	begin
+
+		always @(*)
+			s_data[M]  = 0;
+		always @(*)
+			s_stall[M] = 1;
+		always @(*)
+			s_ack[M]   = 0;
+		always @(*)
+			s_err[M]   = 1;
+		// always @(*) sgrant[M]  = 0;
+
+	end endgenerate
+
+	//
+	// Arbitrate among masters to determine who gets to access a given
+	// channel
+	generate for(N=0; N<NM; N=N+1)
+	begin : ARBITRATE_REQUESTS
+		reg	[NS:0]		regrant;
+		reg	[LGNS-1:0]	reindex;
+
+		// This is done using a couple of variables.
+		//
+		// request[N][M]
+		//	This is true if master N is requesting to access slave
+		//	M.  It is combinatorial, so it will be true if the
+		//	request is being made on the current clock.
+		//
+		// requested[N][M]
+		//	True if some other master, prior to N, has requested
+		//	channel M.  This creates a basic priority arbiter,
+		//	such that lower numbered masters have access before
+		//	a greater numbered master
+		//
+		// grant[N][M]
+		//	True if a grant has been made for master N to access
+		//	slave channel M
+		//
+		// mgrant[N]
+		//	True if master N has been granted access to some slave
+		//	channel, any channel.
+		//
+		// mindex[N]
+		//	This is the number of the slave channel that master
+		//	N has been given access to
+		//
+		// sgrant[M]
+		//	True if there exists some master, N, that has been
+		// 	granted access to this slave, hence grant[N][M] must
+		//	also be true
+		//
+		// sindex[M]
+		//	This is the index of the master that has access to
+		//	slave M, assuming sgrant[M].  Hence, if sgrant[M]
+		//	then grant[sindex[M]][M] must be true
+		//
+		reg	stay_on_channel;
+		reg	requested_channel_is_available;
+
+		always @(*)
+		begin
+			stay_on_channel = |(request[N] & grant[N]);
+
+			if (mgrant[N] && !mempty[N])
+				stay_on_channel = 1;
+		end
+
+		always @(*)
+		begin
+			requested_channel_is_available =
+			|(request[N][NS-1:0] & ~sgrant & ~requested[N][NS-1:0]);
+
+			if (request[N][NS])
+				requested_channel_is_available = 1;
+
+			if (NM < 2)
+				requested_channel_is_available = m_stb[N];
+		end
+
+		initial	grant[N] = 0;
+		initial	mgrant[N] = 0;
+		always @(posedge i_clk)
+		if (i_reset || !i_mcyc[N])
+		begin
+			grant[N] <= 0;
+			mgrant[N] <= 0;
+		end else if (!stay_on_channel)
+		begin
+			if (requested_channel_is_available)
+			begin
+				mgrant[N] <= 1'b1;
+				grant[N] <= request[N];
+			end else if (m_stb[N])
+			begin
+				mgrant[N] <= 1'b0;
+				grant[N]  <= 0;
+			end
+		end
+
+		if (NS == 1)
+		begin
+
+			always @(*)
+				mindex[N] = 0;
+
+			always @(*)
+				regrant = 0;
+
+			always @(*)
+				reindex = 0;
+
+		end else begin
+`define	NEW_MINDEX_CODE
+`ifdef	NEW_MINDEX_CODE
+
+			always @(*)
+			begin
+				regrant = 0;
+				for(iM=0; iM<NS; iM=iM+1)
+				begin
+					if (grant[N][iM])
+						// Maintain any open channels
+						regrant[iM] = 1'b1;
+					else if (!sgrant[iM]&&!requested[N][iM])
+						regrant[iM] = 1'b1;
+
+					if (!request[N][iM])
+						regrant[iM] = 1'b0;
+				end
+
+				if (grant[N][NS])
+					regrant[NS] = 1;
+				if (!request[N][NS])
+					regrant[NS] = 0;
+
+				if (mgrant[N] && !mempty[N])
+					regrant = 0;
+			end
+
+			always @(*)
+			begin
+				reindex = 0;
+				for(iM=0; iM<=NS; iM=iM+1)
+				if (regrant[iM])
+					reindex = reindex | iM[LGNS-1:0];
+				if (regrant == 0)
+					reindex = mindex[N];
+			end
+
+			always @(posedge i_clk)
+				mindex[N] <= reindex;
+`else
+			always @(posedge i_clk)
+			if (!mgrant[N] || mempty[N])
+			begin
+
+				for(iM=0; iM<NS; iM=iM+1)
+				begin
+					if (request[N][iM] && grant[N][iM])
+					begin
+						// Maintain any open channels
+						mindex[N] <= iM;
+					end else if (request[N][iM]
+							&& !sgrant[iM]
+							&& !requested[N][iM])
+					begin
+						// Open a new channel
+						// if necessary
+						mindex[N] <= iM;
+					end
+				end
+			end
+`endif // NEW_MINDEX_CODE
+		end
+
+	end for (N=NM; N<NMFULL; N=N+1)
+	begin
+
+		always @(*)
+			mindex[N] = 0;
+
+	end endgenerate
+
+	// Calculate sindex.  sindex[M] (indexed by slave ID)
+	// references the master controlling this slave.  This makes for
+	// faster/cheaper logic on the return path, since we can now use
+	// a fully populated LUT rather than a priority based return scheme
+	generate for(M=0; M<NS; M=M+1)
+	begin
+
+		if (NM <= 1)
+		begin
+
+			// If there will only ever be one master, then we
+			// can assume all slave indexes point to that master
+			always @(*)
+				sindex[M] = 0;
+
+		end else begin : SINDEX_MORE_THAN_ONE_MASTER
+
+`define	NEW_SINDEX_CODE
+`ifdef	NEW_SINDEX_CODE
+			reg	[NM-1:0]	regrant;
+			reg	[LGNM-1:0]	reindex;
+
+			always @(*)
+			begin
+				regrant = 0;
+				for (iN=0; iN<NM; iN=iN+1)
+				begin
+					// Each bit depends upon 6 inputs, so
+					// one 6-LUT should be sufficient
+					if (grant[iN][M])
+						regrant[iN] = 1;
+					else if (!sgrant[M]&& !requested[iN][M])
+						regrant[iN] = 1;
+
+					if (!request[iN][M])
+						regrant[iN] = 0;
+					if (mgrant[iN] && !mempty[iN])
+						regrant[iN] = 0;
+				end
+			end
+
+			always @(*)
+			begin
+				reindex = 0;
+				// Each bit in reindex depends upon all of the
+				// bits in regrant--should still be one LUT
+				// per bit though
+				if (regrant == 0)
+					reindex = sindex[M];
+				else for(iN=0; iN<NM; iN=iN+1)
+					if (regrant[iN])
+						reindex = reindex | iN[LGNM-1:0];
+			end
+
+			always @(posedge i_clk)
+				sindex[M] <= reindex;
+`else
+			always @(posedge i_clk)
+			for (iN=0; iN<NM; iN=iN+1)
+			begin
+				if (!mgrant[iN] || mempty[iN])
+				begin
+					if (request[iN][M] && grant[iN][M])
+						sindex[M] <= iN;
+					else if (request[iN][M] && !sgrant[M]
+							&& !requested[iN][M])
+						sindex[M] <= iN;
+				end
+			end
+`endif
+		end
+
+	end for(M=NS; M<NSFULL; M=M+1)
+	begin
+		// Assign the unused slave indexes to zero
+		//
+		// Remember, to full out a full 2^something set of slaves,
+		// we may have more slave indexes than we actually have slaves
+
+		always @(*)
+			sindex[M] = 0;
+
+	end endgenerate
+
+
+	//
+	// Assign outputs to the slaves, part one
+	//
+	// In this part, we assign the difficult outputs: o_scyc and o_sstb
+	generate for(M=0; M<NS; M=M+1)
+	begin
+
+		initial	o_scyc[M] = 0;
+		initial	o_sstb[M] = 0;
+		always @(posedge i_clk)
+		begin
+			if (sgrant[M])
+			begin
+
+				if (!i_mcyc[sindex[M]])
+				begin
+					o_scyc[M] <= 1'b0;
+					o_sstb[M] <= 1'b0;
+				end else begin
+					o_scyc[M] <= 1'b1;
+
+					if (!o_sstb[M] || !s_stall[M])
+						o_sstb[M]<=request[sindex[M]][M]
+						  && !mfull[sindex[M]];
+				end
+			end else begin
+				o_scyc[M]  <= 1'b0;
+				o_sstb[M]  <= 1'b0;
+			end
+
+			if (i_reset || s_err[M])
+			begin
+				o_scyc[M] <= 1'b0;
+				o_sstb[M] <= 1'b0;
+			end
+		end
+	end endgenerate
+
+	//
+	// Assign outputs to the slaves, part two
+	//
+	// These are the easy(er) outputs, since there are fewer properties
+	// riding on them
+	generate if ((NM == 1) && (!OPT_LOWPOWER))
+	begin
+		reg			r_swe;
+		reg	[AW-1:0]	r_saddr;
+		reg	[DW-1:0]	r_sdata;
+		reg	[DW/8-1:0]	r_ssel;
+
+		//
+		// This is the low logic version of our bus data outputs.
+		// It only works if we only have one master.
+		//
+		// The basic idea here is that we share all of our bus outputs
+		// between all of the various slaves.  Since we only have one
+		// bus master, this works.
+		//
+		always @(posedge i_clk)
+		begin
+			r_swe   <= o_swe[0];
+			r_saddr <= o_saddr[0+:AW];
+			r_sdata <= o_sdata[0+:DW];
+			r_ssel  <=o_ssel[0+:DW/8];
+
+			// Verilator lint_off WIDTH
+			if (sgrant[mindex[0]] && !s_stall[mindex[0]])
+			// Verilator lint_on  WIDTH
+			begin
+				r_swe   <= m_we[0];
+				r_saddr <= m_addr[0];
+				r_sdata <= m_data[0];
+				r_ssel  <= m_sel[0];
+			end
+		end
+
+		//
+		// The original version set o_s*[0] above, and then
+		// combinatorially the rest of o_s* here below.  That broke
+		// Veri1ator.  Hence, we're using r_s* and setting all of o_s*
+		// here.
+		for(M=0; M<NS; M=M+1)
+		always @(*)
+		begin
+			o_swe[M]            = r_swe;
+			o_saddr[M*AW +: AW] = r_saddr[AW-1:0];
+			o_sdata[M*DW +: DW] = r_sdata[DW-1:0];
+			o_ssel[M*DW/8+:DW/8]= r_ssel[DW/8-1:0];
+		end
+
+	end else for(M=0; M<NS; M=M+1)
+	begin
+		always @(posedge i_clk)
+		begin
+			if (OPT_LOWPOWER && !sgrant[M])
+			begin
+				o_swe[M]              <= 1'b0;
+				o_saddr[M*AW   +: AW] <= 0;
+				o_sdata[M*DW   +: DW] <= 0;
+				o_ssel[M*(DW/8)+:DW/8]<= 0;
+			end else if (!s_stall[M]) begin
+				o_swe[M]              <= m_we[sindex[M]];
+				o_saddr[M*AW   +: AW] <= m_addr[sindex[M]];
+				if (OPT_LOWPOWER && !m_we[sindex[M]])
+					o_sdata[M*DW   +: DW] <= 0;
+				else
+					o_sdata[M*DW   +: DW] <= m_data[sindex[M]];
+				o_ssel[M*(DW/8)+:DW/8]<= m_sel[sindex[M]];
+			end
+
+		end
+	end endgenerate
+
+	//
+	// Assign return values to the masters
+	generate if (OPT_DBLBUFFER)
+	begin : DOUBLE_BUFFERRED_STALL
+
+		reg	[NM-1:0]	r_mack, r_merr;
+
+		for(N=0; N<NM; N=N+1)
+		begin
+			// m_stall isn't buffered, since it depends upon
+			// the already existing buffer within the address
+			// decoder
+			always @(*)
+			begin
+				if (grant[N][NS])
+					m_stall[N] = 1;
+				else if (mgrant[N] && request[N][mindex[N]])
+					m_stall[N] = mfull[N] || s_stall[mindex[N]];
+				else
+					m_stall[N] = m_stb[N];
+
+				if (o_merr[N])
+					m_stall[N] = 0;
+			end
+
+			initial	r_mack[N]   = 0;
+			initial	r_merr[N]   = 0;
+			always @(posedge i_clk)
+			begin
+				// Verilator lint_off WIDTH
+				iM = mindex[N];
+				// Verilator lint_on  WIDTH
+				r_mack[N]   <= mgrant[N] && s_ack[mindex[N]];
+				r_merr[N]   <= mgrant[N] && s_err[mindex[N]];
+				if (OPT_LOWPOWER && !mgrant[N])
+					o_mdata[N*DW +: DW] <= 0;
+				else
+					o_mdata[N*DW +: DW] <= s_data[mindex[N]];
+
+				if (grant[N][NS]||(timed_out[N] && !o_mack[N]))
+				begin
+					r_mack[N]   <= 1'b0;
+					r_merr[N]   <= !o_merr[N];
+				end
+
+				if (i_reset || !i_mcyc[N] || o_merr[N])
+				begin
+					r_mack[N]   <= 1'b0;
+					r_merr[N]   <= 1'b0;
+				end
+			end
+
+			always @(*)
+				o_mack[N] = r_mack[N];
+
+			always @(*)
+			if (!OPT_STARVATION_TIMEOUT || i_mcyc[N])
+				o_merr[N] = r_merr[N];
+			else
+				o_merr[N] = 1'b0;
+
+		end
+
+	end else if (NS == 1) // && !OPT_DBLBUFFER
+	begin : SINGLE_SLAVE
+
+		for(N=0; N<NM; N=N+1)
+		begin
+			always @(*)
+			begin
+				m_stall[N] = !mgrant[N] || s_stall[0]
+					|| (m_stb[N] && !request[N][0]);
+				o_mack[N]   =  mgrant[N] && i_sack[0];
+				o_merr[N]   =  mgrant[N] && i_serr[0];
+				o_mdata[N*DW +: DW]  = (!mgrant[N] && OPT_LOWPOWER)
+					? 0 : i_sdata;
+
+				if (mfull[N])
+					m_stall[N] = 1'b1;
+
+				if (timed_out[N]&&!o_mack[N])
+				begin
+					m_stall[N] = 1'b0;
+					o_mack[N]   = 1'b0;
+					o_merr[N]   = 1'b1;
+				end
+
+				if (grant[N][NS] && m_stb[N])
+				begin
+					m_stall[N] = 1'b0;
+					o_mack[N]   = 1'b0;
+					o_merr[N]   = 1'b1;
+				end
+
+				if (!m_cyc[N])
+				begin
+					o_mack[N] = 1'b0;
+					o_merr[N] = 1'b0;
+				end
+			end
+		end
+
+	end else begin : SINGLE_BUFFER_STALL
+		for(N=0; N<NM; N=N+1)
+		begin
+			// initial	o_mstall[N] = 0;
+			// initial	o_mack[N]   = 0;
+			always @(*)
+			begin
+				m_stall[N] = 1;
+				o_mack[N]   = mgrant[N] && s_ack[mindex[N]];
+				o_merr[N]   = mgrant[N] && s_err[mindex[N]];
+				if (OPT_LOWPOWER && !mgrant[N])
+					o_mdata[N*DW +: DW] = 0;
+				else
+					o_mdata[N*DW +: DW] = s_data[mindex[N]];
+
+				if (mgrant[N])
+					// Possibly lower the stall signal
+					m_stall[N] = s_stall[mindex[N]]
+					    || !request[N][mindex[N]];
+
+				if (mfull[N])
+					m_stall[N] = 1'b1;
+
+				if (grant[N][NS] ||(timed_out[N]&&!o_mack[N]))
+				begin
+					m_stall[N] = 1'b0;
+					o_mack[N]   = 1'b0;
+					o_merr[N]   = 1'b1;
+				end
+
+				if (!m_cyc[N])
+				begin
+					o_mack[N] = 1'b0;
+					o_merr[N] = 1'b0;
+				end
+			end
+		end
+
+	end endgenerate
+
+	//
+	// Count the pending transactions per master
+	generate for(N=0; N<NM; N=N+1)
+	begin : COUNT_PENDING_TRANSACTIONS
+
+		reg	[LGMAXBURST-1:0]	lclpending;
+		initial	lclpending  = 0;
+		initial	mempty[N]    = 1;
+		initial	mnearfull[N] = 0;
+		initial	mfull[N]     = 0;
+		always @(posedge i_clk)
+		if (i_reset || !i_mcyc[N] || o_merr[N])
+		begin
+			lclpending <= 0;
+			mfull[N]    <= 0;
+			mempty[N]   <= 1'b1;
+			mnearfull[N]<= 0;
+		end else case({ (m_stb[N] && !m_stall[N]), o_mack[N] })
+		2'b01: begin
+			lclpending <= lclpending - 1'b1;
+			mnearfull[N]<= mfull[N];
+			mfull[N]    <= 1'b0;
+			mempty[N]   <= (lclpending == 1);
+			end
+		2'b10: begin
+			lclpending <= lclpending + 1'b1;
+			mnearfull[N]<= (&lclpending[LGMAXBURST-1:2])&&(lclpending[1:0] != 0);
+			mfull[N]    <= mnearfull[N];
+			mempty[N]   <= 1'b0;
+			end
+		default: begin end
+		endcase
+
+		assign w_mpending[N] = lclpending;
+
+	end endgenerate
+
+	generate if (OPT_TIMEOUT > 0)
+	begin : CHECK_TIMEOUT
+
+		for(N=0; N<NM; N=N+1)
+		begin
+
+			reg	[TIMEOUT_WIDTH-1:0]	deadlock_timer;
+
+			initial	deadlock_timer = OPT_TIMEOUT;
+			initial	timed_out[N] = 0;
+			always @(posedge i_clk)
+			if (i_reset || !i_mcyc[N]
+					||((w_mpending[N] == 0) && !m_stb[N])
+					||(m_stb[N] && !m_stall[N])
+					||(o_mack[N] || o_merr[N])
+					||(!OPT_STARVATION_TIMEOUT&&!mgrant[N]))
+			begin
+				deadlock_timer <= OPT_TIMEOUT;
+				timed_out[N] <= 0;
+			end else if (deadlock_timer > 0)
+			begin
+				deadlock_timer <= deadlock_timer - 1;
+				timed_out[N] <= (deadlock_timer <= 1);
+			end
+		end
+
+	end else begin
+
+		always @(*)
+			timed_out = 0;
+
+	end endgenerate
+
+	initial	begin
+		if (NM == 0)
+		begin
+			$display("ERROR: At least one master must be defined");
+			$stop;
+		end
+
+		if (NS == 0)
+		begin
+			$display("ERROR: At least one slave must be defined");
+			$stop;
+		end
+
+		if (OPT_STARVATION_TIMEOUT != 0 && OPT_TIMEOUT == 0)
+		begin
+			$display("ERROR: The starvation timeout is implemented as part of the regular timeout");
+			$display("  Without a timeout, the starvation timeout will not work");
+			$stop;
+		end
+	end
+
+`ifdef	FORMAL
+	localparam	F_MAX_DELAY = 4;
+	localparam	F_LGDEPTH = LGMAXBURST;
+	//
+	reg			f_past_valid;
+	//
+	// Our bus checker keeps track of the number of requests,
+	// acknowledgments, and the number of outstanding transactions on
+	// every channel, both the masters driving us
+	wire	[F_LGDEPTH-1:0]	f_mreqs		[0:NM-1];
+	wire	[F_LGDEPTH-1:0]	f_macks		[0:NM-1];
+	wire	[F_LGDEPTH-1:0]	f_moutstanding	[0:NM-1];
+	//
+	// as well as the slaves that we drive ourselves
+	wire	[F_LGDEPTH-1:0]	f_sreqs		[0:NS-1];
+	wire	[F_LGDEPTH-1:0]	f_sacks		[0:NS-1];
+	wire	[F_LGDEPTH-1:0]	f_soutstanding	[0:NS-1];
+
+
+	initial	assert(!OPT_STARVATION_TIMEOUT || OPT_TIMEOUT > 0);
+
+	initial	f_past_valid = 0;
+	always @(posedge i_clk)
+		f_past_valid = 1'b1;
+
+	always @(*)
+	if (!f_past_valid)
+		assume(i_reset);
+
+	generate for(N=0; N<NM; N=N+1)
+	begin
+		always @(*)
+		if (f_past_valid)
+		for(iN=N+1; iN<NM; iN=iN+1)
+			// Can't grant the same channel to two separate
+			// masters.  This applies to all but the error or
+			// no-slave-selected channel
+			assert((grant[N][NS-1:0] & grant[iN][NS-1:0])==0);
+
+		for(M=1; M<=NS; M=M+1)
+		begin
+			// Can't grant two channels to the same master
+			always @(*)
+			if (f_past_valid && grant[N][M])
+				assert(grant[N][M-1:0] == 0);
+		end
+
+
+		always @(*)
+		if (&w_mpending[N])
+			assert(o_merr[N] || m_stall[N]);
+
+		reg	checkgrant;
+		always @(*)
+		if (f_past_valid)
+		begin
+			checkgrant = 0;
+			for(iM=0; iM<NS; iM=iM+1)
+				if (grant[N][iM])
+					checkgrant = 1;
+			if (grant[N][NS])
+				checkgrant = 1;
+
+			assert(checkgrant == mgrant[N]);
+		end
+
+	end endgenerate
+
+	// Double check the grant mechanism and its dependent variables
+	generate for(N=0; N<NM; N=N+1)
+	begin : CHECK_GRANTS
+
+		for(M=0; M<NS; M=M+1)
+		begin
+			always @(*)
+			if ((f_past_valid)&&grant[N][M])
+			begin
+				assert(mgrant[N]);
+				assert(mindex[N] == M);
+				assert(sgrant[M]);
+				assert(sindex[M] == N);
+			end
+		end
+	end endgenerate
+
+	generate for(M=0; M<NS; M=M+1)
+	begin : CHECK_SGRANT
+		reg	f_sgrant;
+
+		always @(*)
+		if (sgrant[M])
+			assert(grant[sindex[M]][M]);
+
+		always @(*)
+		begin
+			f_sgrant = 0;
+			for(iN=0; iN<NM; iN=iN+1)
+			if (grant[iN][M])
+				f_sgrant = 1;
+		end
+
+		always @(*)
+			assert(sgrant[M] == f_sgrant);
+	end endgenerate
+
+	// Double check the timeout flags for consistency
+	generate for(N=0; N<NM; N=N+1)
+	begin
+		always @(*)
+		if (f_past_valid)
+		begin
+			assert(mempty[N] == (w_mpending[N] == 0));
+			assert(mnearfull[N]==(&w_mpending[N][LGMAXBURST-1:1]));
+			assert(mfull[N] == (&w_mpending[N]));
+		end
+	end endgenerate
+
+`ifdef	VERIFIC
+	//
+	// The Verific parser is currently broken, and doesn't allow
+	// initial assumes or asserts.  The following lines get us around that
+	//
+	always @(*)
+	if (!f_past_valid)
+		assume(sgrant == 0);
+
+	generate for(M=0; M<NS; M=M+1)
+	begin
+		always @(*)
+		if (!f_past_valid)
+		begin
+			assume(o_scyc[M] == 0);
+			assume(o_sstb[M] == 0);
+			assume(sgrant[M] == 0);
+		end
+	end endgenerate
+
+	generate for(N=0; N<NM; N=N+1)
+	begin
+		always @(*)
+		if (!f_past_valid)
+		begin
+			assume(grant[N] == 0);
+			assume(mgrant[N] == 0);
+		end
+	end endgenerate
+`endif
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//	BUS CHECK
+	//
+	// Verify that every channel, whether master or slave, follows the rules
+	// of the WB road.
+	//
+	////////////////////////////////////////////////////////////////////////
+	generate for(N=0; N<NM; N=N+1)
+	begin : WB_SLAVE_CHECK
+
+		fwb_slave #(
+			.AW(AW), .DW(DW),
+			.F_LGDEPTH(LGMAXBURST),
+			.F_MAX_ACK_DELAY(0),
+			.F_MAX_STALL(0)
+			) slvi(i_clk, i_reset,
+				i_mcyc[N], i_mstb[N], i_mwe[N],
+				i_maddr[N*AW +: AW], i_mdata[N*DW +: DW],
+				i_msel[N*(DW/8) +: (DW/8)],
+			o_mack[N], o_mstall[N], o_mdata[N*DW +: DW], o_merr[N],
+			f_mreqs[N], f_macks[N], f_moutstanding[N]);
+
+		always @(*)
+		if ((f_past_valid)&&(grant[N][NS]))
+			assert(f_moutstanding[N] <= 1);
+
+		always @(*)
+		if (f_past_valid && grant[N][NS] && i_mcyc[N])
+			assert(m_stall[N] || o_merr[N]);
+
+		always @(posedge i_clk)
+		if (f_past_valid && $past(!i_reset && i_mstb[N] && o_mstall[N]))
+			assume($stable(i_mdata[N*DW +: DW]));
+	end endgenerate
+
+	generate for(M=0; M<NS; M=M+1)
+	begin : WB_MASTER_CHECK
+		fwb_master #(
+			.AW(AW), .DW(DW),
+			.F_LGDEPTH(LGMAXBURST),
+			.F_MAX_ACK_DELAY(F_MAX_DELAY),
+			.F_MAX_STALL(2)
+			) mstri(i_clk, i_reset,
+				o_scyc[M], o_sstb[M], o_swe[M],
+				o_saddr[M*AW +: AW], o_sdata[M*DW +: DW],
+				o_ssel[M*(DW/8) +: (DW/8)],
+			i_sack[M], i_sstall[M], s_data[M], i_serr[M],
+			f_sreqs[M], f_sacks[M], f_soutstanding[M]);
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	////////////////////////////////////////////////////////////////////////
+	generate for(N=0; N<NM; N=N+1)
+	begin : CHECK_OUTSTANDING
+
+		always @(*)
+		if (mfull[N])
+			assert(m_stall[N]);
+
+		always @(posedge i_clk)
+		if (i_mcyc[N])
+			assert(f_moutstanding[N] == w_mpending[N]
+				+((OPT_BUFFER_DECODER & dcd_stb[N]) ? 1:0));
+
+		reg	[LGMAXBURST:0]	n_outstanding;
+		always @(*)
+		if (i_mcyc[N])
+			assert(f_moutstanding[N] >=
+				((OPT_BUFFER_DECODER && dcd_stb[N]) ? 1:0)
+				+ (o_mack[N] && OPT_DBLBUFFER) ? 1:0);
+
+		always @(*)
+			n_outstanding = f_moutstanding[N]
+				- ((OPT_BUFFER_DECODER && dcd_stb[N]) ? 1:0)
+				- ((o_mack[N] && OPT_DBLBUFFER) ? 1:0);
+
+		always @(posedge i_clk)
+		if (i_mcyc[N] && !mgrant[N] && !o_merr[N])
+			assert(f_moutstanding[N]
+				== ((OPT_BUFFER_DECODER & dcd_stb[N]) ? 1:0));
+
+		else if (i_mcyc[N] && mgrant[N] && !i_reset)
+		for(iM=0; iM<NS; iM=iM+1)
+		if (grant[N][iM] && o_scyc[iM] && !i_serr[iM] && !o_merr[N])
+			assert(n_outstanding
+				== {1'b0,f_soutstanding[iM]}
+					+(o_sstb[iM] ? 1:0));
+
+		always @(*)
+		if (!i_reset)
+		begin
+			for(iM=0; iM<NS; iM=iM+1)
+			if (grant[N][iM] && i_mcyc[N])
+			begin
+				if (f_soutstanding[iM] > 0)
+					assert(i_mwe[N] == o_swe[iM]);
+				if (o_sstb[iM])
+					assert(i_mwe[N] == o_swe[iM]);
+				if (o_mack[N])
+					assert(i_mwe[N] == o_swe[iM]);
+				if (o_scyc[iM] && i_sack[iM])
+					assert(i_mwe[N] == o_swe[iM]);
+				if (o_merr[N] && !timed_out[N])
+					assert(i_mwe[N] == o_swe[iM]);
+				if (o_scyc[iM] && i_serr[iM])
+					assert(i_mwe[N] == o_swe[iM]);
+			end
+		end
+
+		always @(*)
+		if (!i_reset && OPT_BUFFER_DECODER && i_mcyc[N])
+		begin
+			if (dcd_stb[N])
+				assert(i_mwe[N] == m_we[N]);
+		end
+
+	end endgenerate
+
+	generate for(M=0; M<NS; M=M+1)
+	begin
+		always @(posedge i_clk)
+		if (!$past(sgrant[M]))
+			assert(!o_scyc[M]);
+	end endgenerate
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	//	CONTRACT SECTION
+	//
+	// Here's the contract, in two parts:
+	//
+	//	1. Should ever a master (any master) wish to read from a slave
+	//		(any slave), he should be able to read a known value
+	//		from that slave (any value) from any arbitrary address
+	//		he might wish to read from (any address)
+	//
+	//	2. Should ever a master (any master) wish to write to a slave
+	//		(any slave), he should be able to write the exact
+	//		value he wants (any value) to the exact address he wants
+	//		(any address)
+	//
+	//	special_master	is an arbitrary constant chosen by the solver,
+	//		which can reference *any* possible master
+	//	special_address	is an arbitrary constant chosen by the solver,
+	//		which can reference *any* possible address the master
+	//		might wish to access
+	//	special_value	is an arbitrary value (at least during
+	//		induction) representing the current value within the
+	//		slave at the given address
+	//
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Now let's pay attention to a special bus master and a special
+	// address referencing a special bus slave.  We'd like to assert
+	// that we can access the values of every slave from every master.
+	(* anyconst *) reg	[(NM<=1)?0:(LGNM-1):0]	special_master;
+			reg	[(NS<=1)?0:(LGNS-1):0]	special_slave;
+	(* anyconst *) reg	[AW-1:0]	special_address;
+			reg	[DW-1:0]	special_value;
+
+	always @(*)
+	if (NM <= 1)
+		assume(special_master == 0);
+	always @(*)
+	if (NS <= 1)
+		assume(special_slave == 0);
+
+	//
+	// Decode the special address to discover the slave associated with it
+	always @(*)
+	begin
+		special_slave = NS;
+		for(iM=0; iM<NS; iM = iM+1)
+		begin
+			if (((special_address ^ SLAVE_ADDR[iM*AW +: AW])
+					&SLAVE_MASK[iM*AW +: AW]) == 0)
+				special_slave = iM;
+		end
+	end
+
+	generate if (NS > 1)
+	begin : DOUBLE_ADDRESS_CHECK
+		//
+		// Check that no slave address has been assigned twice.
+		// This check only needs to be done once at the beginning
+		// of the run, during the BMC section.
+		reg	address_found;
+
+		always @(*)
+		if (!f_past_valid)
+		begin
+			address_found = 0;
+			for(iM=0; iM<NS; iM = iM+1)
+			begin
+				if (((special_address ^ SLAVE_ADDR[iM*AW +: AW])
+						&SLAVE_MASK[iM*AW +: AW]) == 0)
+				begin
+					assert(address_found == 0);
+					address_found = 1;
+				end
+			end
+		end
+
+	end endgenerate
+	//
+	// Let's assume this slave will acknowledge any request on the next
+	// bus cycle after the stall goes low.  Further, lets assume that
+	// it never creates an error, and that it always responds to our special
+	// address with the special data value given above.  To do this, we'll
+	// also need to make certain that the special value will change
+	// following any write.
+	//
+	// These are the "assumptions" associated with our fictitious slave.
+`ifdef	VERIFIC
+	always @(*)
+	if (!f_past_valid)
+		assume(special_value == 0);
+`else
+	initial	assume(special_value == 0);
+`endif
+	always @(posedge i_clk)
+	if (special_slave < NS)
+	begin
+		if ($past(o_sstb[special_slave] && !i_sstall[special_slave]))
+		begin
+			assume(i_sack[special_slave]);
+
+			if ($past(!o_swe[special_slave])
+					&&($past(o_saddr[special_slave*AW +: AW]) == special_address))
+				assume(i_sdata[special_slave*DW+: DW]
+						== special_value);
+		end else
+			assume(!i_sack[special_slave]);
+		assume(!i_serr[special_slave]);
+
+		if (o_scyc[special_slave])
+			assert(f_soutstanding[special_slave]
+				== i_sack[special_slave]);
+
+		if (o_sstb[special_slave] && !i_sstall[special_slave]
+			&& o_swe[special_slave])
+		begin
+			for(iM=0; iM < DW/8; iM=iM+1)
+			if (o_ssel[special_slave * DW/8 + iM])
+				special_value[iM*8 +: 8] <= o_sdata[special_slave * DW + iM*8 +: 8];
+		end
+	end
+
+	//
+	// Now its time to make some assertions.  Specifically, we want to
+	// assert that any time we read from this special slave, the special
+	// value is returned.
+	reg	[2:0]	f_read_seq;
+	reg		f_read_ack, f_read_sstall;
+
+	initial	f_read_sstall = 0;
+	always @(posedge i_clk)
+		f_read_sstall <= s_stall[special_slave];
+
+	always @(*)
+		f_read_ack = (f_read_seq[2] || ((!OPT_DBLBUFFER)&&f_read_seq[1]
+					&& !f_read_sstall));
+	initial	f_read_seq = 0;
+	always @(posedge i_clk)
+	if ((special_master < NM)&&(special_slave < NS)
+			&&(i_mcyc[special_master])
+			&&(!timed_out[special_master]))
+	begin
+		f_read_seq <= 0;
+		if ((grant[special_master][special_slave])
+			&&(m_stb[special_master])
+			&&(m_addr[special_master] == special_address)
+			&&(!m_we[special_master])
+			)
+		begin
+			f_read_seq[0] <= 1;
+		end
+
+		if (|f_read_seq)
+		begin
+			assert(grant[special_master][special_slave]);
+			assert(mgrant[special_master]);
+			assert(sgrant[special_slave]);
+			assert(mindex[special_master] == special_slave);
+			assert(sindex[special_slave] == special_master);
+			assert(!o_merr[special_master]);
+		end
+
+		if (f_read_seq[0] && !$past(s_stall[special_slave]))
+		begin
+			assert(o_scyc[special_slave]);
+			assert(o_sstb[special_slave]);
+			assert(!o_swe[special_slave]);
+			assert(o_saddr[special_slave*AW +: AW] == special_address);
+
+			f_read_seq[1] <= 1;
+
+		end else if (f_read_seq[0] && $past(s_stall[special_slave]))
+		begin
+			assert($stable(m_stb[special_master]));
+			assert(!m_we[special_master]);
+			assert(m_addr[special_master] == special_address);
+
+			f_read_seq[0] <= 1;
+		end
+
+		if (f_read_seq[1] && $past(s_stall[special_slave]))
+		begin
+			assert(o_scyc[special_slave]);
+			assert(o_sstb[special_slave]);
+			assert(!o_swe[special_slave]);
+			assert(o_saddr[special_slave*AW +: AW] == special_address);
+			f_read_seq[1] <= 1;
+		end else if (f_read_seq[1] && !$past(s_stall[special_slave]))
+		begin
+			assert(i_sack[special_slave]);
+			assert(i_sdata[special_slave*DW +: DW] == $past(special_value));
+			if (OPT_DBLBUFFER)
+				f_read_seq[2] <= 1;
+		end
+
+		if (f_read_ack)
+		begin
+			assert(o_mack[special_master]);
+			assert(o_mdata[special_master * DW +: DW]
+				== $past(special_value,2));
+		end
+	end else
+		f_read_seq <= 0;
+
+	always @(*)
+		cover(i_mcyc[special_master] && f_read_ack);
+
+
+	//
+	// Let's try a write assertion now.  Specifically, on any request to
+	// write to our special address, we want to assert that the special
+	// value at that address can be written.
+	reg	[2:0]	f_write_seq;
+	reg		f_write_ack, f_write_sstall;
+
+	initial	f_write_sstall = 0;
+	always @(posedge i_clk)
+		f_write_sstall = s_stall[special_slave];
+
+	always @(*)
+		f_write_ack = (f_write_seq[2]
+				|| ((!OPT_DBLBUFFER)&&f_write_seq[1]
+					&& !f_write_sstall));
+	initial	f_write_seq = 0;
+	always @(posedge i_clk)
+	if ((special_master < NM)&&(special_slave < NS)
+			&&(i_mcyc[special_master])
+			&&(!timed_out[special_master]))
+	begin
+		f_write_seq <= 0;
+		if ((grant[special_master][special_slave])
+			&&(m_stb[special_master])
+			&&(m_addr[special_master] == special_address)
+			&&(m_we[special_master]))
+		begin
+			// Our write sequence begins when our special master
+			// has access to the bus, *and* he is trying to write
+			// to our special address.
+			f_write_seq[0] <= 1;
+		end
+
+		if (|f_write_seq)
+		begin
+			assert(grant[special_master][special_slave]);
+			assert(mgrant[special_master]);
+			assert(sgrant[special_slave]);
+			assert(mindex[special_master] == special_slave);
+			assert(sindex[special_slave] == special_master);
+			assert(!o_merr[special_master]);
+		end
+
+		if (f_write_seq[0] && !$past(s_stall[special_slave]))
+		begin
+			assert(o_scyc[special_slave]);
+			assert(o_sstb[special_slave]);
+			assert(o_swe[special_slave]);
+			assert(o_saddr[special_slave*AW +: AW] == special_address);
+			assert(o_sdata[special_slave*DW +: DW]
+				== $past(m_data[special_master]));
+			assert(o_ssel[special_slave*DW/8 +: DW/8]
+				== $past(m_sel[special_master]));
+
+			f_write_seq[1] <= 1;
+
+		end else if (f_write_seq[0] && $past(s_stall[special_slave]))
+		begin
+			assert($stable(m_stb[special_master]));
+			assert(m_we[special_master]);
+			assert(m_addr[special_master] == special_address);
+			assert($stable(m_data[special_master]));
+			assert($stable(m_sel[special_master]));
+
+			f_write_seq[0] <= 1;
+		end
+
+		if (f_write_seq[1] && $past(s_stall[special_slave]))
+		begin
+			assert(o_scyc[special_slave]);
+			assert(o_sstb[special_slave]);
+			assert(o_swe[special_slave]);
+			assert(o_saddr[special_slave*AW +: AW] == special_address);
+			assert($stable(o_sdata[special_slave*DW +: DW]));
+			assert($stable(o_ssel[special_slave*DW/8 +: DW/8]));
+			f_write_seq[1] <= 1;
+		end else if (f_write_seq[1] && !$past(s_stall[special_slave]))
+		begin
+			for(iM=0; iM<DW/8; iM=iM+1)
+			begin
+				if ($past(o_ssel[special_slave * DW/8 + iM]))
+					assert(special_value[iM*8 +: 8]
+						== $past(o_sdata[special_slave*DW+iM*8 +: 8]));
+			end
+
+			assert(i_sack[special_slave]);
+			if (OPT_DBLBUFFER)
+				f_write_seq[2] <= 1;
+		end
+
+		if (f_write_seq[2] || ((!OPT_DBLBUFFER) && f_write_seq[1]
+					&& !$past(s_stall[special_slave])))
+			assert(o_mack[special_master]);
+	end else
+		f_write_seq <= 0;
+
+	always @(*)
+		cover(i_mcyc[special_master] && f_write_ack);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// (draft) full connectivity check
+	//
+	////////////////////////////////////////////////////////////////////////
+	reg	[NM-1:0]	f_m_ackd;
+	reg	[NS-1:0]	f_s_ackd;
+	reg			f_cvr_aborted;
+
+	initial	f_cvr_aborted = 0;
+	always @(posedge i_clk)
+	if (!f_past_valid || i_reset)
+		f_cvr_aborted <= 0;
+	else for(iN=0; iN<NM; iN=iN+1)
+	begin
+		if (request[iN][NS])
+			f_cvr_aborted = 1;
+		if ($fell(i_mcyc[iN]))
+		begin
+			if (f_macks[iN] != f_mreqs[iN])
+				f_cvr_aborted = 1;
+		end
+	end
+
+	initial	f_m_ackd = 0;
+	generate for (N=0; N<NM; N=N+1)
+	begin
+
+		always @(posedge i_clk)
+		if (i_reset)
+			f_m_ackd[N] <= 0;
+		else if (o_mack[N])
+			f_m_ackd[N] <= 1'b1;
+
+	end endgenerate
+
+	always @(posedge i_clk)
+		cover(!f_cvr_aborted && (&f_m_ackd));
+
+	generate if (NM > 1)
+	begin
+
+		always @(posedge i_clk)
+			cover(!f_cvr_aborted && (&f_m_ackd[1:0]));
+
+	end endgenerate
+
+	initial	f_s_ackd = 0;
+	generate for (M=0; M<NS; M=M+1)
+	begin
+
+		always @(posedge i_clk)
+		if (i_reset)
+			f_s_ackd[M] <= 1'b0;
+		else if (sgrant[M] && o_mack[sindex[M]])
+			f_s_ackd[M] <= 1'b1;
+
+	end endgenerate
+
+	always @(posedge i_clk)
+		cover(!f_cvr_aborted && (&f_s_ackd[NS-1:0]));
+
+	generate if (NS > 1)
+	begin
+
+		always @(posedge i_clk)
+			cover(!f_cvr_aborted && (&f_s_ackd[NS-1:0]));
+
+	end endgenerate
+
+`endif
+endmodule
+`ifndef	YOSYS
+`default_nettype wire
+`endif
diff --git a/verilog/rtl/softshell/third_party/wb2axip/rtl/wbxclk.v b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbxclk.v
new file mode 100644
index 0000000..f9628ef
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/rtl/wbxclk.v
@@ -0,0 +1,839 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: 	rtl/wbxclk.v
+// {{{
+// Project:	WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:	To cross clock domains with a (pipelined) wishbone bus.
+//
+// Challenges:
+//	1. Wishbone has no capacity for back pressure.  That means that we'll
+//		need to be careful not to issue more STB requests than ACKs
+//		that will fit in the return buffer.
+//
+//	    Imagine, for example, a faster return clock but a slave that needs
+//		many clocks to get going.  During that time, many requests
+//		might be issued.  If they all suddenly get returned at once,
+//		flooding the return ACK FIFO, then we have a problem.
+//
+//	2. Bus aborts.  If we ever have to abort a transaction, that's going
+//		to be a pain.  The FIFOs will need to be reset and the
+//		downstream CYC line dropped.  This needs to be done
+//		synchronously in both domains, but there's no real choice but
+//		to make the crossing asynchronous.
+//
+//	3. Synchronous CYC.  Lowering CYC is a normal part of the protocol, as
+//		is raising CYC.  CYC is used as a bus locking scheme, so we'll
+//		need to know when it is (properly) lowered downstream.  This
+//		can be done by passing a synchronous CYC drop request through
+//		the pipeline in addition to the bus aborts above.
+//
+//	Status:
+//		Formally verified against a set of bus properties, not yet
+//		used in any real or simulated designs
+//
+// Creator:	Dan Gisselquist, Ph.D.
+//		Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2020, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License").  You may not use this project,
+// or this file, except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype	none
+// }}}
+module	wbxclk #(
+		// {{{
+		parameter	AW=32,
+				DW=32,
+				DELAY_STALL = 0,
+				LGFIFO = 5,
+		parameter [(LGFIFO-1):0] THRESHOLD = {{(LGFIFO-4){1'b0}},4'h8},
+		localparam	NFF = 2,
+		localparam	FIFOLN    = (1<<LGFIFO)
+		// }}}
+	) (
+		// {{{
+		input	wire			i_wb_clk, i_reset,
+		// Input/master bus
+		input	wire			i_wb_cyc, i_wb_stb, i_wb_we,
+		input	wire	[(AW-1):0]	i_wb_addr,
+		input	wire	[(DW-1):0]	i_wb_data,
+		input	wire	[(DW/8-1):0]	i_wb_sel,
+		output	wire			o_wb_stall,
+		output	reg			o_wb_ack,
+		output	reg	[(DW-1):0]	o_wb_data,
+		output	reg			o_wb_err,
+		// Delayed bus
+		input	wire			i_xclk_clk,
+		output	reg			o_xclk_cyc,
+		output	reg			o_xclk_stb,
+		output	reg			o_xclk_we,
+		output	reg	[(AW-1):0]	o_xclk_addr,
+		output	reg	[(DW-1):0]	o_xclk_data,
+		output	reg	[(DW/8-1):0]	o_xclk_sel,
+		input	wire			i_xclk_stall,
+		input	wire			i_xclk_ack,
+		input	wire	[(DW-1):0]	i_xclk_data,
+		input	wire			i_xclk_err
+		// }}}
+	);
+
+	//
+	// Declare our signals
+	// {{{
+	reg		wb_active;
+	reg [NFF-2:0]	bus_abort_pipe;
+	reg [LGFIFO:0]	acks_outstanding;
+	reg		ackfifo_single, ackfifo_empty, ackfifo_full;
+	wire		ack_stb, err_stb;
+	wire [DW-1:0]	ret_wb_data;
+	wire		req_fifo_stall, no_returns;
+	//
+	// Verilator lint_off SYNCASYNCNET
+	reg		bus_abort;
+	// Verilator lint_on SYNCASYNCNET
+	//
+	wire		req_stb, req_fifo_empty;
+	reg		xclk_err_state, ign_ackfifo_stall;
+	reg		xck_reset;
+	reg [NFF-2:0]	xck_reset_pipe;
+	reg		r_we;
+	wire		req_we;
+	wire [AW-1:0]	req_addr;
+	wire [DW-1:0]	req_data;
+	wire [DW/8-1:0]	req_sel;
+`ifdef	FORMAL
+	wire	[LGFIFO:0]	ackfifo_prefill, reqfifo_prefill;
+`endif
+	// }}}
+
+	//
+	//
+	// On the original wishbone clock ...
+	//
+	//	 FIFO/queue up our requests
+	// {{{
+	initial	wb_active = 1'b0;
+	always	@(posedge i_wb_clk)
+	if (i_reset || !i_wb_cyc)
+		wb_active <= 1'b0;
+	else if (i_wb_stb && !o_wb_stall)
+		wb_active <= 1'b1;
+
+	initial	{ bus_abort, bus_abort_pipe } = -1;
+	always	@(posedge i_wb_clk)
+	if (i_reset)
+		{ bus_abort, bus_abort_pipe } <= -1;
+	else if (!i_wb_cyc && (!ackfifo_empty))
+		{ bus_abort, bus_abort_pipe } <= -1;
+	else if (o_wb_err)
+		{ bus_abort, bus_abort_pipe } <= -1;
+	else if (ackfifo_empty)
+		{ bus_abort, bus_abort_pipe } <= { bus_abort_pipe, 1'b0 };
+`ifdef	FORMAL
+	always @(*)
+	if (bus_abort_pipe)
+		assert(bus_abort);
+`endif
+	// }}}
+
+	//
+	// The request FIFO itself
+	// {{{
+	afifo #(
+`ifdef	FORMAL
+		.OPT_REGISTER_READS(0),
+`endif
+		.NFF(NFF), .LGFIFO(LGFIFO),
+		.WIDTH(2+AW+DW+(DW/8))
+	) reqfifo(.i_wclk(i_wb_clk), .i_wr_reset_n(!bus_abort),
+		.i_wr((i_wb_stb&&!o_wb_stall) || (wb_active && !i_wb_cyc)),
+		.i_wr_data({ i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel }),
+		.o_wr_full(req_fifo_stall),
+		//
+		.i_rclk(i_xclk_clk), .i_rd_reset_n(!xck_reset),
+		.i_rd(!o_xclk_stb || !i_xclk_stall),
+		.o_rd_data({ req_stb, req_we, req_addr, req_data, req_sel }),
+		.o_rd_empty(req_fifo_empty)
+`ifdef	FORMAL
+		, .f_fill(reqfifo_prefill)
+`endif
+	);
+	// }}}
+
+	//
+	// Downstream bus--issuing requests
+	// {{{
+	initial	{ xck_reset, xck_reset_pipe } = -1;
+	always	@(posedge i_xclk_clk or posedge bus_abort)
+	if (bus_abort)
+		{ xck_reset, xck_reset_pipe } <= -1;
+	else
+		{ xck_reset, xck_reset_pipe } <= { xck_reset_pipe, 1'b0 };
+`ifdef	FORMAL
+	always @(*)
+	if (xck_reset_pipe)
+		assert(xck_reset);
+`endif
+
+	initial	xclk_err_state = 1'b0;
+	always @(posedge i_xclk_clk)
+	if (xck_reset || (!req_fifo_empty && !req_stb))
+		xclk_err_state <= 1'b0;
+	else if (o_xclk_cyc && i_xclk_err)
+		xclk_err_state <= 1'b1;
+
+	initial	o_xclk_cyc = 1'b0;
+	always @(posedge i_xclk_clk)
+	if (xck_reset || (o_xclk_cyc && i_xclk_err))
+		o_xclk_cyc <= 1'b0;
+	else if (!req_fifo_empty && !req_stb)
+		o_xclk_cyc <= 1'b0;
+	else if (!req_fifo_empty && !xclk_err_state)
+		o_xclk_cyc <= req_stb;
+
+	initial	o_xclk_stb = 1'b0;
+	always @(posedge i_xclk_clk)
+	if (xck_reset || (o_xclk_cyc && i_xclk_err) || xclk_err_state)
+		o_xclk_stb <= 1'b0;
+	else if (!o_xclk_stb || !i_xclk_stall)
+		o_xclk_stb <= req_stb && !req_fifo_empty;
+
+	always @(posedge i_xclk_clk)
+	if ((!o_xclk_stb || !i_xclk_stall) && req_stb && !req_fifo_empty)
+		o_xclk_we <= req_we;
+
+	always @(posedge i_xclk_clk)
+	if (!o_xclk_stb || !i_xclk_stall)
+	begin
+		o_xclk_addr <= req_addr;
+		o_xclk_data <= req_data;
+		o_xclk_sel  <= req_sel;
+	end
+	// }}}
+
+
+	//
+	// Request counting
+	// {{{
+	initial	acks_outstanding = 0;
+	initial	ackfifo_single = 0;
+	initial	ackfifo_empty  = 1;
+	initial	ackfifo_full   = 0;
+	always @(posedge i_wb_clk)
+	if (i_reset || !i_wb_cyc || o_wb_err)
+	begin
+		acks_outstanding <= 0;
+		ackfifo_single   <= 0;
+		ackfifo_empty    <= 1;
+		ackfifo_full     <= 0;
+	end else case({ (i_wb_stb && !o_wb_stall), o_wb_ack })
+	2'b10: begin
+		acks_outstanding <= acks_outstanding + 1;
+		ackfifo_empty <= 0;
+		ackfifo_single <= ackfifo_empty;
+		ackfifo_full   <= (&acks_outstanding[LGFIFO-1:0]);
+		end
+	2'b01: begin
+		acks_outstanding <= acks_outstanding - 1;
+		ackfifo_empty <= (acks_outstanding <= 1);
+		ackfifo_single <= (acks_outstanding == 2);
+		ackfifo_full   <= 0;
+		end
+	default: begin end
+	endcase
+
+`ifdef	FORMAL
+	always @(*)
+	begin
+		assert(ackfifo_single == (acks_outstanding == 1));
+		assert(ackfifo_empty == (acks_outstanding == 0));
+		assert(ackfifo_full == (acks_outstanding >= (1<<LGFIFO)));
+		assert(acks_outstanding <= (1<<LGFIFO));
+	end
+`endif
+
+	assign	o_wb_stall = ackfifo_full || bus_abort || req_fifo_stall;
+	// }}}
+
+	//
+	// The return FIFO
+	// {{{
+	afifo #(
+		.OPT_REGISTER_READS(0),
+		.NFF(NFF), .LGFIFO(LGFIFO),
+		.WIDTH(2+DW)
+	) ackfifo(.i_wclk(i_xclk_clk), .i_wr_reset_n(!xck_reset),
+		.i_wr(o_xclk_cyc && ( i_xclk_ack || i_xclk_err )),
+		.i_wr_data({ i_xclk_ack, i_xclk_err, i_xclk_data }),
+		.o_wr_full(ign_ackfifo_stall),
+		//
+		.i_rclk(i_wb_clk), .i_rd_reset_n(!bus_abort),
+		.i_rd(!no_returns),
+		.o_rd_data({ ack_stb, err_stb, ret_wb_data }),
+		.o_rd_empty(no_returns)
+`ifdef	FORMAL
+		, .f_fill(ackfifo_prefill)
+`endif
+	);
+	// }}}
+
+	//
+	// Final return processing
+	// {{{
+	initial	{ o_wb_ack, o_wb_err } = 2'b00;
+	always @(posedge i_wb_clk)
+	if (i_reset || bus_abort || !i_wb_cyc || no_returns || o_wb_err)
+		{ o_wb_ack, o_wb_err } <=  2'b00;
+	else
+		{ o_wb_ack, o_wb_err } <= { ack_stb, err_stb };
+
+	always @(posedge i_wb_clk)
+		o_wb_data <= ret_wb_data;
+	// }}}
+
+	// Make Verilator happy
+	// {{{
+	// Verilator lint_off UNUSED
+	wire	unused;
+	assign	unused = &{ 1'b0, req_fifo_stall, ign_ackfifo_stall };
+	// Verilator lint_on UNUSED
+	// }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef	FORMAL
+	// Register/net/macro declarations
+	// {{{
+`ifdef	BMC
+`define	BMC_ASSERT	assert
+`else
+`define	BMC_ASSERT	assume
+`endif
+
+	(* gclk *)	reg	gbl_clk;
+
+	wire	[LGFIFO:0]	fwb_nreqs, fwb_nacks, fwb_outstanding;
+	wire	[LGFIFO:0]	fxck_nreqs, fxck_nacks, fxck_outstanding;
+	reg	[LGFIFO:0]	ackfifo_fill, reqfifo_fill;
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Assume a clock
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	(* anyconst *)	reg	[3:0]	fwb_step, fxck_step;
+	reg	[3:0]	fwb_count, fxck_count;
+
+	always @(*)
+	begin
+		assume(fwb_step  >= 2);
+		assume(fxck_step >= 2);
+
+		assume(fwb_step  <= 4'b1000);
+		assume(fxck_step <= 4'b1000);
+
+	//	assume(fwb_step  == 4'b1000);
+	//	assume(fxck_step  == 4'b0111);
+		assume((fwb_step  == 4'b0111)
+			|| (fxck_step == 4'b0111));
+	end
+
+	always @(posedge gbl_clk)
+	begin
+		fwb_count  <= fwb_count  + fwb_step;
+		fxck_count <= fxck_count + fxck_step;
+	end
+
+	always @(*)
+	begin
+		assume(i_wb_clk   == fwb_count[3]);
+		assume(i_xclk_clk == fxck_count[3]);
+	end
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// ....
+	//
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	//
+	// Cross clock stability assumptions
+	// {{{
+	always @(posedge gbl_clk)
+	if (!$rose(i_wb_clk))
+	begin
+		assume($stable(i_reset));
+
+		assume($stable(i_wb_cyc));
+		assume($stable(i_wb_stb));
+		assume($stable(i_wb_we));
+		assume($stable(i_wb_addr));
+		assume($stable(i_wb_data));
+		assume($stable(i_wb_sel));
+	end
+
+	always @(posedge gbl_clk)
+	if (!$rose(i_xclk_clk))
+	begin
+		assume($stable(i_xclk_ack));
+		assume($stable(i_xclk_err));
+		assume($stable(i_xclk_data));
+		assume($stable(i_xclk_stall));
+	end
+
+	reg			past_wb_clk, past_wb_stb, past_wb_we,
+				past_wb_cyc, past_wb_reset, past_wb_err;
+	reg			past_xclk, past_xclk_stall, past_xclk_ack,
+				past_xclk_err;
+	reg	[DW-1:0]	past_xclk_data;
+	reg			f_drop_cyc_request;
+
+	always @(posedge gbl_clk)
+	begin
+		past_wb_clk  <= i_wb_clk;
+		past_wb_reset<= i_reset;
+		past_wb_cyc  <= i_wb_cyc;
+		past_wb_stb  <= i_wb_stb;
+		past_wb_we   <= i_wb_we;
+		past_wb_err  <= o_wb_err;
+	end
+
+	always @(*)
+	if (!i_wb_clk || past_wb_clk)
+	begin
+		assume(past_wb_reset== i_reset);
+		assume(past_wb_cyc == i_wb_cyc);
+		assume(past_wb_stb == i_wb_stb);
+		assume(past_wb_we  == i_wb_we);
+		assume(past_wb_err == o_wb_err);
+	end else begin
+		if (past_wb_err && past_wb_cyc)
+			assume(!i_wb_cyc);
+		if (fwb_outstanding > 0)
+			assume(past_wb_we == i_wb_we);
+	end
+
+	always @(posedge gbl_clk)
+	begin
+		past_xclk       <= i_xclk_clk;
+		past_xclk_stall <= i_xclk_stall;
+		past_xclk_data  <= i_xclk_data;
+		past_xclk_ack   <= i_xclk_ack;
+		past_xclk_err   <= i_xclk_err;
+	end
+
+	always @(*)
+	if (!i_xclk_clk || past_xclk)
+	begin
+		assume(past_xclk_stall == i_xclk_stall);
+		assume(past_xclk_data  == i_xclk_data);
+		assume(past_xclk_ack   == i_xclk_ack);
+		assume(past_xclk_err   == i_xclk_err);
+	end
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Wishbone bus property checks
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	fwb_slave #(.AW(AW), .DW(DW),
+		.F_LGDEPTH(LGFIFO+1), .F_OPT_DISCONTINUOUS(1)
+	) slv(i_wb_clk, i_reset,
+		i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel,
+		o_wb_ack, o_wb_stall, o_wb_data, o_wb_err,
+		fwb_nreqs, fwb_nacks, fwb_outstanding);
+
+	fwb_master #(.AW(AW), .DW(DW),
+		.F_LGDEPTH(LGFIFO+1), .F_OPT_DISCONTINUOUS(1),
+		.F_MAX_STALL(4),
+		.F_MAX_ACK_DELAY(7)
+	) xclkwb(i_xclk_clk, xck_reset,
+		o_xclk_cyc, o_xclk_stb, o_xclk_we, o_xclk_addr, o_xclk_data, o_xclk_sel,
+		i_xclk_ack, i_xclk_stall, i_xclk_data, i_xclk_err,
+		fxck_nreqs, fxck_nacks, fxck_outstanding);
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// (Random/unsorted) properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	always @(*)
+	if (reqfifo_fill != (o_xclk_stb ? 1:0) && !req_stb)
+		assert(ackfifo_fill == 0 || xclk_err_state);
+
+	always @(*)
+		reqfifo_fill = reqfifo_prefill + (o_xclk_stb ? 1:0);
+
+	always @(*)
+		ackfifo_fill = ackfifo_prefill // + (no_returns ? 0:1)
+			+ ((o_wb_ack || o_wb_err) ? 1:0);
+
+	always @(*)
+	if (fwb_outstanding > 0)
+		assert(wb_active);
+
+	always @(*)
+	if (f_drop_cyc_request && !bus_abort && !xclk_err_state)
+	begin
+		// req_stb is low, so cycle line has dropped normally
+
+		// If the cycle line has since risen, there may be requests
+		// within the request FIFO in addition to the drop-CYC message.
+		if (i_wb_cyc && wb_active)
+			assert(reqfifo_fill == fwb_outstanding + 1);
+
+		// We wouldn't place a drop CYC message into the FIFO
+		// unless XCLK-CYC  was already high
+		assert(o_xclk_cyc && !o_xclk_stb);
+		assert(ackfifo_fill == 0);
+		assert(fxck_outstanding == 0);
+
+		if (reqfifo_fill > 1)
+			assert(wb_active);
+		else
+			assert(!wb_active);
+	end else if (!bus_abort && xclk_err_state)
+	begin
+		//
+		// Bus error downstream causes an abort
+		assert(fxck_outstanding == 0);
+		assert(xck_reset  || wb_active || !i_wb_cyc);
+		assert(!o_xclk_stb);
+		if (ackfifo_fill == 1)
+			assert(no_returns || err_stb);
+		else if (!xck_reset && ackfifo_fill == 1)
+			assert(o_wb_err);
+	end else if (!bus_abort && i_wb_cyc && !xck_reset && !xclk_err_state)
+	begin
+		//
+		// Normal operation in operation
+		//
+		assert(reqfifo_fill <= fwb_outstanding + 1);
+		assert(ackfifo_fill <= fwb_outstanding);
+		assert(fxck_outstanding <= fwb_outstanding);
+		if (o_xclk_cyc)
+			assert(wb_active || f_drop_cyc_request);
+		if (reqfifo_fill == (o_xclk_stb ? 1:0) || req_stb)
+			// Either first request is for strobe, or other
+			// request counters are valid
+			assert(reqfifo_fill + ackfifo_fill
+				+ fxck_outstanding == fwb_outstanding);
+		else begin
+			// First request is to drop CYC
+			assert(reqfifo_fill== fwb_outstanding + 1);
+			assert(ackfifo_fill == 0);
+			assert(fxck_outstanding == 0);
+			assert(!o_xclk_stb);
+			assert(o_xclk_cyc);
+		end
+		if (acks_outstanding == 0)
+			assert((reqfifo_fill == 0)||!req_stb);
+	end
+
+	always @(*)
+	if (o_wb_ack && wb_active)
+	begin
+		assert(o_xclk_cyc || xclk_err_state);
+		assert(!f_drop_cyc_request);
+		assert(!xck_reset || bus_abort);
+	end
+
+	always @(*)
+	if (!bus_abort && acks_outstanding == 0)
+		assert(reqfifo_fill <= (f_drop_cyc_request ? 1:0)
+			+ ((o_xclk_stb && xck_reset) ? 1:0));
+
+	always @(*)
+	if (ackfifo_fill != 0)
+		assert(o_xclk_cyc || xck_reset || xclk_err_state);
+
+	always @(*)
+	if (fxck_outstanding > fwb_outstanding)
+		assert((!i_wb_cyc && wb_active)
+			|| i_reset || bus_abort || xck_reset);
+
+	always @(*)
+	if (!i_reset && xck_reset && !o_xclk_cyc)
+		assert(!i_wb_cyc || fwb_outstanding == reqfifo_fill);
+
+	always @(*)
+	if (bus_abort && i_wb_cyc)
+		assert(!wb_active);
+
+	always @(*)
+	if (acks_outstanding < (1<<LGFIFO))
+	begin
+		// assert(!reqfifo_full);
+		assert(!ackfifo_full);
+	end
+
+	always @(*)
+	if (!i_reset && !xck_reset && (fwb_outstanding > 0)
+		&& ((fxck_outstanding > 0) || o_xclk_stb))
+		assert(i_wb_we == o_xclk_we);
+
+	always @(*)
+	if (!i_reset && i_wb_cyc)
+		assert(acks_outstanding == fwb_outstanding);
+
+	always @(*)
+	if (xclk_err_state)
+		assert(!o_xclk_cyc);
+
+	always @(*)
+	if (!i_reset && !bus_abort && !i_wb_cyc)
+	begin
+		if (ackfifo_empty)
+		begin
+			if (reqfifo_fill > (o_xclk_stb ? 1:0))
+				assert(!req_stb || xck_reset);
+			assert(reqfifo_fill <= 1);
+			if (xck_reset && !xck_reset_pipe)
+				assert(!o_xclk_cyc);
+		end else begin
+			// ???
+		end
+	end
+
+	always @(*)
+		f_drop_cyc_request = !req_stb
+				&& (reqfifo_fill > (o_xclk_stb ? 1:0));
+
+	always @(*)
+	if (!i_reset && !xck_reset && !bus_abort && i_wb_cyc)
+	begin
+		if (!o_xclk_cyc && !xclk_err_state)
+			assert(acks_outstanding == reqfifo_fill
+				- (f_drop_cyc_request ? 1:0));
+		else if (!o_xclk_cyc && xclk_err_state)
+			assert(acks_outstanding >= reqfifo_fill
+				+ ackfifo_fill);
+		else if (o_xclk_cyc && !xclk_err_state)
+		begin
+			assert(acks_outstanding >= reqfifo_fill
+				- (f_drop_cyc_request ? 1:0));
+			assert(acks_outstanding >= ackfifo_fill);
+			assert(acks_outstanding >= fxck_outstanding);
+			assert(acks_outstanding ==
+				reqfifo_fill - (((reqfifo_fill > (o_xclk_stb ? 1:0))&&(!req_stb)) ? 1:0)
+				+ ackfifo_fill
+				+ fxck_outstanding);
+		end
+		if (f_drop_cyc_request)
+			assert(acks_outstanding +1 == reqfifo_fill);
+		else if (reqfifo_fill == 0)
+			assert(!wb_active || o_xclk_cyc || xclk_err_state);
+	end else if (!i_reset && !xck_reset && !bus_abort && f_drop_cyc_request)
+	begin
+		assert(acks_outstanding +1 == reqfifo_fill);
+		assert(ackfifo_fill == 0);
+		assert(fxck_outstanding == 0);
+		assert(!o_xclk_stb);
+		assert(o_xclk_cyc);
+	end
+
+
+	always @(*)
+	if (!bus_abort && wb_active && reqfifo_fill == 0 && !xclk_err_state)
+		assert(o_xclk_cyc);
+
+	always @(*)
+	if (f_drop_cyc_request && !bus_abort)
+		assert(!xck_reset);
+
+	always @(*)
+		assert(!xclk_err_state || acks_outstanding != 0 || xck_reset);
+
+	always @(*)
+	if (o_xclk_cyc && !i_wb_cyc)
+	begin
+		// assert(bus_abort || !xclk_err_state);
+		if (!wb_active && !bus_abort && !xck_reset)
+			assert(f_drop_cyc_request);
+	end else if (i_wb_cyc)
+	begin
+		if (wb_active && !xck_reset)
+			assert(o_xclk_cyc || xclk_err_state
+				||(reqfifo_fill >= acks_outstanding));
+	end
+
+	// always @(*)
+	// if (acks_outstanding >= (1<<LGFIFO))
+	//	assert(o_xclk_cyc || xclk_err_state || xck_reset);	// !!!!
+
+	//
+	// !!!!!!!!!!!
+	//
+	// Fig me here
+	always @(*)
+	if (wb_active && !bus_abort && !xck_reset && i_wb_cyc && !xclk_err_state)
+	begin
+		if (reqfifo_fill == 0)
+			assert(o_xclk_cyc);
+	end
+
+	always @(*)
+	if (fxck_outstanding > 0 || o_xclk_stb)
+		assert(!ign_ackfifo_stall);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Sub properties for the REQ FIFO
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(*)
+	if ((acks_outstanding > 0)&&(reqfifo_fill != (o_xclk_stb ? 1:0)))
+	begin
+		// Something valuable is in the request FIFO
+		if (i_wb_cyc && !f_drop_cyc_request)
+			`BMC_ASSERT(req_we == i_wb_we);
+		else if (req_stb && o_xclk_stb)
+			`BMC_ASSERT(o_xclk_we == req_we);
+
+		// if (acks_outstanding > 0)
+		if (!o_xclk_cyc || o_xclk_stb ||
+				fxck_outstanding > 0 || ackfifo_fill > 0)
+			`BMC_ASSERT(req_stb);
+	end // else the request FIFO is empty, nothing is in it
+		// No assumptions therefore need be made
+
+	always @(*)
+	if (!bus_abort && reqfifo_fill == acks_outstanding)
+		`BMC_ASSERT(!req_fifo_stall || !f_drop_cyc_request);
+
+	always @(*)
+	if (!i_reset && o_xclk_cyc && (reqfifo_fill != (o_xclk_stb ? 1:0)))
+		`BMC_ASSERT(!req_stb || req_we == o_xclk_we
+			|| fxck_outstanding == 0);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Sub properties for the ACK FIFO
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	always @(*)
+	if (!no_returns)
+	begin
+		`BMC_ASSERT(ack_stb ^ err_stb);
+
+		if ((ackfifo_fill ==(o_wb_ack ? 2:1)) && xclk_err_state)
+			`BMC_ASSERT(err_stb);
+		else if (ackfifo_fill > (o_wb_ack ? 2:1))
+			`BMC_ASSERT(!err_stb);
+	end
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Cover properties
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+	reg		cvr_abort;
+	reg	[3:0]	cvr_replies, cvr_post_abort;
+
+	initial	cvr_abort = 0;
+	always @(posedge i_wb_clk)
+	if (i_reset)
+		cvr_abort <= 0;
+	else if (o_wb_err && acks_outstanding > 2)
+		cvr_abort <= 1;
+
+	initial	cvr_replies = 0;
+	always @(posedge i_wb_clk)
+	if (i_reset)
+		cvr_replies <= 0;
+	else if (o_wb_ack || o_wb_err)
+		cvr_replies <= cvr_replies + 1;
+
+	initial	cvr_post_abort = 0;
+	always @(posedge i_wb_clk)
+	if (i_reset)
+		cvr_post_abort <= 0;
+	else if (cvr_abort && o_wb_ack)
+		cvr_post_abort <= cvr_post_abort + 1;
+
+	always @(*)
+	begin
+		cover(cvr_replies > 1);	// 33
+		cover(cvr_replies > 3);	// 38
+		cover(cvr_replies > 9);
+
+		cover(cvr_abort);	// 31
+		cover(cvr_post_abort > 1 && cvr_replies > 1);	// 63
+		cover(cvr_post_abort > 1 && cvr_replies > 2);	// 63
+		cover(cvr_post_abort > 1 && cvr_replies > 3);	// 65
+		cover(cvr_post_abort > 2 && cvr_replies > 3);	// 65
+		cover(cvr_post_abort > 3 && cvr_replies > 3);	// 68
+		cover(cvr_post_abort > 4 && cvr_replies > 3);	// 70
+		cover(cvr_post_abort > 3 && cvr_replies > 6);	// 72
+	end
+
+	always @(posedge gbl_clk)
+	if (!i_reset)
+		cover(cvr_replies > 9 && !i_wb_clk && acks_outstanding == 0
+			&& fwb_nreqs == fwb_nacks && fwb_nreqs == cvr_replies
+			&& !bus_abort && fwb_count != fxck_count);
+
+	always @(posedge gbl_clk)
+	if (!i_reset)
+		cover(cvr_replies > 9 && !i_wb_clk && acks_outstanding == 0
+			&& fwb_nreqs == fwb_nacks && fwb_nreqs == cvr_replies
+			&& !bus_abort && fwb_count != fxck_count
+			&& fwb_step != fxck_step);
+
+	// }}}
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Simplifying (careless) assumptions
+	// {{{
+	////////////////////////////////////////////////////////////////////////
+	//
+	//
+
+	// None (at present)
+
+	// }}}
+`endif
+// }}}
+endmodule
diff --git a/verilog/rtl/softshell/third_party/wb2axip/wb2axip.core b/verilog/rtl/softshell/third_party/wb2axip/wb2axip.core
new file mode 100644
index 0000000..357ca7e
--- /dev/null
+++ b/verilog/rtl/softshell/third_party/wb2axip/wb2axip.core
@@ -0,0 +1,13 @@
+CAPI=1
+[main]
+description = Pipelined Wishbone to AXI converter
+
+[fileset rtl]
+files = rtl/wbm2axisp.v
+file_type = verilogSource
+
+[provider]
+name=github
+user=ZipCPU
+repo=wb2axip
+version = master
diff --git a/verilog/rtl/user_proj_example.v b/verilog/rtl/user_proj_example.v
index 44e8eda..ac83e24 100644
--- a/verilog/rtl/user_proj_example.v
+++ b/verilog/rtl/user_proj_example.v
@@ -71,102 +71,47 @@
     output [`MPRJ_IO_PADS-1:0] io_out,
     output [`MPRJ_IO_PADS-1:0] io_oeb
 );
-    wire clk;
-    wire rst;
 
-    wire [`MPRJ_IO_PADS-1:0] io_in;
-    wire [`MPRJ_IO_PADS-1:0] io_out;
-    wire [`MPRJ_IO_PADS-1:0] io_oeb;
+    softshell_top softshell (
+    `ifdef USE_POWER_PINS
+	.vdda1(vdda1),	// User area 1 3.3V power
+	.vdda2(vdda2),	// User area 2 3.3V power
+	.vssa1(vssa1),	// User area 1 analog ground
+	.vssa2(vssa2),	// User area 2 analog ground
+	.vccd1(vccd1),	// User area 1 1.8V power
+	.vccd2(vccd2),	// User area 2 1.8V power
+	.vssd1(vssd1),	// User area 1 digital ground
+	.vssd2(vssd2),	// User area 2 digital ground
+    `endif
 
-    wire [31:0] rdata; 
-    wire [31:0] wdata;
-    wire [BITS-1:0] count;
+	// MGMT core clock and reset
 
-    wire valid;
-    wire [3:0] wstrb;
-    wire [31:0] la_write;
+    	.wb_clk_i(wb_clk_i),
+    	.wb_rst_i(wb_rst_i),
 
-    // WB MI A
-    assign valid = wbs_cyc_i && wbs_stb_i; 
-    assign wstrb = wbs_sel_i & {4{wbs_we_i}};
-    assign wbs_dat_o = rdata;
-    assign wdata = wbs_dat_i;
+	// MGMT SoC Wishbone Slave
 
-    // IO
-    assign io_out = count;
-    assign io_oeb = {(`MPRJ_IO_PADS-1){rst}};
+	.wbs_cyc_i(wbs_cyc_i),
+	.wbs_stb_i(wbs_stb_i),
+	.wbs_we_i(wbs_we_i),
+	.wbs_sel_i(wbs_sel_i),
+	.wbs_adr_i(wbs_adr_i),
+	.wbs_dat_i(wbs_dat_i),
+	.wbs_ack_o(wbs_ack_o),
+	.wbs_dat_o(wbs_dat_o),
 
-    // LA
-    assign la_data_out = {{(127-BITS){1'b0}}, count};
-    // Assuming LA probes [63:32] are for controlling the count register  
-    assign la_write = ~la_oen[63:32] & ~{BITS{valid}};
-    // Assuming LA probes [65:64] are for controlling the count clk & reset  
-    assign clk = (~la_oen[64]) ? la_data_in[64]: wb_clk_i;
-    assign rst = (~la_oen[65]) ? la_data_in[65]: wb_rst_i;
+	// Logic Analyzer
 
-    counter #(
-        .BITS(BITS)
-    ) counter(
-        .clk(clk),
-        .reset(rst),
-        .ready(wbs_ack_o),
-        .valid(valid),
-        .rdata(rdata),
-        .wdata(wbs_dat_i),
-        .wstrb(wstrb),
-        .la_write(la_write),
-        .la_input(la_data_in[63:32]),
-        .count(count)
+	.la_data_in(la_data_in),
+	.la_data_out(la_data_out),
+	.la_oen (la_oen),
+
+	// IO Pads
+
+	.io_in (io_in),
+    	.io_out(io_out),
+    	.io_oeb(io_oeb)
     );
 
 endmodule
-
-module counter #(
-    parameter BITS = 32
-)(
-    input clk,
-    input reset,
-    input valid,
-    input [3:0] wstrb,
-    input [BITS-1:0] wdata,
-    input [BITS-1:0] la_write,
-    input [BITS-1:0] la_input,
-    output ready,
-    output [BITS-1:0] rdata,
-    output [BITS-1:0] count
-);
-    reg ready;
-    reg [BITS-1:0] count;
-    reg [BITS-1:0] rdata;
-
-    always @(posedge clk) begin
-        if (reset) begin
-            count <= 0;
-            ready <= 0;
-        end else begin
-            ready <= 1'b0;
-            if (~|la_write) begin
-                count <= count + 1;
-            end
-            if (valid && !ready) begin
-                ready <= 1'b1;
-                rdata <= count;
-                if (wstrb[0]) count[7:0]   <= wdata[7:0];
-                if (wstrb[1]) count[15:8]  <= wdata[15:8];
-                if (wstrb[2]) count[23:16] <= wdata[23:16];
-                if (wstrb[3]) count[31:24] <= wdata[31:24];
-            end
-        end
-    end
-
-    genvar i;
-    generate 
-        for(i=0; i<BITS; i=i+1) begin
-          always @(posedge clk) begin
-              if (la_write[i]) count[i] <= la_input[i];
-          end
-        end
-    endgenerate
-
-endmodule
 `default_nettype wire
diff --git a/verilog/rtl/user_project_wrapper.v b/verilog/rtl/user_project_wrapper.v
index 47d92f4..5f47659 100644
--- a/verilog/rtl/user_project_wrapper.v
+++ b/verilog/rtl/user_project_wrapper.v
@@ -81,14 +81,8 @@
 
     user_proj_example mprj (
     `ifdef USE_POWER_PINS
-	.vdda1(vdda1),	// User area 1 3.3V power
-	.vdda2(vdda2),	// User area 2 3.3V power
-	.vssa1(vssa1),	// User area 1 analog ground
-	.vssa2(vssa2),	// User area 2 analog ground
-	.vccd1(vccd1),	// User area 1 1.8V power
-	.vccd2(vccd2),	// User area 2 1.8V power
-	.vssd1(vssd1),	// User area 1 digital ground
-	.vssd2(vssd2),	// User area 2 digital ground
+	.VPWR(vccd1),	// User area 1 1.8V power
+	.VGND(vssd1),	// User area 1 digital ground
     `endif
 
 	// MGMT core clock and reset