diff --git a/Makefile b/Makefile
index 9731d901b0bf4eb2b30f641b2f59593939387382..3fde87178bb48dfb294bb9135a0a8d38afca05a6 100644
--- a/Makefile
+++ b/Makefile
@@ -66,23 +66,34 @@ spike-tandem ?= $(SPIKE_TANDEM)
 
 SPIKE_INSTALL_DIR     ?= $(root-dir)/tools/spike
 
+
 # setting additional xilinx board parameters for the selected board
 ifeq ($(BOARD), genesys2)
 	XILINX_PART              := xc7k325tffg900-2
 	XILINX_BOARD             := digilentinc.com:genesys2:part0:1.1
 	CLK_PERIOD_NS            := 20
+	XILINX_JTAG_PROBE_FILES  := corev_apu/riscv-dbg/src/dmi_jtag_tap.sv corev_apu/riscv-dbg/src/dmi_jtag.sv corev_apu/riscv-dbg/src/dmi_cdc.sv
 else ifeq ($(BOARD), kc705)
 	XILINX_PART              := xc7k325tffg900-2
 	XILINX_BOARD             := xilinx.com:kc705:part0:1.5
 	CLK_PERIOD_NS            := 20
+	XILINX_JTAG_PROBE_FILES  := corev_apu/riscv-dbg/src/dmi_jtag_tap.sv corev_apu/riscv-dbg/src/dmi_jtag.sv corev_apu/riscv-dbg/src/dmi_cdc.sv
 else ifeq ($(BOARD), vc707)
 	XILINX_PART              := xc7vx485tffg1761-2
 	XILINX_BOARD             := xilinx.com:vc707:part0:1.3
 	CLK_PERIOD_NS            := 20
+	XILINX_JTAG_PROBE_FILES  := corev_apu/riscv-dbg/src/dmi_jtag_tap.sv corev_apu/riscv-dbg/src/dmi_jtag.sv corev_apu/riscv-dbg/src/dmi_cdc.sv
 else ifeq ($(BOARD), nexys_video)
 	XILINX_PART              := xc7a200tsbg484-1
 	XILINX_BOARD             := digilentinc.com:nexys_video:part0:1.1
 	CLK_PERIOD_NS            := 40
+	XILINX_JTAG_PROBE_FILES  := corev_apu/riscv-dbg/src/dmi_jtag_tap.sv corev_apu/riscv-dbg/src/dmi_jtag.sv corev_apu/riscv-dbg/src/dmi_cdc.sv
+else ifeq ($(BOARD), arty_a7_100)
+	XILINX_PART              := xc7a100tcsg324-1
+	XILINX_BOARD             := digilentinc.com:arty-a7-100:part0:1.1
+	CLK_PERIOD_NS            := 40
+	XILINX_JTAG_PROBE_FILES  := corev_apu/fpga/src/riscv_dbg_bscane_backport/dmi_bscane_tap.sv corev_apu/fpga/src/riscv_dbg_bscane_backport/dmi_jtag.sv corev_apu/fpga/src/riscv_dbg_bscane_backport/dmi_cdc.sv
+	DBG_BSCANE2              := 1
 else
 $(error Unknown board - please specify a supported FPGA board)
 endif
@@ -151,64 +162,67 @@ $(warning XCELIUM_HOME not set which is necessary for compiling DPIs when using
 endif
 
 # this list contains the standalone components
-src :=  $(if $(spike-tandem),verif/tb/core/uvma_core_cntrl_pkg.sv)                   \
-        $(if $(spike-tandem),verif/tb/core/uvma_cva6pkg_utils_pkg.sv)                \
-        $(if $(spike-tandem),verif/tb/core/uvma_rvfi_pkg.sv)                         \
-        $(if $(spike-tandem),verif/tb/core/uvmc_rvfi_reference_model_pkg.sv)         \
-        $(if $(spike-tandem),verif/tb/core/uvmc_rvfi_scoreboard_pkg.sv)              \
-        $(if $(spike-tandem),corev_apu/tb/common/spike.sv)                           \
-        core/cva6_rvfi.sv                                                            \
-        corev_apu/src/ariane.sv                                                      \
-        $(wildcard corev_apu/bootrom/*.sv)                                           \
-        $(wildcard corev_apu/clint/*.sv)                                             \
-        $(wildcard corev_apu/fpga/src/axi2apb/src/*.sv)                              \
-        $(wildcard corev_apu/fpga/src/apb_timer/*.sv)                                \
-        $(wildcard corev_apu/fpga/src/axi_slice/src/*.sv)                            \
-        $(wildcard corev_apu/src/axi_riscv_atomics/src/*.sv)                         \
-        $(wildcard corev_apu/axi_mem_if/src/*.sv)                                    \
-        corev_apu/rv_plic/rtl/rv_plic_target.sv                                      \
-        corev_apu/rv_plic/rtl/rv_plic_gateway.sv                                     \
-        corev_apu/rv_plic/rtl/plic_regmap.sv                                         \
-        corev_apu/rv_plic/rtl/plic_top.sv                                            \
-        corev_apu/riscv-dbg/src/dmi_cdc.sv                                           \
-        corev_apu/riscv-dbg/src/dmi_jtag.sv                                          \
-        corev_apu/riscv-dbg/src/dmi_jtag_tap.sv                                      \
-        corev_apu/riscv-dbg/src/dm_csrs.sv                                           \
-        corev_apu/riscv-dbg/src/dm_mem.sv                                            \
-        corev_apu/riscv-dbg/src/dm_sba.sv                                            \
-        corev_apu/riscv-dbg/src/dm_top.sv                                            \
-        corev_apu/riscv-dbg/debug_rom/debug_rom.sv                                   \
-        corev_apu/register_interface/src/apb_to_reg.sv                               \
-        vendor/pulp-platform/axi/src/axi_multicut.sv                                 \
-        vendor/pulp-platform/common_cells/src/rstgen_bypass.sv                       \
-        vendor/pulp-platform/common_cells/src/rstgen.sv                              \
-        vendor/pulp-platform/common_cells/src/addr_decode.sv                         \
-        vendor/pulp-platform/common_cells/src/stream_register.sv                     \
-        vendor/pulp-platform/axi/src/axi_cut.sv                                      \
-        vendor/pulp-platform/axi/src/axi_join.sv                                     \
-        vendor/pulp-platform/axi/src/axi_delayer.sv                                  \
-        vendor/pulp-platform/axi/src/axi_to_axi_lite.sv                              \
-        vendor/pulp-platform/axi/src/axi_id_prepend.sv                               \
-        vendor/pulp-platform/axi/src/axi_atop_filter.sv                              \
-        vendor/pulp-platform/axi/src/axi_err_slv.sv                                  \
-        vendor/pulp-platform/axi/src/axi_mux.sv                                      \
-        vendor/pulp-platform/axi/src/axi_demux.sv                                    \
-        vendor/pulp-platform/axi/src/axi_xbar.sv                                     \
-        vendor/pulp-platform/common_cells/src/cdc_2phase.sv                          \
-        vendor/pulp-platform/common_cells/src/spill_register_flushable.sv            \
-        vendor/pulp-platform/common_cells/src/spill_register.sv                      \
-        vendor/pulp-platform/common_cells/src/deprecated/fifo_v1.sv                  \
-        vendor/pulp-platform/common_cells/src/deprecated/fifo_v2.sv                  \
-        vendor/pulp-platform/common_cells/src/stream_delay.sv                        \
-        vendor/pulp-platform/common_cells/src/lfsr_16bit.sv                          \
-        vendor/pulp-platform/tech_cells_generic/src/deprecated/cluster_clk_cells.sv  \
-        vendor/pulp-platform/tech_cells_generic/src/deprecated/pulp_clk_cells.sv     \
-        vendor/pulp-platform/tech_cells_generic/src/rtl/tc_clk.sv                    \
-        corev_apu/tb/ariane_testharness.sv                                           \
-        corev_apu/tb/ariane_peripherals.sv                                           \
-        corev_apu/tb/rvfi_tracer.sv                                                  \
-        corev_apu/tb/common/uart.sv                                                  \
-        corev_apu/tb/common/SimDTM.sv                                                \
+src :=  $(if $(spike-tandem),verif/tb/core/uvma_core_cntrl_pkg.sv)                           \
+        $(if $(spike-tandem),verif/tb/core/uvma_cva6pkg_utils_pkg.sv)                        \
+        $(if $(spike-tandem),verif/tb/core/uvma_rvfi_pkg.sv)                                 \
+        $(if $(spike-tandem),verif/tb/core/uvmc_rvfi_reference_model_pkg.sv)                 \
+        $(if $(spike-tandem),verif/tb/core/uvmc_rvfi_scoreboard_pkg.sv)                      \
+        $(if $(spike-tandem),corev_apu/tb/common/spike.sv)                                   \
+        core/cva6_rvfi.sv                                                                    \
+        corev_apu/src/ariane.sv                                                              \
+        $(wildcard corev_apu/bootrom/*.sv)                                                   \
+        $(wildcard corev_apu/clint/*.sv)                                                     \
+        $(wildcard corev_apu/fpga/src/axi2apb/src/*.sv)                                      \
+        $(wildcard corev_apu/fpga/src/apb_timer/*.sv)                                        \
+        $(wildcard corev_apu/fpga/src/axi_slice/src/*.sv)                                    \
+        $(wildcard corev_apu/src/axi_riscv_atomics/src/*.sv)                                 \
+        $(wildcard corev_apu/axi_mem_if/src/*.sv)                                            \
+        corev_apu/rv_plic/rtl/rv_plic_target.sv                                              \
+        corev_apu/rv_plic/rtl/rv_plic_gateway.sv                                             \
+        corev_apu/rv_plic/rtl/plic_regmap.sv                                                 \
+        corev_apu/rv_plic/rtl/plic_top.sv                                                    \
+        $(XILINX_JTAG_PROBE_FILES)                            				     \
+        corev_apu/riscv-dbg/src/dm_csrs.sv                                                   \
+        corev_apu/riscv-dbg/src/dm_mem.sv                                                    \
+        corev_apu/riscv-dbg/src/dm_sba.sv                                                    \
+        corev_apu/riscv-dbg/src/dm_top.sv                                                    \
+        corev_apu/riscv-dbg/debug_rom/debug_rom.sv                                           \
+        corev_apu/register_interface/src/apb_to_reg.sv                                       \
+        vendor/pulp-platform/axi/src/axi_multicut.sv                                         \
+        vendor/pulp-platform/common_cells/src/rstgen_bypass.sv                               \
+        vendor/pulp-platform/common_cells/src/rstgen.sv                                      \
+        vendor/pulp-platform/common_cells/src/addr_decode.sv                                 \
+        vendor/pulp-platform/common_cells/src/stream_register.sv                             \
+	$(if $(DBG_BSCANE2),vendor/pulp-platform/common_cells/src/cdc_2phase_clearable.sv)   \
+	$(if $(DBG_BSCANE2),vendor/pulp-platform/common_cells/src/cdc_reset_ctrlr.sv)        \
+	$(if $(DBG_BSCANE2),vendor/pulp-platform/common_cells/src/cdc_reset_ctrlr_pkg.sv)    \
+	$(if $(DBG_BSCANE2),vendor/pulp-platform/common_cells/src/cdc_4phase.sv)             \
+	$(if $(DBG_BSCANE2),vendor/pulp-platform/common_cells/src/sync.sv)                   \
+        vendor/pulp-platform/axi/src/axi_cut.sv                                              \
+        vendor/pulp-platform/axi/src/axi_join.sv                                             \
+        vendor/pulp-platform/axi/src/axi_delayer.sv                                          \
+        vendor/pulp-platform/axi/src/axi_to_axi_lite.sv                                      \
+        vendor/pulp-platform/axi/src/axi_id_prepend.sv                                       \
+        vendor/pulp-platform/axi/src/axi_atop_filter.sv                                      \
+        vendor/pulp-platform/axi/src/axi_err_slv.sv                                          \
+        vendor/pulp-platform/axi/src/axi_mux.sv                                              \
+        vendor/pulp-platform/axi/src/axi_demux.sv                                            \
+        vendor/pulp-platform/axi/src/axi_xbar.sv                                             \
+        vendor/pulp-platform/common_cells/src/cdc_2phase.sv                                  \
+        vendor/pulp-platform/common_cells/src/spill_register_flushable.sv                    \
+        vendor/pulp-platform/common_cells/src/spill_register.sv                              \
+        vendor/pulp-platform/common_cells/src/deprecated/fifo_v1.sv                          \
+        vendor/pulp-platform/common_cells/src/deprecated/fifo_v2.sv                          \
+        vendor/pulp-platform/common_cells/src/stream_delay.sv                                \
+        vendor/pulp-platform/common_cells/src/lfsr_16bit.sv                                  \
+        vendor/pulp-platform/tech_cells_generic/src/deprecated/cluster_clk_cells.sv          \
+        vendor/pulp-platform/tech_cells_generic/src/deprecated/pulp_clk_cells.sv             \
+        vendor/pulp-platform/tech_cells_generic/src/rtl/tc_clk.sv                            \
+        corev_apu/tb/ariane_testharness.sv                                                   \
+        corev_apu/tb/ariane_peripherals.sv                                                   \
+        corev_apu/tb/rvfi_tracer.sv                                                          \
+        corev_apu/tb/common/uart.sv                                                          \
+        corev_apu/tb/common/SimDTM.sv                                                        \
         corev_apu/tb/common/SimJTAG.sv
 
 src := $(addprefix $(root-dir), $(src))
diff --git a/core/include/cv64a6_imac_sv39_config_pkg.sv b/core/include/cv64a6_imac_sv39_config_pkg.sv
new file mode 100644
index 0000000000000000000000000000000000000000..dda669ba8a170db07014e2be7a01705ffdb7c54e
--- /dev/null
+++ b/core/include/cv64a6_imac_sv39_config_pkg.sv
@@ -0,0 +1,157 @@
+// Copyright 2024 CISPA Helmholtz Center for Information Security
+//
+// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
+// You may obtain a copy of the License at https://solderpad.org/licenses/
+//
+// Cut-down version of CV64A6: no floating point support, smaller caches
+// Targeted to fit ARTY A7
+// Original Author: Eric Ackermann - CISPA
+
+
+package cva6_config_pkg;
+
+  localparam CVA6ConfigXlen = 64;
+
+  localparam CVA6ConfigRVF = 0;
+  localparam CVA6ConfigF16En = 0;
+  localparam CVA6ConfigF16AltEn = 0;
+  localparam CVA6ConfigF8En = 0;
+  localparam CVA6ConfigFVecEn = 0;
+
+  localparam CVA6ConfigCvxifEn = 1;
+  localparam CVA6ConfigCExtEn = 1;
+  localparam CVA6ConfigZcbExtEn = 1;
+  localparam CVA6ConfigZcmpExtEn = 0;
+  localparam CVA6ConfigAExtEn = 1;
+  localparam CVA6ConfigHExtEn = 0;  // always disabled
+  localparam CVA6ConfigBExtEn = 1;
+  localparam CVA6ConfigVExtEn = 0;
+  localparam CVA6ConfigRVZiCond = 1;
+
+  localparam CVA6ConfigAxiIdWidth = 4;
+  localparam CVA6ConfigAxiAddrWidth = 64;
+  localparam CVA6ConfigAxiDataWidth = 64;
+  localparam CVA6ConfigFetchUserEn = 0;
+  localparam CVA6ConfigFetchUserWidth = CVA6ConfigXlen;
+  localparam CVA6ConfigDataUserEn = 0;
+  localparam CVA6ConfigDataUserWidth = CVA6ConfigXlen;
+
+  localparam CVA6ConfigIcacheByteSize = 16384;
+  localparam CVA6ConfigIcacheSetAssoc = 4;
+  localparam CVA6ConfigIcacheLineWidth = 128;
+  localparam CVA6ConfigDcacheByteSize = 32768;
+  localparam CVA6ConfigDcacheSetAssoc = 8;
+  localparam CVA6ConfigDcacheLineWidth = 128;
+
+  localparam CVA6ConfigDcacheIdWidth = 1;
+  localparam CVA6ConfigMemTidWidth = 2;
+
+  localparam CVA6ConfigWtDcacheWbufDepth = 8;
+
+  localparam CVA6ConfigNrScoreboardEntries = 8;
+
+  localparam CVA6ConfigFpgaEn = 0;
+
+  localparam CVA6ConfigNrLoadPipeRegs = 1;
+  localparam CVA6ConfigNrStorePipeRegs = 0;
+  localparam CVA6ConfigNrLoadBufEntries = 2;
+
+  localparam CVA6ConfigRASDepth = 2;
+  localparam CVA6ConfigBTBEntries = 32;
+  localparam CVA6ConfigBHTEntries = 128;
+
+  localparam CVA6ConfigTvalEn = 1;
+
+  localparam CVA6ConfigNrPMPEntries = 8;
+
+  localparam CVA6ConfigPerfCounterEn = 1;
+
+  localparam config_pkg::cache_type_t CVA6ConfigDcacheType = config_pkg::WT;
+
+  localparam CVA6ConfigMmuPresent = 1;
+
+  localparam CVA6ConfigRvfiTrace = 1;
+
+  localparam config_pkg::cva6_user_cfg_t cva6_cfg = '{
+      XLEN: unsigned'(CVA6ConfigXlen),
+      VLEN: unsigned'(64),
+      FpgaEn: bit'(CVA6ConfigFpgaEn),
+      TechnoCut: bit'(0),
+      SuperscalarEn: bit'(0),
+      NrCommitPorts: unsigned'(2),
+      AxiAddrWidth: unsigned'(CVA6ConfigAxiAddrWidth),
+      AxiDataWidth: unsigned'(CVA6ConfigAxiDataWidth),
+      AxiIdWidth: unsigned'(CVA6ConfigAxiIdWidth),
+      AxiUserWidth: unsigned'(CVA6ConfigDataUserWidth),
+      MemTidWidth: unsigned'(CVA6ConfigMemTidWidth),
+      NrLoadBufEntries: unsigned'(CVA6ConfigNrLoadBufEntries),
+      RVF: bit'(CVA6ConfigRVF),
+      RVD: bit'(CVA6ConfigRVF),
+      XF16: bit'(CVA6ConfigF16En),
+      XF16ALT: bit'(CVA6ConfigF16AltEn),
+      XF8: bit'(CVA6ConfigF8En),
+      RVA: bit'(CVA6ConfigAExtEn),
+      RVB: bit'(CVA6ConfigBExtEn),
+      RVV: bit'(CVA6ConfigVExtEn),
+      RVC: bit'(CVA6ConfigCExtEn),
+      RVH: bit'(CVA6ConfigHExtEn),
+      RVZCB: bit'(CVA6ConfigZcbExtEn),
+      RVZCMP: bit'(CVA6ConfigZcmpExtEn),
+      XFVec: bit'(CVA6ConfigFVecEn),
+      CvxifEn: bit'(CVA6ConfigCvxifEn),
+      RVZiCond: bit'(CVA6ConfigRVZiCond),
+      RVZicntr: bit'(1),
+      RVZihpm: bit'(1),
+      NrScoreboardEntries: unsigned'(CVA6ConfigNrScoreboardEntries),
+      PerfCounterEn: bit'(CVA6ConfigPerfCounterEn),
+      MmuPresent: bit'(CVA6ConfigMmuPresent),
+      RVS: bit'(1),
+      RVU: bit'(1),
+      HaltAddress: 64'h800,
+      ExceptionAddress: 64'h808,
+      RASDepth: unsigned'(CVA6ConfigRASDepth),
+      BTBEntries: unsigned'(CVA6ConfigBTBEntries),
+      BHTEntries: unsigned'(CVA6ConfigBHTEntries),
+      DmBaseAddress: 64'h0,
+      TvalEn: bit'(CVA6ConfigTvalEn),
+      DirectVecOnly: bit'(0),
+      NrPMPEntries: unsigned'(CVA6ConfigNrPMPEntries),
+      PMPCfgRstVal: {64{64'h0}},
+      PMPAddrRstVal: {64{64'h0}},
+      PMPEntryReadOnly: 64'd0,
+      NOCType: config_pkg::NOC_TYPE_AXI4_ATOP,
+      NrNonIdempotentRules: unsigned'(2),
+      NonIdempotentAddrBase: 1024'({64'b0, 64'b0}),
+      NonIdempotentLength: 1024'({64'b0, 64'b0}),
+      NrExecuteRegionRules: unsigned'(3),
+      ExecuteRegionAddrBase: 1024'({64'h8000_0000, 64'h1_0000, 64'h0}),
+      ExecuteRegionLength: 1024'({64'h40000000, 64'h10000, 64'h1000}),
+      NrCachedRegionRules: unsigned'(1),
+      CachedRegionAddrBase: 1024'({64'h8000_0000}),
+      CachedRegionLength: 1024'({64'h40000000}),
+      MaxOutstandingStores: unsigned'(7),
+      DebugEn: bit'(1),
+      AxiBurstWriteEn: bit'(0),
+      IcacheByteSize: unsigned'(CVA6ConfigIcacheByteSize),
+      IcacheSetAssoc: unsigned'(CVA6ConfigIcacheSetAssoc),
+      IcacheLineWidth: unsigned'(CVA6ConfigIcacheLineWidth),
+      DCacheType: CVA6ConfigDcacheType,
+      DcacheByteSize: unsigned'(CVA6ConfigDcacheByteSize),
+      DcacheSetAssoc: unsigned'(CVA6ConfigDcacheSetAssoc),
+      DcacheLineWidth: unsigned'(CVA6ConfigDcacheLineWidth),
+      DataUserEn: unsigned'(CVA6ConfigDataUserEn),
+      WtDcacheWbufDepth: int'(CVA6ConfigWtDcacheWbufDepth),
+      FetchUserWidth: unsigned'(CVA6ConfigFetchUserWidth),
+      FetchUserEn: unsigned'(CVA6ConfigFetchUserEn),
+      InstrTlbEntries: int'(16),
+      DataTlbEntries: int'(16),
+      UseSharedTlb: bit'(0),
+      SharedTlbDepth: int'(64),
+      NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs),
+      NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs),
+      DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth)
+  };
+
+endpackage
diff --git a/core/include/cv64a6_imafdc_sv39_fpga_config_pkg.sv b/core/include/cv64a6_imafdc_sv39_fpga_config_pkg.sv
new file mode 100644
index 0000000000000000000000000000000000000000..057931bb23c75775e6e1f6078012139228f2879e
--- /dev/null
+++ b/core/include/cv64a6_imafdc_sv39_fpga_config_pkg.sv
@@ -0,0 +1,155 @@
+// Copyright 2021 Thales DIS design services SAS
+//
+// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
+// You may obtain a copy of the License at https://solderpad.org/licenses/
+//
+// Original Author: Jean-Roch COULON - Thales
+
+
+package cva6_config_pkg;
+
+  localparam CVA6ConfigXlen = 64;
+
+  localparam CVA6ConfigRVF = 1;
+  localparam CVA6ConfigF16En = 0;
+  localparam CVA6ConfigF16AltEn = 0;
+  localparam CVA6ConfigF8En = 0;
+  localparam CVA6ConfigFVecEn = 0;
+
+  localparam CVA6ConfigCvxifEn = 1;
+  localparam CVA6ConfigCExtEn = 1;
+  localparam CVA6ConfigZcbExtEn = 1;
+  localparam CVA6ConfigZcmpExtEn = 0;
+  localparam CVA6ConfigAExtEn = 1;
+  localparam CVA6ConfigHExtEn = 0;  // always disabled
+  localparam CVA6ConfigBExtEn = 1;
+  localparam CVA6ConfigVExtEn = 0;
+  localparam CVA6ConfigRVZiCond = 1;
+
+  localparam CVA6ConfigAxiIdWidth = 4;
+  localparam CVA6ConfigAxiAddrWidth = 64;
+  localparam CVA6ConfigAxiDataWidth = 64;
+  localparam CVA6ConfigFetchUserEn = 0;
+  localparam CVA6ConfigFetchUserWidth = CVA6ConfigXlen;
+  localparam CVA6ConfigDataUserEn = 0;
+  localparam CVA6ConfigDataUserWidth = CVA6ConfigXlen;
+
+  localparam CVA6ConfigIcacheByteSize = 16384;
+  localparam CVA6ConfigIcacheSetAssoc = 4;
+  localparam CVA6ConfigIcacheLineWidth = 128;
+  localparam CVA6ConfigDcacheByteSize = 32768;
+  localparam CVA6ConfigDcacheSetAssoc = 8;
+  localparam CVA6ConfigDcacheLineWidth = 128;
+
+  localparam CVA6ConfigDcacheIdWidth = 1;
+  localparam CVA6ConfigMemTidWidth = 2;
+
+  localparam CVA6ConfigWtDcacheWbufDepth = 8;
+
+  localparam CVA6ConfigNrScoreboardEntries = 8;
+
+  localparam CVA6ConfigFpgaEn = 1;
+
+  localparam CVA6ConfigNrLoadPipeRegs = 1;
+  localparam CVA6ConfigNrStorePipeRegs = 0;
+  localparam CVA6ConfigNrLoadBufEntries = 2;
+
+  localparam CVA6ConfigRASDepth = 2;
+  localparam CVA6ConfigBTBEntries = 32;
+  localparam CVA6ConfigBHTEntries = 128;
+
+  localparam CVA6ConfigTvalEn = 1;
+
+  localparam CVA6ConfigNrPMPEntries = 8;
+
+  localparam CVA6ConfigPerfCounterEn = 1;
+
+  localparam config_pkg::cache_type_t CVA6ConfigDcacheType = config_pkg::WT;
+
+  localparam CVA6ConfigMmuPresent = 1;
+
+  localparam CVA6ConfigRvfiTrace = 1;
+
+  localparam config_pkg::cva6_user_cfg_t cva6_cfg = '{
+      XLEN: unsigned'(CVA6ConfigXlen),
+      VLEN: unsigned'(64),
+      FpgaEn: bit'(CVA6ConfigFpgaEn),
+      TechnoCut: bit'(0),
+      SuperscalarEn: bit'(0),
+      NrCommitPorts: unsigned'(2),
+      AxiAddrWidth: unsigned'(CVA6ConfigAxiAddrWidth),
+      AxiDataWidth: unsigned'(CVA6ConfigAxiDataWidth),
+      AxiIdWidth: unsigned'(CVA6ConfigAxiIdWidth),
+      AxiUserWidth: unsigned'(CVA6ConfigDataUserWidth),
+      MemTidWidth: unsigned'(CVA6ConfigMemTidWidth),
+      NrLoadBufEntries: unsigned'(CVA6ConfigNrLoadBufEntries),
+      RVF: bit'(CVA6ConfigRVF),
+      RVD: bit'(CVA6ConfigRVF),
+      XF16: bit'(CVA6ConfigF16En),
+      XF16ALT: bit'(CVA6ConfigF16AltEn),
+      XF8: bit'(CVA6ConfigF8En),
+      RVA: bit'(CVA6ConfigAExtEn),
+      RVB: bit'(CVA6ConfigBExtEn),
+      RVV: bit'(CVA6ConfigVExtEn),
+      RVC: bit'(CVA6ConfigCExtEn),
+      RVH: bit'(CVA6ConfigHExtEn),
+      RVZCB: bit'(CVA6ConfigZcbExtEn),
+      RVZCMP: bit'(CVA6ConfigZcmpExtEn),
+      XFVec: bit'(CVA6ConfigFVecEn),
+      CvxifEn: bit'(CVA6ConfigCvxifEn),
+      RVZiCond: bit'(CVA6ConfigRVZiCond),
+      RVZicntr: bit'(1),
+      RVZihpm: bit'(1),
+      NrScoreboardEntries: unsigned'(CVA6ConfigNrScoreboardEntries),
+      PerfCounterEn: bit'(CVA6ConfigPerfCounterEn),
+      MmuPresent: bit'(CVA6ConfigMmuPresent),
+      RVS: bit'(1),
+      RVU: bit'(1),
+      HaltAddress: 64'h800,
+      ExceptionAddress: 64'h808,
+      RASDepth: unsigned'(CVA6ConfigRASDepth),
+      BTBEntries: unsigned'(CVA6ConfigBTBEntries),
+      BHTEntries: unsigned'(CVA6ConfigBHTEntries),
+      DmBaseAddress: 64'h0,
+      TvalEn: bit'(CVA6ConfigTvalEn),
+      DirectVecOnly: bit'(0),
+      NrPMPEntries: unsigned'(CVA6ConfigNrPMPEntries),
+      PMPCfgRstVal: {64{64'h0}},
+      PMPAddrRstVal: {64{64'h0}},
+      PMPEntryReadOnly: 64'd0,
+      NOCType: config_pkg::NOC_TYPE_AXI4_ATOP,
+      NrNonIdempotentRules: unsigned'(2),
+      NonIdempotentAddrBase: 1024'({64'b0, 64'b0}),
+      NonIdempotentLength: 1024'({64'b0, 64'b0}),
+      NrExecuteRegionRules: unsigned'(3),
+      ExecuteRegionAddrBase: 1024'({64'h8000_0000, 64'h1_0000, 64'h0}),
+      ExecuteRegionLength: 1024'({64'h40000000, 64'h10000, 64'h1000}),
+      NrCachedRegionRules: unsigned'(1),
+      CachedRegionAddrBase: 1024'({64'h8000_0000}),
+      CachedRegionLength: 1024'({64'h40000000}),
+      MaxOutstandingStores: unsigned'(7),
+      DebugEn: bit'(1),
+      AxiBurstWriteEn: bit'(0),
+      IcacheByteSize: unsigned'(CVA6ConfigIcacheByteSize),
+      IcacheSetAssoc: unsigned'(CVA6ConfigIcacheSetAssoc),
+      IcacheLineWidth: unsigned'(CVA6ConfigIcacheLineWidth),
+      DCacheType: CVA6ConfigDcacheType,
+      DcacheByteSize: unsigned'(CVA6ConfigDcacheByteSize),
+      DcacheSetAssoc: unsigned'(CVA6ConfigDcacheSetAssoc),
+      DcacheLineWidth: unsigned'(CVA6ConfigDcacheLineWidth),
+      DataUserEn: unsigned'(CVA6ConfigDataUserEn),
+      WtDcacheWbufDepth: int'(CVA6ConfigWtDcacheWbufDepth),
+      FetchUserWidth: unsigned'(CVA6ConfigFetchUserWidth),
+      FetchUserEn: unsigned'(CVA6ConfigFetchUserEn),
+      InstrTlbEntries: int'(16),
+      DataTlbEntries: int'(16),
+      UseSharedTlb: bit'(0),
+      SharedTlbDepth: int'(64),
+      NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs),
+      NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs),
+      DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth)
+  };
+
+endpackage
diff --git a/corev_apu/fpga/ariane_arty_a7.cfg b/corev_apu/fpga/ariane_arty_a7.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..625679278b37eaf59d7711df96a9194dd1143361
--- /dev/null
+++ b/corev_apu/fpga/ariane_arty_a7.cfg
@@ -0,0 +1,39 @@
+adapter driver ftdi
+
+transport select jtag
+
+ftdi vid_pid 0x0403 0x6010
+
+# Channel 1 is UART
+ftdi channel 0
+
+# https://github.com/epsilon537/boxlambda/blob/master/scripts/arty_a7_100t.openocd.cfg
+ftdi layout_init 0x00e8 0x60eb
+
+set _CHIPNAME riscv
+jtag newtap $_CHIPNAME cpu -irlen 6 -expected-id 0x13631093
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid 0
+
+riscv set_ir idcode 0x09
+riscv set_ir dtmcs 0x22
+riscv set_ir dmi 0x23
+
+riscv set_command_timeout_sec 120
+
+adapter speed  100
+
+# prefer to use sba for system bus access
+riscv set_mem_access progbuf abstract sysbus
+
+gdb_report_data_abort enable
+gdb_report_register_access_error enable
+
+# Try enabling address translation (only works for newer versions)
+if { [catch {riscv set_enable_virtual on} ] } {
+    echo "Warning: This version of OpenOCD does not support address translation. To debug on virtual addresses, please update to the latest version." }
+
+init
+halt
+echo "Ready for Remote Connections"
diff --git a/corev_apu/fpga/constraints/arty_a7_100.xdc b/corev_apu/fpga/constraints/arty_a7_100.xdc
new file mode 100644
index 0000000000000000000000000000000000000000..fbc922f7adf9431f4be11b56a760bac76fa5f984
--- /dev/null
+++ b/corev_apu/fpga/constraints/arty_a7_100.xdc
@@ -0,0 +1,172 @@
+## On board single ended clock, 100MHz
+set_property -dict { PACKAGE_PIN E3    IOSTANDARD LVCMOS33 } [get_ports { board_clk_i }]; #IO_L12P_T1_MRCC_35 Sch=gclk[100]
+create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports { board_clk_i }];
+
+# prevent DRC error related to routing constraint set by MiG
+set_property CLOCK_DEDICATED_ROUTE TRUE [get_nets sys_clk_i]
+
+## Switches
+set_property -dict { PACKAGE_PIN A8    IOSTANDARD LVCMOS33 } [get_ports { sw[0] }]; #IO_L12N_T1_MRCC_16 Sch=sw[0]
+set_property -dict { PACKAGE_PIN C11   IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L13P_T2_MRCC_16 Sch=sw[1]
+set_property -dict { PACKAGE_PIN C10   IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L13N_T2_MRCC_16 Sch=sw[2]
+set_property -dict { PACKAGE_PIN A10   IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L14P_T2_SRCC_16 Sch=sw[3]
+
+## LEDs
+set_property -dict { PACKAGE_PIN H5    IOSTANDARD LVCMOS33 } [get_ports { led[0] }]; #IO_L24N_T3_35 Sch=led[4]
+set_property -dict { PACKAGE_PIN J5    IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; #IO_25_35 Sch=led[5]
+set_property -dict { PACKAGE_PIN T9    IOSTANDARD LVCMOS33 } [get_ports { led[2] }]; #IO_L24P_T3_A01_D17_14 Sch=led[6]
+set_property -dict { PACKAGE_PIN T10   IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; #IO_L24N_T3_A00_D16_14 Sch=led[7]
+
+## The red "reset" button
+set_property -dict { PACKAGE_PIN C2    IOSTANDARD LVCMOS33 } [get_ports { cpu_resetn }]; #IO_L6N_T0_VREF_16 Sch=btn[0]
+
+
+## Pmod Header JA - SD / MicroSD Pmod
+## Pin 1 is SS
+## Pin 2 is MOSI
+## Pin 3 is MISO
+## Pin 4 is CLK
+set_property -dict { PACKAGE_PIN G13   IOSTANDARD LVCMOS33 } [get_ports { spi_ss }]; #IO_0_15 Sch=ja[1]
+set_property -dict { PACKAGE_PIN B11   IOSTANDARD LVCMOS33 } [get_ports { spi_mosi }]; #IO_L4P_T0_15 Sch=ja[2]
+set_property -dict { PACKAGE_PIN A11   IOSTANDARD LVCMOS33 } [get_ports { spi_miso }]; #IO_L4N_T0_15 Sch=ja[3]
+set_property -dict { PACKAGE_PIN D12   IOSTANDARD LVCMOS33 } [get_ports { spi_clk_o }]; #IO_L6P_T0_15 Sch=ja[4]
+
+## USB-UART Interface
+set_property -dict { PACKAGE_PIN D10   IOSTANDARD LVCMOS33 } [get_ports { tx }]; #IO_L19N_T3_VREF_16 Sch=uart_rxd_out
+set_property -dict { PACKAGE_PIN A9    IOSTANDARD LVCMOS33 } [get_ports { rx }]; #IO_L14N_T2_SRCC_16 Sch=uart_txd_in
+
+## ChipKit Outer Digital Header
+#set_property -dict { PACKAGE_PIN V15   IOSTANDARD LVCMOS33 } [get_ports { ck_io0  }]; #IO_L16P_T2_CSI_B_14 Sch=ck_io[0]
+#set_property -dict { PACKAGE_PIN U16   IOSTANDARD LVCMOS33 } [get_ports { ck_io1  }]; #IO_L18P_T2_A12_D28_14 Sch=ck_io[1]
+#set_property -dict { PACKAGE_PIN P14   IOSTANDARD LVCMOS33 } [get_ports { ck_io2  }]; #IO_L8N_T1_D12_14 Sch=ck_io[2]
+#set_property -dict { PACKAGE_PIN T11   IOSTANDARD LVCMOS33 } [get_ports { ck_io3  }]; #IO_L19P_T3_A10_D26_14 Sch=ck_io[3]
+#set_property -dict { PACKAGE_PIN R12   IOSTANDARD LVCMOS33 } [get_ports { ck_io4  }]; #IO_L5P_T0_D06_14 Sch=ck_io[4]
+#set_property -dict { PACKAGE_PIN T14   IOSTANDARD LVCMOS33 } [get_ports { ck_io5  }]; #IO_L14P_T2_SRCC_14 Sch=ck_io[5]
+#set_property -dict { PACKAGE_PIN T15   IOSTANDARD LVCMOS33 } [get_ports { ck_io6  }]; #IO_L14N_T2_SRCC_14 Sch=ck_io[6]
+#set_property -dict { PACKAGE_PIN T16   IOSTANDARD LVCMOS33 } [get_ports { ck_io7  }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=ck_io[7]
+#set_property -dict { PACKAGE_PIN N15   IOSTANDARD LVCMOS33 } [get_ports { ck_io8  }]; #IO_L11P_T1_SRCC_14 Sch=ck_io[8]
+#set_property -dict { PACKAGE_PIN M16   IOSTANDARD LVCMOS33 } [get_ports { ck_io9  }]; #IO_L10P_T1_D14_14 Sch=ck_io[9]
+#set_property -dict { PACKAGE_PIN V17   IOSTANDARD LVCMOS33 } [get_ports { ck_io10 }]; #IO_L18N_T2_A11_D27_14 Sch=ck_io[10]
+#set_property -dict { PACKAGE_PIN U18   IOSTANDARD LVCMOS33 } [get_ports { ck_io11 }]; #IO_L17N_T2_A13_D29_14 Sch=ck_io[11]
+#set_property -dict { PACKAGE_PIN R17   IOSTANDARD LVCMOS33 } [get_ports { ck_io12 }]; #IO_L12N_T1_MRCC_14 Sch=ck_io[12]
+#set_property -dict { PACKAGE_PIN P17   IOSTANDARD LVCMOS33 } [get_ports { ck_io13 }]; #IO_L12P_T1_MRCC_14 Sch=ck_io[13]
+
+## ChipKit Inner Digital Header
+#set_property -dict { PACKAGE_PIN U11   IOSTANDARD LVCMOS33 } [get_ports { ck_io26 }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=ck_io[26]
+#set_property -dict { PACKAGE_PIN V16   IOSTANDARD LVCMOS33 } [get_ports { ck_io27 }]; #IO_L16N_T2_A15_D31_14 Sch=ck_io[27]
+#set_property -dict { PACKAGE_PIN M13   IOSTANDARD LVCMOS33 } [get_ports { ck_io28 }]; #IO_L6N_T0_D08_VREF_14 Sch=ck_io[28]
+#set_property -dict { PACKAGE_PIN R10   IOSTANDARD LVCMOS33 } [get_ports { ck_io29 }]; #IO_25_14 Sch=ck_io[29]
+#set_property -dict { PACKAGE_PIN R11   IOSTANDARD LVCMOS33 } [get_ports { ck_io30 }]; #IO_0_14 Sch=ck_io[30]
+#set_property -dict { PACKAGE_PIN R13   IOSTANDARD LVCMOS33 } [get_ports { ck_io31 }]; #IO_L5N_T0_D07_14 Sch=ck_io[31]
+#set_property -dict { PACKAGE_PIN R15   IOSTANDARD LVCMOS33 } [get_ports { ck_io32 }]; #IO_L13N_T2_MRCC_14 Sch=ck_io[32]
+#set_property -dict { PACKAGE_PIN P15   IOSTANDARD LVCMOS33 } [get_ports { ck_io33 }]; #IO_L13P_T2_MRCC_14 Sch=ck_io[33]
+#set_property -dict { PACKAGE_PIN R16   IOSTANDARD LVCMOS33 } [get_ports { ck_io34 }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=ck_io[34]
+#set_property -dict { PACKAGE_PIN N16   IOSTANDARD LVCMOS33 } [get_ports { ck_io35 }]; #IO_L11N_T1_SRCC_14 Sch=ck_io[35]
+#set_property -dict { PACKAGE_PIN N14   IOSTANDARD LVCMOS33 } [get_ports { ck_io36 }]; #IO_L8P_T1_D11_14 Sch=ck_io[36]
+#set_property -dict { PACKAGE_PIN U17   IOSTANDARD LVCMOS33 } [get_ports { ck_io37 }]; #IO_L17P_T2_A14_D30_14 Sch=ck_io[37]
+#set_property -dict { PACKAGE_PIN T18   IOSTANDARD LVCMOS33 } [get_ports { ck_io38 }]; #IO_L7N_T1_D10_14 Sch=ck_io[38]
+#set_property -dict { PACKAGE_PIN R18   IOSTANDARD LVCMOS33 } [get_ports { ck_io39 }]; #IO_L7P_T1_D09_14 Sch=ck_io[39]
+#set_property -dict { PACKAGE_PIN P18   IOSTANDARD LVCMOS33 } [get_ports { ck_io40 }]; #IO_L9N_T1_DQS_D13_14 Sch=ck_io[40]
+#set_property -dict { PACKAGE_PIN N17   IOSTANDARD LVCMOS33 } [get_ports { ck_io41 }]; #IO_L9P_T1_DQS_14 Sch=ck_io[41]
+
+## ChipKit Outer Analog Header - as Single-Ended Analog Inputs
+## NOTE: These ports can be used as single-ended analog inputs with voltages from 0-3.3V (ChipKit analog pins A0-A5) or as digital I/O.
+## WARNING: Do not use both sets of constraints at the same time!
+## NOTE: The following constraints should be used with the XADC IP core when using these ports as analog inputs.
+#set_property -dict { PACKAGE_PIN C5    IOSTANDARD LVCMOS33 } [get_ports { vaux4_n  }]; #IO_L1N_T0_AD4N_35 	   Sch=ck_an_n[0] ChipKit pin=A0
+#set_property -dict { PACKAGE_PIN C6    IOSTANDARD LVCMOS33 } [get_ports { vaux4_p  }]; #IO_L1P_T0_AD4P_35 	   Sch=ck_an_p[0] ChipKit pin=A0
+#set_property -dict { PACKAGE_PIN A5    IOSTANDARD LVCMOS33 } [get_ports { vaux5_n  }]; #IO_L3N_T0_DQS_AD5N_35 Sch=ck_an_n[1] ChipKit pin=A1
+#set_property -dict { PACKAGE_PIN A6    IOSTANDARD LVCMOS33 } [get_ports { vaux5_p  }]; #IO_L3P_T0_DQS_AD5P_35 Sch=ck_an_p[1] ChipKit pin=A1
+#set_property -dict { PACKAGE_PIN B4    IOSTANDARD LVCMOS33 } [get_ports { vaux6_n  }]; #IO_L7N_T1_AD6N_35 	   Sch=ck_an_n[2] ChipKit pin=A2
+#set_property -dict { PACKAGE_PIN C4    IOSTANDARD LVCMOS33 } [get_ports { vaux6_p  }]; #IO_L7P_T1_AD6P_35 	   Sch=ck_an_p[2] ChipKit pin=A2
+#set_property -dict { PACKAGE_PIN A1    IOSTANDARD LVCMOS33 } [get_ports { vaux7_n  }]; #IO_L9N_T1_DQS_AD7N_35 Sch=ck_an_n[3] ChipKit pin=A3
+#set_property -dict { PACKAGE_PIN B1    IOSTANDARD LVCMOS33 } [get_ports { vaux7_p  }]; #IO_L9P_T1_DQS_AD7P_35 Sch=ck_an_p[3] ChipKit pin=A3
+#set_property -dict { PACKAGE_PIN B2    IOSTANDARD LVCMOS33 } [get_ports { vaux15_n }]; #IO_L10N_T1_AD15N_35   Sch=ck_an_n[4] ChipKit pin=A4
+#set_property -dict { PACKAGE_PIN B3    IOSTANDARD LVCMOS33 } [get_ports { vaux15_p }]; #IO_L10P_T1_AD15P_35   Sch=ck_an_p[4] ChipKit pin=A4
+#set_property -dict { PACKAGE_PIN C14   IOSTANDARD LVCMOS33 } [get_ports { vaux0_n  }]; #IO_L1N_T0_AD0N_15 	   Sch=ck_an_n[5] ChipKit pin=A5
+#set_property -dict { PACKAGE_PIN D14   IOSTANDARD LVCMOS33 } [get_ports { vaux0_p  }]; #IO_L1P_T0_AD0P_15 	   Sch=ck_an_p[5] ChipKit pin=A5
+## ChipKit Outer Analog Header - as Digital I/O
+## NOTE: The following constraints should be used when using these ports as digital I/O.
+# set_property -dict { PACKAGE_PIN F5    IOSTANDARD LVCMOS33 } [get_ports { ck_a0 }]; #IO_0_35 Sch=ck_a[0]
+#set_property -dict { PACKAGE_PIN D8    IOSTANDARD LVCMOS33 } [get_ports { ck_a1 }]; #IO_L4P_T0_35 Sch=ck_a[1]
+#set_property -dict { PACKAGE_PIN C7    IOSTANDARD LVCMOS33 } [get_ports { ck_a2 }]; #IO_L4N_T0_35 Sch=ck_a[2]
+#set_property -dict { PACKAGE_PIN E7    IOSTANDARD LVCMOS33 } [get_ports { ck_a3 }]; #IO_L6P_T0_35 Sch=ck_a[3]
+#set_property -dict { PACKAGE_PIN D7    IOSTANDARD LVCMOS33 } [get_ports { ck_a4 }]; #IO_L6N_T0_VREF_35 Sch=ck_a[4]
+#set_property -dict { PACKAGE_PIN D5    IOSTANDARD LVCMOS33 } [get_ports { ck_a5 }]; #IO_L11P_T1_SRCC_35 Sch=ck_a[5]
+
+## ChipKit Inner Analog Header - as Differential Analog Inputs
+## NOTE: These ports can be used as differential analog inputs with voltages from 0-1.0V (ChipKit analog pins A6-A11) or as digital I/O.
+## WARNING: Do not use both sets of constraints at the same time!
+## NOTE: The following constraints should be used with the XADC core when using these ports as analog inputs.
+#set_property -dict { PACKAGE_PIN B7    IOSTANDARD LVCMOS33 } [get_ports { vaux12_p }]; #IO_L2P_T0_AD12P_35 Sch=ad_p[12] ChipKit pin=A6
+#set_property -dict { PACKAGE_PIN B6    IOSTANDARD LVCMOS33 } [get_ports { vaux12_n }]; #IO_L2N_T0_AD12N_35 Sch=ad_n[12] ChipKit pin=A7
+#set_property -dict { PACKAGE_PIN E6    IOSTANDARD LVCMOS33 } [get_ports { vaux13_p }]; #IO_L5P_T0_AD13P_35 Sch=ad_p[13] ChipKit pin=A8
+#set_property -dict { PACKAGE_PIN E5    IOSTANDARD LVCMOS33 } [get_ports { vaux13_n }]; #IO_L5N_T0_AD13N_35 Sch=ad_n[13] ChipKit pin=A9
+#set_property -dict { PACKAGE_PIN A4    IOSTANDARD LVCMOS33 } [get_ports { vaux14_p }]; #IO_L8P_T1_AD14P_35 Sch=ad_p[14] ChipKit pin=A10
+#set_property -dict { PACKAGE_PIN A3    IOSTANDARD LVCMOS33 } [get_ports { vaux14_n }]; #IO_L8N_T1_AD14N_35 Sch=ad_n[14] ChipKit pin=A11
+## ChipKit Inner Analog Header - as Digital I/O
+## NOTE: The following constraints should be used when using the inner analog header ports as digital I/O.
+#set_property -dict { PACKAGE_PIN B7    IOSTANDARD LVCMOS33 } [get_ports { ck_a6  }]; #IO_L2P_T0_AD12P_35 Sch=ad_p[12]
+#set_property -dict { PACKAGE_PIN B6    IOSTANDARD LVCMOS33 } [get_ports { ck_a7  }]; #IO_L2N_T0_AD12N_35 Sch=ad_n[12]
+#set_property -dict { PACKAGE_PIN E6    IOSTANDARD LVCMOS33 } [get_ports { ck_a8  }]; #IO_L5P_T0_AD13P_35 Sch=ad_p[13]
+#set_property -dict { PACKAGE_PIN E5    IOSTANDARD LVCMOS33 } [get_ports { ck_a9  }]; #IO_L5N_T0_AD13N_35 Sch=ad_n[13]
+#set_property -dict { PACKAGE_PIN A4    IOSTANDARD LVCMOS33 } [get_ports { ck_a10 }]; #IO_L8P_T1_AD14P_35 Sch=ad_p[14]
+#set_property -dict { PACKAGE_PIN A3    IOSTANDARD LVCMOS33 } [get_ports { ck_a11 }]; #IO_L8N_T1_AD14N_35 Sch=ad_n[14]
+
+## ChipKit SPI
+#set_property -dict { PACKAGE_PIN G1    IOSTANDARD LVCMOS33 } [get_ports { ck_miso }]; #IO_L17N_T2_35 Sch=ck_miso
+#set_property -dict { PACKAGE_PIN H1    IOSTANDARD LVCMOS33 } [get_ports { ck_mosi }]; #IO_L17P_T2_35 Sch=ck_mosi
+#set_property -dict { PACKAGE_PIN F1    IOSTANDARD LVCMOS33 } [get_ports { ck_sck }]; #IO_L18P_T2_35 Sch=ck_sck
+#set_property -dict { PACKAGE_PIN C1    IOSTANDARD LVCMOS33 } [get_ports { ck_ss }]; #IO_L16N_T2_35 Sch=ck_ss
+
+## ChipKit I2C
+#set_property -dict { PACKAGE_PIN L18   IOSTANDARD LVCMOS33 } [get_ports { ck_scl }]; #IO_L4P_T0_D04_14 Sch=ck_scl
+#set_property -dict { PACKAGE_PIN M18   IOSTANDARD LVCMOS33 } [get_ports { ck_sda }]; #IO_L4N_T0_D05_14 Sch=ck_sda
+#set_property -dict { PACKAGE_PIN A14   IOSTANDARD LVCMOS33 } [get_ports { scl_pup }]; #IO_L9N_T1_DQS_AD3N_15 Sch=scl_pup
+#set_property -dict { PACKAGE_PIN A13   IOSTANDARD LVCMOS33 } [get_ports { sda_pup }]; #IO_L9P_T1_DQS_AD3P_15 Sch=sda_pup
+
+## Misc. ChipKit Ports
+#set_property -dict { PACKAGE_PIN M17   IOSTANDARD LVCMOS33 } [get_ports { ck_ioa }]; #IO_L10N_T1_D15_14 Sch=ck_ioa
+#set_property -dict { PACKAGE_PIN C2    IOSTANDARD LVCMOS33 } [get_ports { ck_rst }]; #IO_L16P_T2_35 Sch=ck_rst
+
+## SMSC Ethernet PHY
+#set_property -dict { PACKAGE_PIN D17   IOSTANDARD LVCMOS33 } [get_ports { eth_col }]; #IO_L16N_T2_A27_15 Sch=eth_col
+#set_property -dict { PACKAGE_PIN G14   IOSTANDARD LVCMOS33 } [get_ports { eth_crs }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=eth_crs
+set_property -dict { PACKAGE_PIN F16   IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L14N_T2_SRCC_15 Sch=eth_mdc
+set_property -dict { PACKAGE_PIN K13   IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L17P_T2_A26_15 Sch=eth_mdio
+set_property -dict { PACKAGE_PIN G18   IOSTANDARD LVCMOS33 } [get_ports { eth_phy_ref_clk }]; #IO_L22P_T3_A17_15 Sch=eth_ref_clk
+set_property -dict { PACKAGE_PIN C16   IOSTANDARD LVCMOS33 } [get_ports { eth_rst_n }]; #IO_L20P_T3_A20_15 Sch=eth_rstn
+set_property -dict { PACKAGE_PIN F15   IOSTANDARD LVCMOS33 } [get_ports { eth_rxck }]; #IO_L14P_T2_SRCC_15 Sch=eth_rx_clk
+set_property -dict { PACKAGE_PIN G16   IOSTANDARD LVCMOS33 } [get_ports { eth_rxctl }]; #IO_L13N_T2_MRCC_15 Sch=eth_rx_dv
+set_property -dict { PACKAGE_PIN D18   IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L21N_T3_DQS_A18_15 Sch=eth_rxd[0]
+set_property -dict { PACKAGE_PIN E17   IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L16P_T2_A28_15 Sch=eth_rxd[1]
+set_property -dict { PACKAGE_PIN E18   IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[2] }]; #IO_L21P_T3_DQS_15 Sch=eth_rxd[2]
+set_property -dict { PACKAGE_PIN G17   IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[3] }]; #IO_L18N_T2_A23_15 Sch=eth_rxd[3]
+#set_property -dict { PACKAGE_PIN C17   IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L20N_T3_A19_15 Sch=eth_rxerr
+set_property -dict { PACKAGE_PIN H16   IOSTANDARD LVCMOS33 } [get_ports { eth_txck }]; #IO_L13P_T2_MRCC_15 Sch=eth_tx_clk
+set_property -dict { PACKAGE_PIN H15   IOSTANDARD LVCMOS33 } [get_ports { eth_txctl }]; #IO_L19N_T3_A21_VREF_15 Sch=eth_tx_en
+set_property -dict { PACKAGE_PIN H14   IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L15P_T2_DQS_15 Sch=eth_txd[0]
+set_property -dict { PACKAGE_PIN J14   IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L19P_T3_A22_15 Sch=eth_txd[1]
+set_property -dict { PACKAGE_PIN J13   IOSTANDARD LVCMOS33 } [get_ports { eth_txd[2] }]; #IO_L17N_T2_A25_15 Sch=eth_txd[2]
+set_property -dict { PACKAGE_PIN H17   IOSTANDARD LVCMOS33 } [get_ports { eth_txd[3] }]; #IO_L18P_T2_A24_15 Sch=eth_txd[3]
+
+## Quad SPI Flash
+#set_property -dict { PACKAGE_PIN L13   IOSTANDARD LVCMOS33 } [get_ports { qspi_cs }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_cs
+#set_property -dict { PACKAGE_PIN K17   IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0]
+#set_property -dict { PACKAGE_PIN K18   IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1]
+#set_property -dict { PACKAGE_PIN L14   IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2]
+#set_property -dict { PACKAGE_PIN M14   IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3]
+
+## Power Measurements 
+#set_property -dict { PACKAGE_PIN B17   IOSTANDARD LVCMOS33     } [get_ports { vsnsvu_n }]; #IO_L7N_T1_AD2N_15 Sch=ad_n[2]
+#set_property -dict { PACKAGE_PIN B16   IOSTANDARD LVCMOS33     } [get_ports { vsnsvu_p }]; #IO_L7P_T1_AD2P_15 Sch=ad_p[2]
+#set_property -dict { PACKAGE_PIN B12   IOSTANDARD LVCMOS33     } [get_ports { vsns5v0_n }]; #IO_L3N_T0_DQS_AD1N_15 Sch=ad_n[1]
+#set_property -dict { PACKAGE_PIN C12   IOSTANDARD LVCMOS33     } [get_ports { vsns5v0_p }]; #IO_L3P_T0_DQS_AD1P_15 Sch=ad_p[1]
+#set_property -dict { PACKAGE_PIN F14   IOSTANDARD LVCMOS33     } [get_ports { isns5v0_n }]; #IO_L5N_T0_AD9N_15 Sch=ad_n[9]
+#set_property -dict { PACKAGE_PIN F13   IOSTANDARD LVCMOS33     } [get_ports { isns5v0_p }]; #IO_L5P_T0_AD9P_15 Sch=ad_p[9]
+#set_property -dict { PACKAGE_PIN A16   IOSTANDARD LVCMOS33     } [get_ports { isns0v95_n }]; #IO_L8N_T1_AD10N_15 Sch=ad_n[10]
+#set_property -dict { PACKAGE_PIN A15   IOSTANDARD LVCMOS33     } [get_ports { isns0v95_p }]; #IO_L8P_T1_AD10P_15 Sch=ad_p[10]
+
+# resetgen constraint
+set_multicycle_path -from [get_pins i_rstgen_dm/i_rstgen_bypass/synch_regs_q_reg[3]/C] 4
+set_multicycle_path -from [get_pins i_rstgen_dm/i_rstgen_bypass/synch_regs_q_reg[3]/C] 3  -hold
diff --git a/corev_apu/fpga/scripts/run.tcl b/corev_apu/fpga/scripts/run.tcl
index 9ba9d4e18780cbaa25c00cf01e58ecebbcf56b30..9da65d12dc101eac923ff28b5e9c8a838d3d9efd 100644
--- a/corev_apu/fpga/scripts/run.tcl
+++ b/corev_apu/fpga/scripts/run.tcl
@@ -24,6 +24,8 @@ if {$::env(BOARD) eq "genesys2"} {
       add_files -fileset constrs_1 -norecurse constraints/vc707.xdc
 } elseif {$::env(BOARD) eq "nexys_video"} {
       add_files -fileset constrs_1 -norecurse constraints/nexys_video.xdc
+} elseif {$::env(BOARD) eq "arty_a7_100"} {
+      add_files -fileset constrs_1 -norecurse constraints/arty_a7_100.xdc
 } else {
       exit 1
 }
@@ -69,6 +71,10 @@ if {$::env(BOARD) eq "genesys2"} {
       read_verilog -sv {src/nexys_video.svh ../../vendor/pulp-platform/common_cells/include/common_cells/registers.svh}
       set file "src/nexys_video.svh"
       set registers "../../vendor/pulp-platform/common_cells/include/common_cells/registers.svh"
+} elseif {$::env(BOARD) eq "arty_a7_100"} {
+      read_verilog -sv {src/arty_a7_100.svh ../../vendor/pulp-platform/common_cells/include/common_cells/registers.svh}
+      set file "src/arty_a7_100.svh"
+      set registers "../../vendor/pulp-platform/common_cells/include/common_cells/registers.svh"
 } else {
     exit 1
 }
diff --git a/corev_apu/fpga/scripts/write_cfgmem.tcl b/corev_apu/fpga/scripts/write_cfgmem.tcl
index 5138011f43ceeb75d2f0639b2a4b140615b9cba3..578a9066d4f5ff40964d36a17c7a458986f60bbd 100644
--- a/corev_apu/fpga/scripts/write_cfgmem.tcl
+++ b/corev_apu/fpga/scripts/write_cfgmem.tcl
@@ -34,6 +34,8 @@ if {$::env(BOARD) eq "genesys2"} {
     write_cfgmem -format mcs -interface SPIx4 -size 128  -loadbit "up 0x0 $bitfile" -file $mcsfile -force
 } elseif {$::env(BOARD) eq "nexys_video"} {
     write_cfgmem -format mcs -interface SPIx4 -size 256  -loadbit "up 0x0 $bitfile" -file $mcsfile -force
+} elseif {$::env(BOARD) eq "arty_a7_100"} {
+    write_cfgmem -format mcs -interface SPIx1 -size 128  -loadbit "up 0x0 $bitfile" -file $mcsfile -force
 } else {
       exit 1
 }
diff --git a/corev_apu/fpga/src/ariane_xilinx.sv b/corev_apu/fpga/src/ariane_xilinx.sv
index 20e77f77c2c336dbb14ff113997b791d1056124d..08e71cd1791262cb644a356f1b8f400b1e4c7194 100644
--- a/corev_apu/fpga/src/ariane_xilinx.sv
+++ b/corev_apu/fpga/src/ariane_xilinx.sv
@@ -170,18 +170,56 @@ module ariane_xilinx (
   input  logic [ 7:0]  sw          ,
   output logic         fan_pwm     ,
   input  logic         trst_n      ,
+`elsif ARTY_A7_100
+  input  logic         board_clk_i ,
+  input  logic         cpu_resetn  ,
+
+  inout  wire [15:0]   ddr3_dq     ,
+  inout  wire [ 1:0]   ddr3_dqs_n  ,
+  inout  wire [ 1:0]   ddr3_dqs_p  ,
+  output wire [13:0]   ddr3_addr   ,
+  output wire [ 2:0]   ddr3_ba     ,
+  output wire          ddr3_ras_n  ,
+  output wire          ddr3_cas_n  ,
+  output wire          ddr3_we_n   ,
+  output wire          ddr3_reset_n,
+  output wire [ 0:0]   ddr3_ck_p   ,
+  output wire [ 0:0]   ddr3_ck_n   ,
+  output wire [ 0:0]   ddr3_cke    ,
+  output wire [ 1:0]   ddr3_dm     ,
+  output wire [ 0:0]   ddr3_odt    ,
+  output wire          ddr3_cs_n   ,
+
+  output wire          eth_rst_n   ,
+  input  wire          eth_rxck    ,
+  input  wire          eth_rxctl   ,
+  input  wire [3:0]    eth_rxd     ,
+  output wire          eth_txck    ,
+  output wire          eth_txctl   ,
+  output wire [3:0]    eth_txd     ,
+  inout  wire          eth_mdio    ,
+  output logic         eth_mdc     ,
+  output logic [ 3:0]  led         ,
+  input  logic [ 3:0]  sw          ,
+
+  // 25 MHz reference clock for the PHY interface
+  output wire          eth_phy_ref_clk,
 `endif
   // SPI
   output logic        spi_mosi    ,
   input  logic        spi_miso    ,
   output logic        spi_ss      ,
   output logic        spi_clk_o   ,
-  // common part
+  // JTAG
+`ifndef ARTY_A7_100
+  // ARTY uses dmi_bscane
   // input logic      trst_n      ,
   input  logic        tck         ,
   input  logic        tms         ,
   input  logic        tdi         ,
   output wire         tdo         ,
+`endif
+  // USB UART
   input  logic        rx          ,
   output logic        tx
 );
@@ -281,6 +319,9 @@ assign trst_n = ~trst;
 `elsif NEXYS_VIDEO
 logic cpu_reset;
 assign cpu_reset  = ~cpu_resetn;
+`elsif ARTY_A7_100
+logic cpu_reset;
+assign cpu_reset  = ~cpu_resetn;
 `endif
 
 logic pll_locked;
@@ -306,6 +347,30 @@ assign test_en    = 1'b0;
 
 logic [NBSlave-1:0] pc_asserted;
 
+`ifdef ARTY_A7_100
+
+rstgen i_rstgen_main (
+    .clk_i        ( clk                              ),
+    .rst_ni       ( pll_locked & (~ndmreset) & rst_n ), // need to delay resetting the rest of the system until both DRAM and debug module ready
+    .test_mode_i  ( test_en                          ),
+    .rst_no       ( ndmreset_n                       ),
+    .init_no      (                                  ) // keep open
+);
+
+// DDR reset is not in phase, and might be too fast
+// so we synchronize the board-level reset in as well
+rstgen i_rstgen_dm (
+    .clk_i        ( clk                                         ),
+    .rst_ni       ( pll_locked & cpu_resetn & ~(ddr_sync_reset) ),
+    .test_mode_i  ( test_en                                     ),
+    .rst_no       ( rst_n                                       ),
+    .init_no      (                                             ) // keep open
+);
+
+assign rst = ~rst_n;
+
+`else
+
 rstgen i_rstgen_main (
     .clk_i        ( clk                      ),
     .rst_ni       ( pll_locked & (~ndmreset) ),
@@ -317,6 +382,7 @@ rstgen i_rstgen_main (
 assign rst_n = ~ddr_sync_reset;
 assign rst = ddr_sync_reset;
 
+`endif
 // ---------------
 // AXI Xbar
 // ---------------
@@ -366,6 +432,25 @@ axi_xbar_intf #(
   .default_mst_port_i    ( '0         )
 );
 
+`ifdef ARTY_A7_100
+// when selecting the input files, we use "dmi_bscane_tap" instead of "dmi_jtag_tag".
+// dmi_bscane_tap uses Xilinx' BSCANE primitive to access the USB JTAG chain
+// hence, no JTAG signals needed
+logic tck;
+logic tms;
+logic trst_n;
+logic tdi;
+logic tdo;
+
+assign tck = 1'b0;
+assign tms = 1'b0;
+assign tdi = 1'b0;
+
+// reset of the JTAG tap
+// tied to external reset; should not be the same as CPU to avoid loop
+assign trst_n = cpu_resetn;
+
+`endif
 // ---------------
 // Debug Module
 // ---------------
@@ -853,6 +938,14 @@ end
 // Peripherals
 // ---------------
 `ifdef KC705
+`define ONLY_FOUR_LEDS_SWITCHES
+`endif
+
+`ifdef ARTY_A7_100
+`define ONLY_FOUR_LEDS_SWITCHES
+`endif
+
+`ifdef ONLY_FOUR_LEDS_SWITCHES
   logic [7:0] unused_led;
   logic [3:0] unused_switches = 4'b0000;
 `endif
@@ -881,6 +974,9 @@ ariane_peripherals #(
     `elsif NEXYS_VIDEO
     .InclSPI      ( 1'b1         ),
     .InclEthernet ( 1'b0         )
+    `elsif ARTY_A7_100
+    .InclSPI      ( 1'b1         ),
+    .InclEthernet ( 1'b0         ) // Ethernet does not meet timing
     `endif
 ) i_ariane_peripherals (
     .clk_i        ( clk                          ),
@@ -911,7 +1007,7 @@ ariane_peripherals #(
     .spi_mosi       ( spi_mosi                    ),
     .spi_miso       ( spi_miso                    ),
     .spi_ss         ( spi_ss                      ),
-    `ifdef KC705
+    `ifdef ONLY_FOUR_LEDS_SWITCHES
       .leds_o         ( {led[3:0], unused_led[7:4]}),
       .dip_switches_i ( {sw, unused_switches}     )
     `else
@@ -1144,6 +1240,28 @@ xlnx_clk_gen i_xlnx_clk_gen (
   .clk_in1  ( ddr_clock_out   )  // 100MHz input clock
 );
 
+`elsif ARTY_A7_100
+logic sys_clk_i;
+
+// clock input buffer
+// allows us to share the clock between MIG and clkgen
+// MIG output clock is not 100 MHz on Arty
+BUFG(
+  .I(board_clk_i),
+  .O(sys_clk_i)
+);
+
+xlnx_clk_gen i_xlnx_clk_gen (
+  .clk_out1 ( clk             ), // 25 MHz
+  .clk_out2 ( phy_tx_clk      ), // 125 MHz (for RGMII PHY)
+  .clk_out3 ( eth_clk         ), // 125 MHz quadrature (90 deg phase shift)
+  .clk_out4 ( sd_clk_sys      ), // 50 MHz clock
+  .clk_out5 ( clk_200MHz_ref  ), // 200 MHz clock
+  .clk_out6 ( eth_phy_ref_clk ), // 25 MHz reference for PHY
+  .reset    ( cpu_reset       ),
+  .locked   ( pll_locked      ),
+  .clk_in1  ( sys_clk_i       )  // 100MHz input clock
+);
 `else
 
 xlnx_clk_gen i_xlnx_clk_gen (
@@ -1904,6 +2022,77 @@ axi_clock_converter_0 pcie_axi_clock_converter (
   .s_axi_rvalid   ( pcie_dwidth_axi_rvalid   ),
   .s_axi_rready   ( pcie_dwidth_axi_rready   )
 );
+`elsif ARTY_A7_100
+
+
+xlnx_mig_7_ddr3 i_ddr (
+    .sys_clk_i       ( sys_clk_i        ),
+    .clk_ref_i       ( clk_200MHz_ref   ),
+    .ddr3_dq,
+    .ddr3_dqs_n,
+    .ddr3_dqs_p,
+    .ddr3_addr,
+    .ddr3_ba,
+    .ddr3_ras_n,
+    .ddr3_cas_n,
+    .ddr3_we_n,
+    .ddr3_reset_n,
+    .ddr3_ck_p,
+    .ddr3_ck_n,
+    .ddr3_cke,
+    .ddr3_cs_n,
+    .ddr3_dm,
+    .ddr3_odt,
+    .mmcm_locked     (                    ), // keep open
+    .app_sr_req      ( '0                 ),
+    .app_ref_req     ( '0                 ),
+    .app_zq_req      ( '0                 ),
+    .app_sr_active   (                    ), // keep open
+    .app_ref_ack     (                    ), // keep open
+    .app_zq_ack      (                    ), // keep open
+    .ui_clk          ( ddr_clock_out      ),
+    .ui_clk_sync_rst ( ddr_sync_reset     ),
+    .aresetn         ( ndmreset_n         ),
+    .s_axi_awid,
+    .s_axi_awaddr    ( s_axi_awaddr[28:0] ),
+    .s_axi_awlen,
+    .s_axi_awsize,
+    .s_axi_awburst,
+    .s_axi_awlock,
+    .s_axi_awcache,
+    .s_axi_awprot,
+    .s_axi_awqos,
+    .s_axi_awvalid,
+    .s_axi_awready,
+    .s_axi_wdata,
+    .s_axi_wstrb,
+    .s_axi_wlast,
+    .s_axi_wvalid,
+    .s_axi_wready,
+    .s_axi_bready,
+    .s_axi_bid,
+    .s_axi_bresp,
+    .s_axi_bvalid,
+    .s_axi_arid,
+    .s_axi_araddr     ( s_axi_araddr[28:0] ),
+    .s_axi_arlen,
+    .s_axi_arsize,
+    .s_axi_arburst,
+    .s_axi_arlock,
+    .s_axi_arcache,
+    .s_axi_arprot,
+    .s_axi_arqos,
+    .s_axi_arvalid,
+    .s_axi_arready,
+    .s_axi_rready,
+    .s_axi_rid,
+    .s_axi_rdata,
+    .s_axi_rresp,
+    .s_axi_rlast,
+    .s_axi_rvalid,
+    .init_calib_complete (            ), // keep open
+    .sys_rst             ( cpu_resetn )
+);
 `endif
 
 endmodule
diff --git a/corev_apu/fpga/src/arty_a7_100.svh b/corev_apu/fpga/src/arty_a7_100.svh
new file mode 100644
index 0000000000000000000000000000000000000000..77655506b13d9928149635274622ed60c8a8ff9a
--- /dev/null
+++ b/corev_apu/fpga/src/arty_a7_100.svh
@@ -0,0 +1,17 @@
+`define ARTY_A7_100
+
+`define ARIANE_DATA_WIDTH 64
+
+// Instantiate protocl checker
+// `define PROTOCOL_CHECKER
+
+// write-back cache
+// `define WB_DCACHE
+
+// write-through cache
+`define WT_DCACHE
+
+// causes build error in cdc_2phase_clearable.sv
+`define COMMON_CELLS_ASSERTS_OFF
+
+`define RAMB16
diff --git a/corev_apu/fpga/src/bootrom/Makefile b/corev_apu/fpga/src/bootrom/Makefile
index 35c2b872ea76dc0342105721e93768277853b6f0..a9f637207a108bfb844d26330956b770ea3bafa8 100644
--- a/corev_apu/fpga/src/bootrom/Makefile
+++ b/corev_apu/fpga/src/bootrom/Makefile
@@ -9,6 +9,14 @@ HALF_CLOCK_FREQUENCY ?= 12500000 #12.5MHz
 UART_BITRATE ?= 57600
 HAS_ETHERNET ?= 0
 else
+ifeq ($(BOARD), arty_a7_100)
+DRAM_SIZE_64 ?= 0x10000000 #256MB
+DRAM_SIZE_32 ?= 0x08000000 #128MB
+CLOCK_FREQUENCY ?= 25000000 #25MHz
+HALF_CLOCK_FREQUENCY ?= 12500000 #12.5MHz
+UART_BITRATE ?= 57600
+HAS_ETHERNET ?= 0
+else
 DRAM_SIZE_64 ?= 0x40000000 #1GB
 DRAM_SIZE_32 ?= 0x08000000 #128MB
 CLOCK_FREQUENCY ?= 50000000 #50MHz
@@ -16,6 +24,7 @@ HALF_CLOCK_FREQUENCY ?= 25000000 #25MHz
 UART_BITRATE ?= 115200
 HAS_ETHERNET ?= 1
 endif
+endif
 
 CC = $(RISCV)/bin/${CROSSCOMPILE}gcc
 OBJCOPY = $(RISCV)/bin/$(CROSSCOMPILE)objcopy
diff --git a/corev_apu/fpga/src/bootrom/src/main.c b/corev_apu/fpga/src/bootrom/src/main.c
index f62485ba246d25c46f71bb7aea9010367dc170b1..65dd2109f7091b01c252ee8d2013f938e1ccaecf 100644
--- a/corev_apu/fpga/src/bootrom/src/main.c
+++ b/corev_apu/fpga/src/bootrom/src/main.c
@@ -81,6 +81,9 @@ int main()
             "la a1, _dtb;"
             "jr s0");
     }
+    else{
+        print_uart("\r\nFailed to boot! Halting...\r\n");
+    }
 
     while (1)
     {
diff --git a/corev_apu/fpga/src/riscv_dbg_bscane_backport/dmi_bscane_tap.sv b/corev_apu/fpga/src/riscv_dbg_bscane_backport/dmi_bscane_tap.sv
new file mode 100644
index 0000000000000000000000000000000000000000..5fe5d86e519773172160abc2e9d10e25eb275fa9
--- /dev/null
+++ b/corev_apu/fpga/src/riscv_dbg_bscane_backport/dmi_bscane_tap.sv
@@ -0,0 +1,80 @@
+// Copyright 2020 ETH Zurich and University of Bologna.
+// Solderpad Hardware License, Version 0.51, see LICENSE for details.
+// SPDX-License-Identifier: SHL-0.51
+
+// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
+
+/// Replacement for the full JTAG tap with `BSCANE2` Xilinx elements which hook
+/// into the FPGA native scan chain. Meant for FPGA boards which do not expose a
+/// usable pin-header or a separate, programmable FTDI chip.
+
+/// They replace the functionality of `dmi_jtag_tap.sv`. The file is
+/// pin-compatible so that by selecting the appropriate file for the target it
+/// can be transparently managed without relying on tick defines.
+module dmi_jtag_tap #(
+  // Ignored, defined by the FPGA model.
+  parameter int unsigned IrLength = 5,
+  // JTAG IDCODE Value
+  parameter logic [31:0] IdcodeValue = 32'h00000001
+  // xxxx             version
+  // xxxxxxxxxxxxxxxx part number
+  // xxxxxxxxxxx      manufacturer id
+  // 1                required by standard
+) (
+  /// Unused. Here to maintain pin compatibility with `dmi_jtag_tap` so that it
+  /// can be used as a drop-in replacement.
+  input  logic        tck_i,
+  input  logic        tms_i,
+  input  logic        trst_ni,
+  input  logic        td_i,
+  output logic        td_o,
+  output logic        tdo_oe_o,
+  input  logic        testmode_i,
+
+  output logic        tck_o,
+  output logic        dmi_clear_o,
+  output logic        update_o,
+  output logic        capture_o,
+  output logic        shift_o,
+  output logic        tdi_o,
+  output logic        dtmcs_select_o,
+  input  logic        dtmcs_tdo_i,
+  // we want to access DMI register
+  output logic        dmi_select_o,
+  input  logic        dmi_tdo_i
+);
+
+  BSCANE2 #(
+    .JTAG_CHAIN (3)
+  ) i_tap_dtmcs (
+    .CAPTURE (capture_o),
+    .DRCK (),
+    .RESET (dmi_clear_o),
+    .RUNTEST (),
+    .SEL (dtmcs_select_o),
+    .SHIFT (shift_o),
+    .TCK (tck_o),
+    .TDI (tdi_o),
+    .TMS (),
+    .TDO (dtmcs_tdo_i),
+    .UPDATE (update_o)
+  );
+
+  /// DMI Register
+  BSCANE2 #(
+    .JTAG_CHAIN (4)
+  ) i_tap_dmi (
+    .CAPTURE (),
+    .DRCK (),
+    .RESET (),
+    .RUNTEST (),
+    .SEL (dmi_select_o),
+    .SHIFT (),
+    .TCK (),
+    .TDI (),
+    .TMS (),
+    .TDO (dmi_tdo_i),
+    .UPDATE ()
+  );
+
+endmodule
diff --git a/corev_apu/fpga/src/riscv_dbg_bscane_backport/dmi_cdc.sv b/corev_apu/fpga/src/riscv_dbg_bscane_backport/dmi_cdc.sv
new file mode 100644
index 0000000000000000000000000000000000000000..f9d66fdd41baf9dcc69e039214355ab6abbe84e5
--- /dev/null
+++ b/corev_apu/fpga/src/riscv_dbg_bscane_backport/dmi_cdc.sv
@@ -0,0 +1,114 @@
+/* Copyright 2018 ETH Zurich and University of Bologna.
+* Copyright and related rights are licensed under the Solderpad Hardware
+* License, Version 0.51 (the “License”); you may not use this file except in
+* compliance with the License.  You may obtain a copy of the License at
+* http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+* or agreed to in writing, software, hardware and materials distributed under
+* this 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.
+*
+* File:   axi_riscv_debug_module.sv
+* Author: Andreas Traber <atraber@iis.ee.ethz.ch>
+* Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
+*
+* Description: Clock domain crossings for JTAG to DMI very heavily based
+*              on previous work by Andreas Traber for the PULP project.
+*              This is mainly a wrapper around the existing CDCs.
+*/
+module dmi_cdc (
+  // JTAG side (master side)
+  input  logic             tck_i,
+  input  logic             trst_ni,
+  input  dm::dmi_req_t     jtag_dmi_req_i,
+  output logic             jtag_dmi_ready_o,
+  input  logic             jtag_dmi_valid_i,
+  input  logic             jtag_dmi_cdc_clear_i, // Synchronous clear signal.
+                                                 // Triggers reset sequencing
+                                                 // accross CDC
+
+  output dm::dmi_resp_t    jtag_dmi_resp_o,
+  output logic             jtag_dmi_valid_o,
+  input  logic             jtag_dmi_ready_i,
+
+  // core side (slave side)
+  input  logic             clk_i,
+  input  logic             rst_ni,
+
+  output logic             core_dmi_rst_no,
+  output dm::dmi_req_t     core_dmi_req_o,
+  output logic             core_dmi_valid_o,
+  input  logic             core_dmi_ready_i,
+
+  input dm::dmi_resp_t     core_dmi_resp_i,
+  output logic             core_dmi_ready_o,
+  input  logic             core_dmi_valid_i
+);
+
+  logic                    core_clear_pending;
+
+  cdc_2phase_clearable #(.T(dm::dmi_req_t)) i_cdc_req (
+    .src_rst_ni  ( trst_ni              ),
+    .src_clear_i ( jtag_dmi_cdc_clear_i ),
+    .src_clk_i   ( tck_i                ),
+    .src_clear_pending_o(), // Not used
+    .src_data_i  ( jtag_dmi_req_i       ),
+    .src_valid_i ( jtag_dmi_valid_i     ),
+    .src_ready_o ( jtag_dmi_ready_o     ),
+
+    .dst_rst_ni  ( rst_ni               ),
+    .dst_clear_i ( 1'b0                 ), // No functional reset from core side
+                                           // used (only async).
+    .dst_clear_pending_o( core_clear_pending ), // use the clear pending signal
+                                                // to synchronously clear the
+                                                // response FIFO in the dm_top
+                                                // csrs
+    .dst_clk_i   ( clk_i                ),
+    .dst_data_o  ( core_dmi_req_o       ),
+    .dst_valid_o ( core_dmi_valid_o     ),
+    .dst_ready_i ( core_dmi_ready_i     )
+  );
+
+  cdc_2phase_clearable #(.T(dm::dmi_resp_t)) i_cdc_resp (
+    .src_rst_ni  ( rst_ni               ),
+    .src_clear_i ( 1'b0                 ), // No functional reset from core side
+                                           // used (only async ).
+    .src_clear_pending_o(), // Not used
+    .src_clk_i   ( clk_i                ),
+    .src_data_i  ( core_dmi_resp_i      ),
+    .src_valid_i ( core_dmi_valid_i     ),
+    .src_ready_o ( core_dmi_ready_o     ),
+
+    .dst_rst_ni  ( trst_ni              ),
+    .dst_clear_i ( jtag_dmi_cdc_clear_i ),
+    .dst_clear_pending_o(), //Not used
+    .dst_clk_i   ( tck_i                ),
+    .dst_data_o  ( jtag_dmi_resp_o      ),
+    .dst_valid_o ( jtag_dmi_valid_o     ),
+    .dst_ready_i ( jtag_dmi_ready_i     )
+  );
+
+  // We need to flush the DMI response FIFO in DM top using the core clock
+  // synchronous clear signal core_dmi_rst_no. We repurpose the clear
+  // pending signal in the core clock domain by generating a 1 cycle pulse from
+  // it.
+
+  logic                    core_clear_pending_q;
+  logic                    core_dmi_rst_nq;
+  logic                    clear_pending_rise_edge_detect;
+
+  assign clear_pending_rise_edge_detect = !core_clear_pending_q && core_clear_pending;
+
+  always_ff @(posedge clk_i, negedge rst_ni) begin
+    if (!rst_ni) begin
+      core_dmi_rst_nq       <= 1'b1;
+      core_clear_pending_q <= 1'b0;
+    end else begin
+      core_dmi_rst_nq       <= ~clear_pending_rise_edge_detect; // active-low!
+      core_clear_pending_q <= core_clear_pending;
+    end
+  end
+
+  assign core_dmi_rst_no = core_dmi_rst_nq;
+
+endmodule : dmi_cdc
diff --git a/corev_apu/fpga/src/riscv_dbg_bscane_backport/dmi_jtag.sv b/corev_apu/fpga/src/riscv_dbg_bscane_backport/dmi_jtag.sv
new file mode 100644
index 0000000000000000000000000000000000000000..9c5b5b552b36969d5c774a3c472211f91b55225b
--- /dev/null
+++ b/corev_apu/fpga/src/riscv_dbg_bscane_backport/dmi_jtag.sv
@@ -0,0 +1,373 @@
+/* Copyright 2018 ETH Zurich and University of Bologna.
+* Copyright and related rights are licensed under the Solderpad Hardware
+* License, Version 0.51 (the “License”); you may not use this file except in
+* compliance with the License.  You may obtain a copy of the License at
+* http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+* or agreed to in writing, software, hardware and materials distributed under
+* this 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.
+*
+* File:   axi_riscv_debug_module.sv
+* Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
+* Date:   19.7.2018
+*
+* Description: JTAG DMI (debug module interface)
+*
+*/
+
+module dmi_jtag #(
+  parameter logic [31:0] IdcodeValue = 32'h00000DB3
+) (
+  input  logic         clk_i,      // DMI Clock
+  input  logic         rst_ni,     // Asynchronous reset active low
+  input  logic         testmode_i,
+
+  // active-low glitch free reset signal. Is asserted for one dmi clock cycle
+  // (clk_i) whenever the dmi_jtag is reset (POR or functional reset).
+  output logic         dmi_rst_no,
+  output dm::dmi_req_t dmi_req_o,
+  output logic         dmi_req_valid_o,
+  input  logic         dmi_req_ready_i,
+
+  input dm::dmi_resp_t dmi_resp_i,
+  output logic         dmi_resp_ready_o,
+  input  logic         dmi_resp_valid_i,
+
+  input  logic         tck_i,    // JTAG test clock pad
+  input  logic         tms_i,    // JTAG test mode select pad
+  input  logic         trst_ni,  // JTAG test reset pad
+  input  logic         td_i,     // JTAG test data input pad
+  output logic         td_o,     // JTAG test data output pad
+  output logic         tdo_oe_o  // Data out output enable
+);
+
+  typedef enum logic [1:0] {
+    DMINoError = 2'h0, DMIReservedError = 2'h1,
+    DMIOPFailed = 2'h2, DMIBusy = 2'h3
+  } dmi_error_e;
+  dmi_error_e error_d, error_q;
+
+  logic tck;
+  logic jtag_dmi_clear; // Synchronous reset of DMI triggered by TestLogicReset in
+                        // jtag TAP
+  logic dmi_clear; // Functional (warm) reset of the entire DMI
+  logic update;
+  logic capture;
+  logic shift;
+  logic tdi;
+
+  logic dtmcs_select;
+
+  assign dmi_clear = jtag_dmi_clear || (dtmcs_select && update && dtmcs_q.dmihardreset);
+
+  //--------------------------------
+  // Backported types from dm_pkg.sv
+  //--------------------------------
+  typedef struct packed {
+    logic [31:18] zero1;
+    logic         dmihardreset;
+    logic         dmireset;
+    logic         zero0;
+    logic [14:12] idle;
+    logic [11:10] dmistat;
+    logic [9:4]   abits;
+    logic [3:0]   version;
+  } dtmcs_t;
+
+  typedef enum logic [1:0] {
+    DTM_SUCCESS = 2'h0,
+    DTM_ERR     = 2'h2,
+    DTM_BUSY    = 2'h3
+  } dtm_op_status_e;
+
+  // -------------------------------
+  // Debug Module Control and Status
+  // -------------------------------
+
+  dtmcs_t dtmcs_d, dtmcs_q;
+
+  always_comb begin
+    dtmcs_d = dtmcs_q;
+    if (capture) begin
+      if (dtmcs_select) begin
+        dtmcs_d  = '{
+                      zero1        : '0,
+                      dmihardreset : 1'b0,
+                      dmireset     : 1'b0,
+                      zero0        : '0,
+                      idle         : 3'd1, // 1: Enter Run-Test/Idle and leave it immediately
+                      dmistat      : error_q, // 0: No error, 2: Op failed, 3: too fast
+                      abits        : 6'd7, // The size of address in dmi
+                      version      : 4'd1  // Version described in spec version 0.13 (and later?)
+                    };
+      end
+    end
+
+    if (shift) begin
+      if (dtmcs_select) dtmcs_d  = {tdi, 31'(dtmcs_q >> 1)};
+    end
+  end
+
+  always_ff @(posedge tck or negedge trst_ni) begin
+    if (!trst_ni) begin
+      dtmcs_q <= '0;
+    end else begin
+      dtmcs_q <= dtmcs_d;
+    end
+  end
+
+  // ----------------------------
+  // DMI (Debug Module Interface)
+  // ----------------------------
+
+  logic        dmi_select;
+  logic        dmi_tdo;
+
+  dm::dmi_req_t  dmi_req;
+  logic          dmi_req_ready;
+  logic          dmi_req_valid;
+
+  dm::dmi_resp_t dmi_resp;
+  logic          dmi_resp_valid;
+  logic          dmi_resp_ready;
+
+  typedef struct packed {
+    logic [6:0]  address;
+    logic [31:0] data;
+    logic [1:0]  op;
+  } dmi_t;
+
+  typedef enum logic [2:0] { Idle, Read, WaitReadValid, Write, WaitWriteValid } state_e;
+  state_e state_d, state_q;
+
+  logic [$bits(dmi_t)-1:0] dr_d, dr_q;
+  logic [6:0] address_d, address_q;
+  logic [31:0] data_d, data_q;
+
+  dmi_t  dmi;
+  assign dmi          = dmi_t'(dr_q);
+  assign dmi_req.addr = address_q;
+  assign dmi_req.data = data_q;
+  assign dmi_req.op   = (state_q == Write) ? dm::DTM_WRITE : dm::DTM_READ;
+  // We will always be ready to accept the data we requested.
+  assign dmi_resp_ready = 1'b1;
+
+  logic error_dmi_busy;
+  logic error_dmi_op_failed;
+
+  always_comb begin : p_fsm
+    error_dmi_busy = 1'b0;
+    error_dmi_op_failed = 1'b0;
+    // default assignments
+    state_d   = state_q;
+    address_d = address_q;
+    data_d    = data_q;
+    error_d   = error_q;
+
+    dmi_req_valid = 1'b0;
+
+    if (dmi_clear) begin
+      state_d   = Idle;
+      data_d    = '0;
+      error_d   = DMINoError;
+      address_d = '0;
+    end else begin
+      unique case (state_q)
+        Idle: begin
+          // make sure that no error is sticky
+          if (dmi_select && update && (error_q == DMINoError)) begin
+            // save address and value
+            address_d = dmi.address;
+            data_d = dmi.data;
+            if (dm::dtm_op_e'(dmi.op) == dm::DTM_READ) begin
+              state_d = Read;
+            end else if (dm::dtm_op_e'(dmi.op) == dm::DTM_WRITE) begin
+              state_d = Write;
+            end
+            // else this is a nop and we can stay here
+          end
+        end
+
+        Read: begin
+          dmi_req_valid = 1'b1;
+          if (dmi_req_ready) begin
+            state_d = WaitReadValid;
+          end
+        end
+
+        WaitReadValid: begin
+          // load data into register and shift out
+          if (dmi_resp_valid) begin
+            unique case (dmi_resp.resp)
+              DTM_SUCCESS: begin
+                data_d = dmi_resp.data;
+              end
+              DTM_ERR: begin
+                data_d = 32'hDEAD_BEEF;
+                error_dmi_op_failed = 1'b1;
+              end
+              DTM_BUSY: begin
+                data_d = 32'hB051_B051;
+                error_dmi_busy = 1'b1;
+              end
+              default: begin
+                data_d = 32'hBAAD_C0DE;
+              end
+            endcase
+            state_d = Idle;
+          end
+        end
+
+        Write: begin
+          dmi_req_valid = 1'b1;
+          // request sent, wait for response before going back to idle
+          if (dmi_req_ready) begin
+            state_d = WaitWriteValid;
+          end
+        end
+
+        WaitWriteValid: begin
+          // got a valid answer go back to idle
+          if (dmi_resp_valid) begin
+            unique case (dmi_resp.resp)
+              DTM_ERR: error_dmi_op_failed = 1'b1;
+              DTM_BUSY: error_dmi_busy = 1'b1;
+              default: ;
+            endcase
+            state_d = Idle;
+          end
+        end
+
+        default: begin
+          // just wait for idle here
+          if (dmi_resp_valid) begin
+            state_d = Idle;
+          end
+        end
+      endcase
+
+      // update means we got another request but we didn't finish
+      // the one in progress, this state is sticky
+      if (update && state_q != Idle) begin
+        error_dmi_busy = 1'b1;
+      end
+
+      // if capture goes high while we are in the read state
+      // or in the corresponding wait state we are not giving back a valid word
+      // -> throw an error
+      if (capture && state_q inside {Read, WaitReadValid}) begin
+        error_dmi_busy = 1'b1;
+      end
+
+      if (error_dmi_busy && error_q == DMINoError) begin
+        error_d = DMIBusy;
+      end
+
+      if (error_dmi_op_failed && error_q == DMINoError) begin
+        error_d = DMIOPFailed;
+      end
+
+      // clear sticky error flag
+      if (update && dtmcs_q.dmireset && dtmcs_select) begin
+        error_d = DMINoError;
+      end
+    end
+  end
+
+  // shift register
+  assign dmi_tdo = dr_q[0];
+
+  always_comb begin : p_shift
+    dr_d    = dr_q;
+    if (dmi_clear) begin
+      dr_d = '0;
+    end else begin
+      if (capture) begin
+        if (dmi_select) begin
+          if (error_q == DMINoError && !error_dmi_busy) begin
+            dr_d = {address_q, data_q, DMINoError};
+            // DMI was busy, report an error
+          end else if (error_q == DMIBusy || error_dmi_busy) begin
+            dr_d = {address_q, data_q, DMIBusy};
+          end
+        end
+      end
+
+      if (shift) begin
+        if (dmi_select) begin
+          dr_d = {tdi, dr_q[$bits(dr_q)-1:1]};
+        end
+      end
+    end
+  end
+
+  always_ff @(posedge tck or negedge trst_ni) begin
+    if (!trst_ni) begin
+      dr_q      <= '0;
+      state_q   <= Idle;
+      address_q <= '0;
+      data_q    <= '0;
+      error_q   <= DMINoError;
+    end else begin
+      dr_q      <= dr_d;
+      state_q   <= state_d;
+      address_q <= address_d;
+      data_q    <= data_d;
+      error_q   <= error_d;
+    end
+  end
+
+  // ---------
+  // TAP
+  // ---------
+  dmi_jtag_tap #(
+    .IrLength (5),
+    .IdcodeValue(IdcodeValue)
+  ) i_dmi_jtag_tap (
+    .tck_i,
+    .tms_i,
+    .trst_ni,
+    .td_i,
+    .td_o,
+    .tdo_oe_o,
+    .testmode_i,
+    .tck_o          ( tck              ),
+    .dmi_clear_o    ( jtag_dmi_clear   ),
+    .update_o       ( update           ),
+    .capture_o      ( capture          ),
+    .shift_o        ( shift            ),
+    .tdi_o          ( tdi              ),
+    .dtmcs_select_o ( dtmcs_select     ),
+    .dtmcs_tdo_i    ( dtmcs_q[0]       ),
+    .dmi_select_o   ( dmi_select       ),
+    .dmi_tdo_i      ( dmi_tdo          )
+  );
+
+  // ---------
+  // CDC
+  // ---------
+  dmi_cdc i_dmi_cdc (
+    // JTAG side (master side)
+    .tck_i                ( tck              ),
+    .trst_ni              ( trst_ni          ),
+    .jtag_dmi_cdc_clear_i ( dmi_clear        ),
+    .jtag_dmi_req_i       ( dmi_req          ),
+    .jtag_dmi_ready_o     ( dmi_req_ready    ),
+    .jtag_dmi_valid_i     ( dmi_req_valid    ),
+    .jtag_dmi_resp_o      ( dmi_resp         ),
+    .jtag_dmi_valid_o     ( dmi_resp_valid   ),
+    .jtag_dmi_ready_i     ( dmi_resp_ready   ),
+    // core side
+    .clk_i,
+    .rst_ni,
+    .core_dmi_rst_no      ( dmi_rst_no       ),
+    .core_dmi_req_o       ( dmi_req_o        ),
+    .core_dmi_valid_o     ( dmi_req_valid_o  ),
+    .core_dmi_ready_i     ( dmi_req_ready_i  ),
+    .core_dmi_resp_i      ( dmi_resp_i       ),
+    .core_dmi_ready_o     ( dmi_resp_ready_o ),
+    .core_dmi_valid_i     ( dmi_resp_valid_i )
+  );
+
+endmodule : dmi_jtag
diff --git a/corev_apu/fpga/xilinx/xlnx_clk_gen/tcl/run.tcl b/corev_apu/fpga/xilinx/xlnx_clk_gen/tcl/run.tcl
index 2754a49ffe82aff23514bc8a26e12dcbef32b0e8..5955de1459ac1d1e70042509adae977329c24f9b 100644
--- a/corev_apu/fpga/xilinx/xlnx_clk_gen/tcl/run.tcl
+++ b/corev_apu/fpga/xilinx/xlnx_clk_gen/tcl/run.tcl
@@ -23,6 +23,24 @@ if {$::env(BOARD) eq "nexys_video"} {
                         CONFIG.CLKOUT5_REQUESTED_OUT_FREQ {200} \
                         CONFIG.CLKIN1_JITTER_PS {50.0} \
                        ] [get_ips $ipName]
+} elseif {$::env(BOARD) eq "arty_a7_100"} {
+    set_property -dict [list CONFIG.PRIM_IN_FREQ {100.000} \
+                        CONFIG.NUM_OUT_CLKS {6} \
+                        CONFIG.CLKOUT2_USED {true} \
+                        CONFIG.CLKOUT3_USED {true} \
+                        CONFIG.CLKOUT4_USED {true} \
+                        CONFIG.CLKOUT5_USED {true} \
+                        CONFIG.CLKOUT6_USED {true} \
+                        CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {25} \
+                        CONFIG.CLKOUT2_REQUESTED_OUT_FREQ {125} \
+                        CONFIG.CLKOUT3_REQUESTED_OUT_FREQ {125} \
+                        CONFIG.CLKOUT3_REQUESTED_PHASE {90.000} \
+                        CONFIG.CLKOUT4_REQUESTED_OUT_FREQ {50} \
+                        CONFIG.CLKOUT5_REQUESTED_OUT_FREQ {200} \
+                        CONFIG.CLKOUT6_REQUESTED_OUT_FREQ {25} \
+                        CONFIG.CLKIN1_JITTER_PS {100.0} \
+                        CONFIG.PRIM_SOURCE {No_buffer} \
+                       ] [get_ips $ipName]
 } else {
 set_property -dict [list CONFIG.PRIM_IN_FREQ {200.000} \
                         CONFIG.NUM_OUT_CLKS {4} \
diff --git a/corev_apu/fpga/xilinx/xlnx_mig_7_ddr3/mig_arty_a7_100.prj b/corev_apu/fpga/xilinx/xlnx_mig_7_ddr3/mig_arty_a7_100.prj
new file mode 100644
index 0000000000000000000000000000000000000000..a122e60bb34f69f3dfb332f649034348c2f3582e
--- /dev/null
+++ b/corev_apu/fpga/xilinx/xlnx_mig_7_ddr3/mig_arty_a7_100.prj
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<Project NoOfControllers="1">
+
+  
+
+<!-- IMPORTANT: This is an internal file that has been generated by the MIG software. Any direct editing or changes made to this file may result in unpredictable behavior or data corruption. It is strongly advised that users do not edit the contents of this file. Re-run the MIG GUI with the required settings if any of the options provided below need to be altered. -->
+
+  <ModuleName>design_1_mig_7series_0_0</ModuleName>
+
+  <dci_inouts_inputs>1</dci_inouts_inputs>
+
+  <dci_inputs>1</dci_inputs>
+
+  <Debug_En>OFF</Debug_En>
+
+  <DataDepth_En>1024</DataDepth_En>
+
+  <LowPower_En>ON</LowPower_En>
+
+  <XADC_En>Enabled</XADC_En>
+
+  <TargetFPGA>xc7a100t-csg324/-1</TargetFPGA>
+
+  <Version>4.2</Version>
+
+  <SystemClock>Single-Ended</SystemClock>
+
+  <ReferenceClock>No Buffer</ReferenceClock>
+
+  <SysResetPolarity>ACTIVE LOW</SysResetPolarity>
+
+  <BankSelectionFlag>FALSE</BankSelectionFlag>
+
+  <InternalVref>1</InternalVref>
+
+  <dci_hr_inouts_inputs>50 Ohms</dci_hr_inouts_inputs>
+
+  <dci_cascade>0</dci_cascade>
+
+  <Controller number="0">
+    <MemoryDevice>DDR3_SDRAM/Components/MT41K128M16XX-15E</MemoryDevice>
+    <TimePeriod>3077</TimePeriod>
+    <VccAuxIO>1.8V</VccAuxIO>
+    <PHYRatio>4:1</PHYRatio>
+    <InputClkFreq>99.997</InputClkFreq>
+    <UIExtraClocks>1</UIExtraClocks>
+    <MMCM_VCO>649</MMCM_VCO>
+    <MMCMClkOut0> 3.250</MMCMClkOut0>
+    <MMCMClkOut1>1</MMCMClkOut1>
+    <MMCMClkOut2>1</MMCMClkOut2>
+    <MMCMClkOut3>1</MMCMClkOut3>
+    <MMCMClkOut4>1</MMCMClkOut4>
+    <DataWidth>16</DataWidth>
+    <DeepMemory>1</DeepMemory>
+    <DataMask>1</DataMask>
+    <ECC>Disabled</ECC>
+    <Ordering>Normal</Ordering>
+    <BankMachineCnt>4</BankMachineCnt>
+    <CustomPart>FALSE</CustomPart>
+    <NewPartName/>
+    <RowAddress>14</RowAddress>
+    <ColAddress>10</ColAddress>
+    <BankAddress>3</BankAddress>
+    <MemoryVoltage>1.35V</MemoryVoltage>
+    <C0_MEM_SIZE>268435456</C0_MEM_SIZE>
+    <UserMemoryAddressMap>BANK_ROW_COLUMN</UserMemoryAddressMap>
+    <PinSelection>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R2" SLEW="" VCCAUX_IO="" name="ddr3_addr[0]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R6" SLEW="" VCCAUX_IO="" name="ddr3_addr[10]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U6" SLEW="" VCCAUX_IO="" name="ddr3_addr[11]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="T6" SLEW="" VCCAUX_IO="" name="ddr3_addr[12]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="T8" SLEW="" VCCAUX_IO="" name="ddr3_addr[13]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="M6" SLEW="" VCCAUX_IO="" name="ddr3_addr[1]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="N4" SLEW="" VCCAUX_IO="" name="ddr3_addr[2]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="T1" SLEW="" VCCAUX_IO="" name="ddr3_addr[3]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="N6" SLEW="" VCCAUX_IO="" name="ddr3_addr[4]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R7" SLEW="" VCCAUX_IO="" name="ddr3_addr[5]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="V6" SLEW="" VCCAUX_IO="" name="ddr3_addr[6]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U7" SLEW="" VCCAUX_IO="" name="ddr3_addr[7]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R8" SLEW="" VCCAUX_IO="" name="ddr3_addr[8]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="V7" SLEW="" VCCAUX_IO="" name="ddr3_addr[9]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R1" SLEW="" VCCAUX_IO="" name="ddr3_ba[0]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="P4" SLEW="" VCCAUX_IO="" name="ddr3_ba[1]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="P2" SLEW="" VCCAUX_IO="" name="ddr3_ba[2]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="M4" SLEW="" VCCAUX_IO="" name="ddr3_cas_n"/>
+      <Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="V9" SLEW="" VCCAUX_IO="" name="ddr3_ck_n[0]"/>
+      <Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="U9" SLEW="" VCCAUX_IO="" name="ddr3_ck_p[0]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="N5" SLEW="" VCCAUX_IO="" name="ddr3_cke[0]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U8" SLEW="" VCCAUX_IO="" name="ddr3_cs_n[0]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="L1" SLEW="" VCCAUX_IO="" name="ddr3_dm[0]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U1" SLEW="" VCCAUX_IO="" name="ddr3_dm[1]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="K5" SLEW="" VCCAUX_IO="" name="ddr3_dq[0]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U4" SLEW="" VCCAUX_IO="" name="ddr3_dq[10]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="V5" SLEW="" VCCAUX_IO="" name="ddr3_dq[11]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="V1" SLEW="" VCCAUX_IO="" name="ddr3_dq[12]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="T3" SLEW="" VCCAUX_IO="" name="ddr3_dq[13]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U3" SLEW="" VCCAUX_IO="" name="ddr3_dq[14]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R3" SLEW="" VCCAUX_IO="" name="ddr3_dq[15]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="L3" SLEW="" VCCAUX_IO="" name="ddr3_dq[1]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="K3" SLEW="" VCCAUX_IO="" name="ddr3_dq[2]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="L6" SLEW="" VCCAUX_IO="" name="ddr3_dq[3]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="M3" SLEW="" VCCAUX_IO="" name="ddr3_dq[4]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="M1" SLEW="" VCCAUX_IO="" name="ddr3_dq[5]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="L4" SLEW="" VCCAUX_IO="" name="ddr3_dq[6]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="M2" SLEW="" VCCAUX_IO="" name="ddr3_dq[7]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="V4" SLEW="" VCCAUX_IO="" name="ddr3_dq[8]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="T5" SLEW="" VCCAUX_IO="" name="ddr3_dq[9]"/>
+      <Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="N1" SLEW="" VCCAUX_IO="" name="ddr3_dqs_n[0]"/>
+      <Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="V2" SLEW="" VCCAUX_IO="" name="ddr3_dqs_n[1]"/>
+      <Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="N2" SLEW="" VCCAUX_IO="" name="ddr3_dqs_p[0]"/>
+      <Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="U2" SLEW="" VCCAUX_IO="" name="ddr3_dqs_p[1]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R5" SLEW="" VCCAUX_IO="" name="ddr3_odt[0]"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="P3" SLEW="" VCCAUX_IO="" name="ddr3_ras_n"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="K6" SLEW="" VCCAUX_IO="" name="ddr3_reset_n"/>
+      <Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="P5" SLEW="" VCCAUX_IO="" name="ddr3_we_n"/>
+    </PinSelection>
+    <System_Clock>
+      <Pin Bank="35" PADName="E3(MRCC_P)" name="sys_clk_i"/>
+    </System_Clock>
+    <System_Control>
+      <Pin Bank="Select Bank" PADName="No connect" name="sys_rst"/>
+      <Pin Bank="Select Bank" PADName="No connect" name="init_calib_complete"/>
+      <Pin Bank="Select Bank" PADName="No connect" name="tg_compare_error"/>
+    </System_Control>
+    <TimingParameters>
+      <Parameters tcke="5.625" tfaw="45" tras="36" trcd="13.5" trefi="7.8" trfc="160" trp="13.5" trrd="7.5" trtp="7.5" twtr="7.5"/>
+    </TimingParameters>
+    <mrBurstLength name="Burst Length">8 - Fixed</mrBurstLength>
+    <mrBurstType name="Read Burst Type and Length">Sequential</mrBurstType>
+    <mrCasLatency name="CAS Latency">5</mrCasLatency>
+    <mrMode name="Mode">Normal</mrMode>
+    <mrDllReset name="DLL Reset">No</mrDllReset>
+    <mrPdMode name="DLL control for precharge PD">Slow Exit</mrPdMode>
+    <emrDllEnable name="DLL Enable">Enable</emrDllEnable>
+    <emrOutputDriveStrength name="Output Driver Impedance Control">RZQ/6</emrOutputDriveStrength>
+    <emrMirrorSelection name="Address Mirroring">Disable</emrMirrorSelection>
+    <emrCSSelection name="Controller Chip Select Pin">Enable</emrCSSelection>
+    <emrRTT name="RTT (nominal) - On Die Termination (ODT)">RZQ/6</emrRTT>
+    <emrPosted name="Additive Latency (AL)">0</emrPosted>
+    <emrOCD name="Write Leveling Enable">Disabled</emrOCD>
+    <emrDQS name="TDQS enable">Enabled</emrDQS>
+    <emrRDQS name="Qoff">Output Buffer Enabled</emrRDQS>
+    <mr2PartialArraySelfRefresh name="Partial-Array Self Refresh">Full Array</mr2PartialArraySelfRefresh>
+    <mr2CasWriteLatency name="CAS write latency">5</mr2CasWriteLatency>
+    <mr2AutoSelfRefresh name="Auto Self Refresh">Enabled</mr2AutoSelfRefresh>
+    <mr2SelfRefreshTempRange name="High Temparature Self Refresh Rate">Normal</mr2SelfRefreshTempRange>
+    <mr2RTTWR name="RTT_WR - Dynamic On Die Termination (ODT)">Dynamic ODT off</mr2RTTWR>
+    <PortInterface>AXI</PortInterface>
+    <AXIParameters>
+      <C0_C_RD_WR_ARB_ALGORITHM>RD_PRI_REG</C0_C_RD_WR_ARB_ALGORITHM>
+      <C0_S_AXI_ADDR_WIDTH>28</C0_S_AXI_ADDR_WIDTH>
+      <C0_S_AXI_DATA_WIDTH>64</C0_S_AXI_DATA_WIDTH>
+      <C0_S_AXI_ID_WIDTH>5</C0_S_AXI_ID_WIDTH>
+      <C0_S_AXI_SUPPORTS_NARROW_BURST>0</C0_S_AXI_SUPPORTS_NARROW_BURST>
+    </AXIParameters>
+  </Controller>
+
+
+</Project>
diff --git a/vendor/pulp-platform/common_cells/src/cdc_2phase_clearable.sv b/vendor/pulp-platform/common_cells/src/cdc_2phase_clearable.sv
new file mode 100644
index 0000000000000000000000000000000000000000..c538aa6c61aa04cdfe1bfc430f24c218cbba8041
--- /dev/null
+++ b/vendor/pulp-platform/common_cells/src/cdc_2phase_clearable.sv
@@ -0,0 +1,340 @@
+// Copyright 2018 ETH Zurich and University of Bologna.
+//
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this 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.
+//
+// Fabian Schuiki <fschuiki@iis.ee.ethz.ch> (original CDC)
+// Manuel Eggimann <meggiman@iis.ee.ethz.ch> (clearability feature)
+
+/// A two-phase clock domain crossing.
+///
+/// CONSTRAINT: Requires max_delay of min_period(src_clk_i, dst_clk_i) through
+/// the paths async_req, async_ack, async_data.
+///
+///
+/// Reset Behavior:
+///
+/// In contrast to the cdc_2phase version without clear signal, this module
+/// supports one-sided warm resets (asynchronously and synchronously). The way
+/// this is implemented is described in more detail in the cdc_reset_ctrlr
+/// module. To summarize a synchronous clear request i.e. src/dst_clear_i will
+/// cause the respective other clock domain to reset as well without introducing
+/// any spurious transactions. This is acomplished by an internal module
+/// (cdc_reset_ctrlr) that starts a reset sequence on both sides of the CDC in
+/// lock-step that first isolates the CDC from the outside world and then resets
+/// it. The reset sequencer provides the following behavior:
+/// 1. There are no spurious invalid or duplicated transactions regardless how
+///    the individual sides are reset (can also happen roughly simultaneosly)
+/// 2. The CDC becomes unready at the src side in the next cycle after
+///    synchronous reset request until the reset sequence is completed. A currently
+///    pending transactions might still complete (if the dst accepts at the
+///    exact time the reset is request on the src die).
+/// 3. During the reset sequence the dst might withdraw the valid signal. This
+///    might violate higher level protocols. If you need this feature you would
+///    have to path the existing implementation to wait with the isolate_ack
+///    assertion until all open handshakes were acknowledged.
+/// 4. If the parameter CLEAR_ON_ASYNC_RESET is enabled, the same behavior as
+///    above is also valid for asynchronous resets on either side. However, this
+///    increases the minimum number of synchronization stages (SYNC_STAGES
+///    parameter) from 2 to 3 (read the cdc_reset_ctrlr header to figure out
+///    why).
+///
+///
+/* verilator lint_off DECLFILENAME */
+
+`include "common_cells/registers.svh"
+`include "common_cells/assertions.svh"
+
+module cdc_2phase_clearable #(
+  parameter type T = logic,
+  parameter int unsigned SYNC_STAGES = 3,
+  parameter int CLEAR_ON_ASYNC_RESET = 1
+)(
+  input  logic src_rst_ni,
+  input  logic src_clk_i,
+  input  logic src_clear_i,
+  output logic src_clear_pending_o,
+  input  T     src_data_i,
+  input  logic src_valid_i,
+  output logic src_ready_o,
+
+  input  logic dst_rst_ni,
+  input  logic dst_clk_i,
+  input  logic dst_clear_i,
+  output logic dst_clear_pending_o,
+  output T     dst_data_o,
+  output logic dst_valid_o,
+  input  logic dst_ready_i
+);
+  logic        s_src_clear_req;
+  logic        s_src_clear_ack_q;
+  logic        s_src_ready;
+  logic        s_src_isolate_req;
+  logic        s_src_isolate_ack_q;
+  logic        s_dst_clear_req;
+  logic        s_dst_clear_ack_q;
+  logic        s_dst_valid;
+  logic        s_dst_isolate_req;
+  logic        s_dst_isolate_ack_q;
+
+  // Asynchronous handshake signals between the CDCs
+  (* dont_touch = "true" *) logic async_req;
+  (* dont_touch = "true" *) logic async_ack;
+  (* dont_touch = "true" *) T async_data;
+
+  if (CLEAR_ON_ASYNC_RESET) begin : gen_elaboration_assertion
+    if (SYNC_STAGES < 3)
+      $error("The clearable 2-phase CDC with async reset",
+             "synchronization requires at least 3 synchronizer stages for the FIFO.");
+  end else begin : gen_elaboration_assertion
+    if (SYNC_STAGES < 2) begin : gen_elaboration_assertion
+      $error("A minimum of 2 synchronizer stages is required for proper functionality.");
+    end
+  end
+
+
+  // The sender in the source domain.
+  cdc_2phase_src_clearable #(
+    .T           ( T           ),
+    .SYNC_STAGES ( SYNC_STAGES )
+  ) i_src (
+    .rst_ni       ( src_rst_ni                       ),
+    .clk_i        ( src_clk_i                        ),
+    .clear_i      ( s_src_clear_req                      ),
+    .data_i       ( src_data_i                       ),
+    .valid_i      ( src_valid_i & !s_src_isolate_req ),
+    .ready_o      ( s_src_ready                      ),
+    .async_req_o  ( async_req                        ),
+    .async_ack_i  ( async_ack                        ),
+    .async_data_o ( async_data                       )
+  );
+
+  assign src_ready_o = s_src_ready & !s_src_isolate_req;
+
+
+  // The receiver in the destination domain.
+  cdc_2phase_dst_clearable #(
+    .T           ( T           ),
+    .SYNC_STAGES ( SYNC_STAGES )
+  ) i_dst (
+    .rst_ni       ( dst_rst_ni                       ),
+    .clk_i        ( dst_clk_i                        ),
+    .clear_i      ( s_dst_clear_req                      ),
+    .data_o       ( dst_data_o                       ),
+    .valid_o      ( s_dst_valid                      ),
+    .ready_i      ( dst_ready_i & !s_dst_isolate_req ),
+    .async_req_i  ( async_req                        ),
+    .async_ack_o  ( async_ack                        ),
+    .async_data_i ( async_data                       )
+  );
+
+  assign dst_valid_o = s_dst_valid & !s_dst_isolate_req;
+
+  // Synchronize the clear and reset signaling in both directions (see header of
+  // the cdc_reset_ctrlr module for more details.)
+  cdc_reset_ctrlr #(
+    .SYNC_STAGES(SYNC_STAGES-1)
+  ) i_cdc_reset_ctrlr (
+    .a_clk_i         ( src_clk_i           ),
+    .a_rst_ni        ( src_rst_ni          ),
+    .a_clear_i       ( src_clear_i         ),
+    .a_clear_o       ( s_src_clear_req     ),
+    .a_clear_ack_i   ( s_src_clear_ack_q   ),
+    .a_isolate_o     ( s_src_isolate_req   ),
+    .a_isolate_ack_i ( s_src_isolate_ack_q ),
+    .b_clk_i         ( dst_clk_i           ),
+    .b_rst_ni        ( dst_rst_ni          ),
+    .b_clear_i       ( dst_clear_i         ),
+    .b_clear_o       ( s_dst_clear_req     ),
+    .b_clear_ack_i   ( s_dst_clear_ack_q   ),
+    .b_isolate_o     ( s_dst_isolate_req   ),
+    .b_isolate_ack_i ( s_dst_isolate_ack_q )
+  );
+
+  // Just delay the isolate request by one cycle. We can ensure isolation within
+  // one cycle by just deasserting valid and ready signals on both sides of the CDC.
+  always_ff @(posedge src_clk_i, negedge src_rst_ni) begin
+    if (!src_rst_ni) begin
+      s_src_isolate_ack_q <= 1'b0;
+      s_src_clear_ack_q   <= 1'b0;
+    end else begin
+      s_src_isolate_ack_q <= s_src_isolate_req;
+      s_src_clear_ack_q   <= s_src_clear_req;
+    end
+  end
+
+  always_ff @(posedge dst_clk_i, negedge dst_rst_ni) begin
+    if (!dst_rst_ni) begin
+      s_dst_isolate_ack_q <= 1'b0;
+      s_dst_clear_ack_q   <= 1'b0;
+    end else begin
+      s_dst_isolate_ack_q <= s_dst_isolate_req;
+      s_dst_clear_ack_q   <= s_dst_clear_req;
+    end
+  end
+
+
+  assign src_clear_pending_o = s_src_isolate_req; // The isolate signal stays
+  // asserted during the whole
+  // clear sequence.
+  assign dst_clear_pending_o = s_dst_isolate_req;
+
+
+`ifndef COMMON_CELLS_ASSERTS_OFF
+
+  `ASSERT(no_valid_i_during_clear_i, src_clear_i |-> !src_valid_i, src_clk_i, !src_rst_ni)
+
+`endif
+
+endmodule
+
+
+/// Half of the two-phase clock domain crossing located in the source domain.
+module cdc_2phase_src_clearable #(
+  parameter type T = logic,
+  parameter int unsigned SYNC_STAGES = 2
+) (
+  input  logic rst_ni,
+  input  logic clk_i,
+  input  logic clear_i,
+  input  T     data_i,
+  input  logic valid_i,
+  output logic ready_o,
+  output logic async_req_o,
+  input  logic async_ack_i,
+  output T     async_data_o
+);
+
+  (* dont_touch = "true" *)
+  logic  req_src_d, req_src_q, ack_synced;
+  (* dont_touch = "true" *)
+  T data_src_d, data_src_q;
+
+  // Synchronize the async ACK
+  sync #(
+    .STAGES(SYNC_STAGES)
+  ) i_sync(
+    .clk_i,
+    .rst_ni,
+    .serial_i( async_ack_i ),
+    .serial_o( ack_synced  )
+  );
+
+  // If we receive the clear signal clear the content of the request flip-flop
+  // and the data register
+  always_comb begin
+    data_src_d = data_src_q;
+    req_src_d  = req_src_q;
+    if (clear_i) begin
+      req_src_d  = 1'b0;
+    // The req_src and data_src registers change when a new data item is accepted.
+    end else if (valid_i && ready_o) begin
+      req_src_d  = ~req_src_q;
+      data_src_d = data_i;
+    end
+  end
+
+  `FFNR(data_src_q, data_src_d, clk_i)
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      req_src_q  <= 0;
+    end else begin
+      req_src_q  <= req_src_d;
+    end
+  end
+
+  // Output assignments.
+  assign ready_o = (req_src_q == ack_synced);
+  assign async_req_o = req_src_q;
+  assign async_data_o = data_src_q;
+
+// Assertions
+`ifndef COMMON_CELLS_ASSERTS_OFF
+  `ASSUME(no_clear_and_request, clear_i |-> ~valid_i, clk_i, !rst_ni,
+          "No request allowed while clear_i is asserted.")
+`endif
+
+endmodule
+
+
+/// Half of the two-phase clock domain crossing located in the destination
+/// domain.
+module cdc_2phase_dst_clearable #(
+  parameter type T = logic,
+  parameter int unsigned SYNC_STAGES = 2
+)(
+  input  logic rst_ni,
+  input  logic clk_i,
+  input  logic clear_i,
+  output T     data_o,
+  output logic valid_o,
+  input  logic ready_i,
+  input  logic async_req_i,
+  output logic async_ack_o,
+  input  T     async_data_i
+);
+
+  (* dont_touch = "true" *)
+  (* async_reg = "true" *)
+ logic ack_dst_d, ack_dst_q, req_synced, req_synced_q1;
+  (* dont_touch = "true" *)
+  T data_dst_d, data_dst_q;
+
+
+  //Synchronize the request
+  sync #(
+    .STAGES(SYNC_STAGES)
+  ) i_sync(
+    .clk_i,
+    .rst_ni,
+    .serial_i( async_req_i ),
+    .serial_o( req_synced  )
+  );
+
+  // The ack_dst register changes when a new data item is accepted.
+  always_comb begin
+    ack_dst_d = ack_dst_q;
+    if (clear_i) begin
+      ack_dst_d = 1'b0;
+    end else if (valid_o && ready_i) begin
+      ack_dst_d = ~ack_dst_q;
+    end
+  end
+
+  // The data_dst register samples when a new data item is presented. This is
+  // indicated by a transition in the req_synced line.
+  always_comb begin
+    data_dst_d = data_dst_q;
+    if (req_synced != req_synced_q1 && !valid_o) begin
+      data_dst_d = async_data_i;
+    end
+  end
+
+  `FFNR(data_dst_q, data_dst_d, clk_i)
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      ack_dst_q     <= 0;
+      req_synced_q1 <= 1'b0;
+    end else begin
+      ack_dst_q     <= ack_dst_d;
+      // The req_synced_q1 is the delayed version of the synchronized req_synced
+      // used to detect transitions in the request.
+      req_synced_q1 <= req_synced;
+    end
+  end
+
+  // Output assignments.
+  assign valid_o = (ack_dst_q != req_synced_q1);
+  assign data_o = data_dst_q;
+  assign async_ack_o = ack_dst_q;
+
+endmodule
+/* verilator lint_on DECLFILENAME */
diff --git a/vendor/pulp-platform/common_cells/src/cdc_4phase.sv b/vendor/pulp-platform/common_cells/src/cdc_4phase.sv
new file mode 100644
index 0000000000000000000000000000000000000000..bd4c65ae52cf00c17e520d09f8d5378beae42214
--- /dev/null
+++ b/vendor/pulp-platform/common_cells/src/cdc_4phase.sv
@@ -0,0 +1,327 @@
+// Copyright 2018 ETH Zurich and University of Bologna.
+//
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this 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.
+//
+// Manuel Eggimann <meggimann@iis.ee.ethz.ch>
+
+/// A 4-phase clock domain crossing. While this is less efficient than a 2-phase
+/// CDC, it doesn't suffer from the same issues during one sided resets since
+/// the IDLE state doesn't alternate with every transaction.
+///
+/// Parameters: T - The type of the data to transmit through the CDC.
+///
+/// Decoupled - If decoupled is disabled, the 4phase cdc will not consume the
+/// src item until the handshake with the other side is completed. This
+/// increases the latency of the first transaction but has no effect on
+/// throughput. However, critical paths might be slightly longer. Use this mode
+/// if you want to ensure that there are no in-flight transactions within the
+/// CDC.
+///
+/// SEND_RESET_MSG - If send reset msg is enabled, the 4phase cdc starts sending
+/// the RESET_MSG within its' asynchronous reset state. This can be usefull if
+/// we need to transmit a message to the other side of the CDC immediately
+/// during an async reset even if there is no clock available. This mode is
+/// required for proper functionality of the cdc_reset_ctrlr module.
+///
+/// CONSTRAINT: Requires max_delay of min_period(src_clk_i, dst_clk_i) through
+/// the paths async_req, async_ack, async_data.
+/* verilator lint_off DECLFILENAME */
+module cdc_4phase #(
+  parameter type T = logic,
+  parameter bit DECOUPLED = 1'b1,
+  parameter bit SEND_RESET_MSG = 1'b0,
+  parameter T RESET_MSG = T'('0)
+)(
+  input  logic src_rst_ni,
+  input  logic src_clk_i,
+  input  T     src_data_i,
+  input  logic src_valid_i,
+  output logic src_ready_o,
+
+  input  logic dst_rst_ni,
+  input  logic dst_clk_i,
+  output T     dst_data_o,
+  output logic dst_valid_o,
+  input  logic dst_ready_i
+);
+
+  // Asynchronous handshake signals.
+  (* dont_touch = "true" *) logic async_req;
+  (* dont_touch = "true" *) logic async_ack;
+  (* dont_touch = "true" *) T async_data;
+
+  // The sender in the source domain.
+  cdc_4phase_src #(
+    .T(T),
+    .DECOUPLED(DECOUPLED),
+    .SEND_RESET_MSG(SEND_RESET_MSG),
+    .RESET_MSG(RESET_MSG)
+  ) i_src (
+    .rst_ni       ( src_rst_ni  ),
+    .clk_i        ( src_clk_i   ),
+    .data_i       ( src_data_i  ),
+    .valid_i      ( src_valid_i ),
+    .ready_o      ( src_ready_o ),
+    .async_req_o  ( async_req   ),
+    .async_ack_i  ( async_ack   ),
+    .async_data_o ( async_data  )
+  );
+
+  // The receiver in the destination domain.
+  cdc_4phase_dst #(.T(T), .DECOUPLED(DECOUPLED)) i_dst (
+    .rst_ni       ( dst_rst_ni  ),
+    .clk_i        ( dst_clk_i   ),
+    .data_o       ( dst_data_o  ),
+    .valid_o      ( dst_valid_o ),
+    .ready_i      ( dst_ready_i ),
+    .async_req_i  ( async_req   ),
+    .async_ack_o  ( async_ack   ),
+    .async_data_i ( async_data  )
+  );
+endmodule
+
+
+/// Half of the 4-phase clock domain crossing located in the source domain.
+module cdc_4phase_src #(
+  parameter type T = logic,
+  parameter int unsigned SYNC_STAGES = 2,
+  parameter bit DECOUPLED = 1'b1,
+  parameter bit SEND_RESET_MSG = 1'b0,
+  parameter T RESET_MSG = T'('0)
+)(
+  input  logic rst_ni,
+  input  logic clk_i,
+  input  T     data_i,
+  input  logic valid_i,
+  output logic ready_o,
+  output logic async_req_o,
+  input  logic async_ack_i,
+  output T     async_data_o
+);
+
+  (* dont_touch = "true" *)
+  logic  req_src_d, req_src_q;
+  (* dont_touch = "true" *)
+  T data_src_d, data_src_q;
+  (* dont_touch = "true" *)
+  logic  ack_synced;
+
+  typedef enum logic[1:0] {IDLE, WAIT_ACK_ASSERT, WAIT_ACK_DEASSERT} state_e;
+  state_e state_d, state_q;
+
+  // Synchronize the async ACK
+  sync #(
+    .STAGES(SYNC_STAGES)
+  ) i_sync(
+    .clk_i,
+    .rst_ni,
+    .serial_i( async_ack_i ),
+    .serial_o( ack_synced  )
+  );
+
+  // FSM for the 4-phase handshake
+  always_comb begin
+    state_d    = state_q;
+    req_src_d  = 1'b0;
+    data_src_d = data_src_q;
+    ready_o    = 1'b0;
+    case (state_q)
+      IDLE: begin
+        // If decoupling is disabled, defer assertion of ready until the
+        // handshake with the dst is completed
+        if (DECOUPLED) begin
+          ready_o = 1'b1;
+        end else begin
+          ready_o = 1'b0;
+        end
+        // Sample a new item when the valid signal is asserted.
+        if (valid_i) begin
+          data_src_d = data_i;
+          req_src_d  = 1'b1;
+          state_d = WAIT_ACK_ASSERT;
+        end
+      end
+      WAIT_ACK_ASSERT: begin
+        req_src_d = 1'b1;
+        if (ack_synced == 1'b1) begin
+          req_src_d = 1'b0;
+          state_d   = WAIT_ACK_DEASSERT;
+        end
+      end
+      WAIT_ACK_DEASSERT: begin
+        if (ack_synced == 1'b0) begin
+          state_d = IDLE;
+          if (!DECOUPLED) begin
+            ready_o = 1'b1;
+          end
+        end
+      end
+      default: begin
+        state_d = IDLE;
+      end
+    endcase
+  end
+
+  always_ff @(posedge clk_i, negedge rst_ni) begin
+    if (!rst_ni) begin
+      state_q <= IDLE;
+    end else begin
+      state_q <= state_d;
+    end
+  end
+
+  // Sample the data and the request signal to filter combinational glitches
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      if (SEND_RESET_MSG) begin
+        req_src_q  <= 1'b1;
+        data_src_q <= RESET_MSG;
+      end else begin
+        req_src_q  <= 1'b0;
+        data_src_q <= T'('0);
+      end
+    end else begin
+      req_src_q  <= req_src_d;
+      data_src_q <= data_src_d;
+    end
+  end
+
+  // Async output assignments.
+  assign async_req_o = req_src_q;
+  assign async_data_o = data_src_q;
+
+endmodule
+
+
+/// Half of the 4-phase clock domain crossing located in the destination
+/// domain.
+module cdc_4phase_dst #(
+  parameter type T = logic,
+  parameter int unsigned SYNC_STAGES = 2,
+  parameter bit DECOUPLED = 1
+)(
+  input  logic rst_ni,
+  input  logic clk_i,
+  output T     data_o,
+  output logic valid_o,
+  input  logic ready_i,
+  input  logic async_req_i,
+  output logic async_ack_o,
+  input  T     async_data_i
+);
+
+  (* dont_touch = "true" *)
+  logic  ack_dst_d, ack_dst_q;
+  (* dont_touch = "true" *)
+  logic  req_synced;
+
+  logic  data_valid;
+
+  logic  output_ready;
+
+
+  typedef enum logic[1:0] {IDLE, WAIT_DOWNSTREAM_ACK, WAIT_REQ_DEASSERT} state_e;
+  state_e state_d, state_q;
+
+  //Synchronize the request
+  sync #(
+    .STAGES(SYNC_STAGES)
+  ) i_sync(
+    .clk_i,
+    .rst_ni,
+    .serial_i( async_req_i ),
+    .serial_o( req_synced  )
+  );
+
+  // FSM for the 4-phase handshake
+  always_comb begin
+    state_d    = state_q;
+    data_valid = 1'b0;
+    ack_dst_d  = 1'b0;
+
+    case (state_q)
+      IDLE: begin
+        // Sample the data upon a new request and transition to the next state
+        if (req_synced == 1'b1) begin
+          data_valid = 1'b1;
+          if (output_ready == 1'b1) begin
+            state_d = WAIT_REQ_DEASSERT;
+          end else begin
+            state_d = WAIT_DOWNSTREAM_ACK;
+          end
+        end
+      end
+
+      WAIT_DOWNSTREAM_ACK: begin
+        data_valid       = 1'b1;
+        if (output_ready == 1'b1) begin
+          state_d    = WAIT_REQ_DEASSERT;
+          ack_dst_d  = 1'b1;
+        end
+      end
+
+      WAIT_REQ_DEASSERT: begin
+        ack_dst_d = 1'b1;
+        if (req_synced == 1'b0) begin
+          ack_dst_d = 1'b0;
+          state_d   = IDLE;
+        end
+      end
+
+      default: begin
+        state_d = IDLE;
+      end
+    endcase
+  end
+
+  always_ff @(posedge clk_i, negedge rst_ni) begin
+    if (!rst_ni) begin
+      state_q <= IDLE;
+    end else begin
+      state_q <= state_d;
+    end
+  end
+
+  // Filter glitches on ack signal before sending it through the asynchronous channel
+  always_ff @(posedge clk_i, negedge rst_ni) begin
+    if (!rst_ni) begin
+      ack_dst_q <= 1'b0;
+    end else begin
+      ack_dst_q <= ack_dst_d;
+    end
+  end
+
+  if (DECOUPLED) begin : gen_decoupled
+    // Decouple the output from the asynchronous data bus without introducing
+    // additional latency by inserting a spill register
+    spill_register #(
+      .T(T),
+      .Bypass(1'b0)
+    ) i_spill_register (
+      .clk_i,
+      .rst_ni,
+      .valid_i(data_valid),
+      .ready_o(output_ready),
+      .data_i(async_data_i),
+      .valid_o,
+      .ready_i,
+      .data_o
+    );
+  end else begin : gen_not_decoupled
+    assign valid_o      = data_valid;
+    assign output_ready = ready_i;
+    assign data_o       = async_data_i;
+  end
+
+  // Output assignments.
+  assign async_ack_o = ack_dst_q;
+
+endmodule
+/* verilator lint_on DECLFILENAME */
diff --git a/vendor/pulp-platform/common_cells/src/cdc_reset_ctrlr.sv b/vendor/pulp-platform/common_cells/src/cdc_reset_ctrlr.sv
new file mode 100644
index 0000000000000000000000000000000000000000..3ea5e3b755aef84e567941a52a086ed184e31e54
--- /dev/null
+++ b/vendor/pulp-platform/common_cells/src/cdc_reset_ctrlr.sv
@@ -0,0 +1,529 @@
+//-----------------------------------------------------------------------------
+// Title : CDC Clear Signaling Synchronization
+// -----------------------------------------------------------------------------
+// File : cdc_clear_propagator.sv Author : Manuel Eggimann
+// <meggimann@iis.ee.ethz.ch> Created : 22.12.2021
+// -----------------------------------------------------------------------------
+// Description :
+//
+// This module is mainly used internally to synchronize the clear requests
+// between both sides of a CDC module. It aims to solve the problem of
+// initiating a CDC clear, reset one-sidedly without running into
+// reset-domain-crossing issues and breaking CDC protocol assumption.
+//
+// Problem Formulation:
+//
+// CDC implementations usually face the issue that one side of the CDC must not
+// be cleared without clearing the other side. E.g. clearing the write-pointer
+// without clearing the read-pointer in a gray-counting CDC FIFO results in an
+// invalid fill-state an may cause spurious transactions of invalid data to be
+// propagated accross the CDC. A similar effect is caused in 2-phase CDC
+// implementations.
+//
+// A naive mitigation technique would be to reset both domains asynchronously
+// with the same reset signal. This will cause intra-clock domain RDC issues
+// since the asynchronous clear event (assertion of the reset signal) might
+// happen close to the active edge of the CDC's periphery and thus might induce
+// metastability. A better, but still flawed approach would be to naively
+// synchronize assertion AND deassertion (the usual rst sync only synchronize
+// deassertion) of the resets into the respective other domain. However, this
+// might cause the classic issue of fast-to-slow clock domain crossing where the
+// clear signal is not asserted long enough to be captured by the receiving
+// side. The common mitigation strategy is to use a feedback acknowledge signal
+// to handshake the reset request into the other domain. One even more peculiar
+// corner case this approach might suffer is the scenario where the synchronized
+// clear signal arrives at the other side of the CDC within or even worse after
+// the same clock cylce that the other domain crossing signals (e.g. read/write
+// pointers) are cleared. In this scenario, multiple signals change within the
+// same clock cycle and due to metastability we cannot be sure, that the other
+// side of the CDC sees the reset assertion before the first bits of e.g. the
+// write/read pointer start to switch to their reset state. Care must also be
+// taken to handle the corner cases where both sides are reset simultaneously or
+// the case where one side leaves reset earlier than the other.
+//
+// How this Module Works
+//
+// This module has two interfaces, the 'a' side and the 'b' side. Each side can
+// be triggered using the a/b_clear_i signal or (optionally) by the asynchronous
+// a/b_rst_ni. Once e.g. 'a' is triggered it will initiate a clear sequence that
+// first asserts an 'a_isolate_o' signal, waits until the external circuitry
+// acknowledges isolation using the 'a_isolate_ack_i'. Then the module asserts
+// the 'a_clear_o' signals before some cycles later, the isolate signal is
+// deasserted. This sequence ensures that no transactions can arrive to the CDC
+// while the state is cleared. Now the important part is, that those four phases
+// (asser isolate, assert clear, deassert clear, deassert isolate) are mirrored
+// on the other side ('b') in lock-step. The cdc_reset_ctrlr module uses a
+// dedicated 4-phase handshaking CDC to transmit the current phase of the clear
+// sequence to the other domain. We use a 4-phase rather than a 2-phase CDC to
+// avoid the issues of one-sided async reset that might trigger spurious
+// transactions. Furthermore, the 4-phase CDC within this module is operated in
+// a special mode: DECOUPLED=0 ensures that there are no in-flight transactions.
+// The src side only consumes the item once the destination side acknowledged
+// the receiption. This property is required to transition through the phases in
+// lock-step. Furthermore, (SEND_RESET_MSG=1) will cause the src side of the
+// 4-phase CDC to immediately initiate the isolation phase in the dst domain
+// upon asynchronous reset regardless how long the async reset stays asserted or
+// whether the source clock is gated. Both sides of this module independently
+// generate the sequence signals as an initiator (triggered by the clear_i or
+// rst_ni signal) or receiver (trigerred for the other side). The or-ed version
+// of initiator and receiver are used to generate the actual a/b_isolate_o and
+// a/b_clear_o signal. That way, it doesn't matter wheter both sides
+// simulatenously trigger a clear sequence, proper sequencing is still
+// guaranteed.
+//
+// The time it takes to complete an entire clear sequence can be bounded as follows:
+//
+// t_clear <= 20*T+16*SYNC_STAGES*T, with T=max(T_a, T_b) (clock periods of src and dst)
+//
+// How to Use the Module
+//
+// Instantiate the module within your CDC and connect a/b_clk_i, the
+// asyncrhonous a/b_rst_ni and the synchronous a/b_clear_i signals. The 'a' and
+// 'b' port are entirely symetric so it doesn't matter whether you connect src
+// to 'a' or 'b'. If you enable support for async reset
+// (CLEAR_ON_ASYNC_RESET==1), parametrize the number of synchronization stages
+// (for metastability resolution) to be strictly less than the latency of the
+// CDC. E.g. if your CDC uses 3 (the minimum) sync stages, parametrize this
+// module with SYNC_STAGES < 2! Your CDC must implement a src/dst_clear_i port
+// that SYNCHRONOUSLY clears all FFs on the respective side. Connect the CDC's
+// src/dst_clear ports to this module's a/b_clear_o port. Once the a/b_isolate_o
+// signal is asserted, the respective CDC side (src/dst) must be isolated from
+// the outside world (i.e. must no longer accept any transaction on the src side
+// and cease presenting or even withdrawing data on the dst side). Once your CDC
+// side is isolated (depending on protocol this might take several cycles),
+// assert the a/b_isolate_ack_i signal.
+//
+// -----------------------------------------------------------------------------
+// Copyright (C) 2021 ETH Zurich, University of Bologna Copyright and related
+// rights are licensed under the Solderpad Hardware License, Version 0.51 (the
+// "License"); you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law or
+// agreed to in writing, software, hardware and materials distributed under this
+// 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.
+// SPDX-License-Identifier: SHL-0.51
+// -----------------------------------------------------------------------------
+
+module cdc_reset_ctrlr
+  import cdc_reset_ctrlr_pkg::*;
+ #(
+  /// The number of synchronization stages to use for the
+  /// clear signal request/acknowledge. Must be less than the
+  /// number of sync stages used in the CDC.
+  parameter int unsigned SYNC_STAGES = 2,
+  /// Whether an asynchronous reset shall cause a clear
+  /// request to be sent to the other side.
+  parameter logic        CLEAR_ON_ASYNC_RESET = 1'b1
+)(
+  // Side A (both sides are symmetric)
+  input logic  a_clk_i,
+  input logic  a_rst_ni,
+  input logic  a_clear_i,
+  output logic a_clear_o,
+  input logic a_clear_ack_i,
+  output logic a_isolate_o,
+  input logic  a_isolate_ack_i,
+  // Side B (both sides are symmetric)
+  input logic  b_clk_i,
+  input logic  b_rst_ni,
+  input logic  b_clear_i,
+  output logic b_clear_o,
+  input logic  b_clear_ack_i,
+  output logic b_isolate_o,
+  input logic  b_isolate_ack_i
+);
+
+  (* dont_touch = "true" *)
+  logic        async_a2b_req, async_b2a_ack;
+  (* dont_touch = "true" *)
+  clear_seq_phase_e async_a2b_next_phase;
+  (* dont_touch = "true" *)
+  logic        async_b2a_req, async_a2b_ack;
+  (* dont_touch = "true" *)
+  clear_seq_phase_e async_b2a_next_phase;
+
+  cdc_reset_ctrlr_half #(
+    .SYNC_STAGES          ( SYNC_STAGES          ),
+    .CLEAR_ON_ASYNC_RESET ( CLEAR_ON_ASYNC_RESET )
+  ) i_cdc_reset_ctrlr_half_a (
+    .clk_i              ( a_clk_i              ),
+    .rst_ni             ( a_rst_ni             ),
+    .clear_i            ( a_clear_i            ),
+    .clear_o            ( a_clear_o            ),
+    .clear_ack_i        ( a_clear_ack_i        ),
+    .isolate_o          ( a_isolate_o          ),
+    .isolate_ack_i      ( a_isolate_ack_i      ),
+    (* async *) .async_next_phase_o ( async_a2b_next_phase ),
+    (* async *) .async_req_o        ( async_a2b_req        ),
+    (* async *) .async_ack_i        ( async_b2a_ack        ),
+    (* async *) .async_next_phase_i ( async_b2a_next_phase ),
+    (* async *) .async_req_i        ( async_b2a_req        ),
+    (* async *) .async_ack_o        ( async_a2b_ack        )
+  );
+
+    cdc_reset_ctrlr_half #(
+    .SYNC_STAGES          ( SYNC_STAGES          ),
+    .CLEAR_ON_ASYNC_RESET ( CLEAR_ON_ASYNC_RESET )
+  ) i_cdc_reset_ctrlr_half_b (
+    .clk_i              ( b_clk_i              ),
+    .rst_ni             ( b_rst_ni             ),
+    .clear_i            ( b_clear_i            ),
+    .clear_o            ( b_clear_o            ),
+    .clear_ack_i        ( b_clear_ack_i        ),
+    .isolate_o          ( b_isolate_o          ),
+    .isolate_ack_i      ( b_isolate_ack_i      ),
+    (* async *) .async_next_phase_o ( async_b2a_next_phase ),
+    (* async *) .async_req_o        ( async_b2a_req        ),
+    (* async *) .async_ack_i        ( async_a2b_ack        ),
+    (* async *) .async_next_phase_i ( async_a2b_next_phase ),
+    (* async *) .async_req_i        ( async_a2b_req        ),
+    (* async *) .async_ack_o        ( async_b2a_ack        )
+  );
+endmodule
+
+
+module cdc_reset_ctrlr_half
+  import cdc_reset_ctrlr_pkg::*;
+#(
+  /// The number of synchronization stages to use for the
+  /// clear signal request/acknowledge. Must be less than
+  /// the number of sync stages used in the CDC
+  parameter int unsigned SYNC_STAGES = 2,
+  /// Whether an asynchronous reset shall cause a clear
+  /// request to be sent to the other side.
+  parameter logic        CLEAR_ON_ASYNC_RESET = 1'b1
+)(
+  // Synchronous side
+  input logic                clk_i,
+  input logic                rst_ni,
+  input logic                clear_i,
+  output logic               isolate_o,
+  input logic                isolate_ack_i,
+  output logic               clear_o,
+  input logic                clear_ack_i,
+  // Asynchronous clear sequence hanshaking
+  output clear_seq_phase_e   async_next_phase_o,
+  output logic               async_req_o,
+  input logic                async_ack_i,
+  input clear_seq_phase_e    async_next_phase_i,
+  input logic                async_req_i,
+  output logic               async_ack_o
+);
+
+
+  // How this module works:
+
+  // The module is split into two parts. The initiator part consists of an FSM
+  // that is triggered by the clear_i signal and transitions through reset
+  // sequence. During those transitions, the `initiator_isolate_out` and
+  // `initiator_clear_out` signals are asserted appropriately.
+
+  // The receiver part receives the state transitions from the other clock
+  // domain (initiator part of the `cdc_reset_ctrlr_half` instance in the other
+  // clock domain) and asserts the `receiver_isolate_out` and
+  // `receiver_clear_out` appropriately (considering the `isolate_ack_i`
+  // signal).
+
+  // In both, the initiator and the receiver part, the respective FSM
+  // transitions through 4 phases. In the ISOLATE phase, the isolate signal is
+  // asserted and the connected CDCs are expected to block all further
+  // interactions with the outside world and acknowledge the isolation with the
+  // isolate_ack_i signal. In the CLEAR phase, the clear signal is asserted
+  // which resets the internal state of the CDC while keeping the isolate signal
+  // asserted. In the POST_CLEAR phase, the clear signal is deasserted. Finally,
+  // when returning to the IDLE phase, the isolate signal is deasserted to
+  // continue normal operation. The FSM uses a dedicated 4-phase handshaking CDC
+  // to transition between the phases in lock-step and transmits the current
+  // state to the other domain to avoid issues if the other domain is reset
+  // asynchronously while a clear procedure is pending.
+
+  //---------------------- Initiator Side ----------------------
+  // Sends clear sequence state transitions to the other side.
+   typedef enum logic[3:0] {
+     IDLE,
+     ISOLATE,
+     WAIT_ISOLATE_PHASE_ACK,
+     WAIT_ISOLATE_ACK,
+     CLEAR,
+     WAIT_CLEAR_PHASE_ACK,
+     WAIT_CLEAR_ACK,
+     POST_CLEAR,
+     FINISHED
+  } initiator_state_e;
+  initiator_state_e initiator_state_d, initiator_state_q;
+
+  // The current phase of the clear sequence, sent to the other side using a
+  // 4-phase CDC
+  clear_seq_phase_e          initiator_clear_seq_phase;
+  logic                      initiator_phase_transition_req;
+  logic                      initiator_phase_transition_ack;
+  logic                      initiator_isolate_out;
+  logic                      initiator_clear_out;
+
+  always_comb begin
+    initiator_state_d              = initiator_state_q;
+    initiator_phase_transition_req = 1'b0;
+    initiator_isolate_out          = 1'b0;
+    initiator_clear_out            = 1'b0;
+    initiator_clear_seq_phase      = CLEAR_PHASE_IDLE;
+
+    case (initiator_state_q)
+      IDLE: begin
+        if (clear_i) begin
+          initiator_state_d = ISOLATE;
+        end
+      end
+
+      ISOLATE: begin
+        initiator_phase_transition_req = 1'b1;
+        initiator_clear_seq_phase      = CLEAR_PHASE_ISOLATE;
+        initiator_isolate_out          = 1'b1;
+        initiator_clear_out            = 1'b0;
+        if (initiator_phase_transition_ack && isolate_ack_i) begin
+          initiator_state_d = CLEAR;
+        end else if (initiator_phase_transition_ack) begin
+          initiator_state_d = WAIT_ISOLATE_ACK;
+        end else if (isolate_ack_i) begin
+          initiator_state_d = WAIT_ISOLATE_PHASE_ACK;
+        end
+      end
+
+      WAIT_ISOLATE_ACK: begin
+        initiator_isolate_out     = 1'b1;
+        initiator_clear_out       = 1'b0;
+        initiator_clear_seq_phase = CLEAR_PHASE_ISOLATE;
+        if (isolate_ack_i) begin
+          initiator_state_d = CLEAR;
+        end
+      end
+
+      WAIT_ISOLATE_PHASE_ACK: begin
+        initiator_phase_transition_req = 1'b1;
+        initiator_clear_seq_phase      = CLEAR_PHASE_ISOLATE;
+        initiator_isolate_out          = 1'b1;
+        initiator_clear_out            = 1'b0;
+        if (initiator_phase_transition_ack) begin
+          initiator_state_d = CLEAR;
+        end
+      end
+
+      CLEAR: begin
+        initiator_isolate_out          = 1'b1;
+        initiator_clear_out            = 1'b1;
+        initiator_phase_transition_req = 1'b1;
+        initiator_clear_seq_phase      = CLEAR_PHASE_CLEAR;
+        if (initiator_phase_transition_ack && clear_ack_i) begin
+          initiator_state_d = POST_CLEAR;
+        end else if (initiator_phase_transition_ack) begin
+          initiator_state_d = WAIT_CLEAR_ACK;
+        end else if (clear_ack_i) begin
+          initiator_state_d = WAIT_CLEAR_PHASE_ACK;
+        end
+      end
+
+      WAIT_CLEAR_ACK: begin
+        initiator_isolate_out     = 1'b1;
+        initiator_clear_out       = 1'b1;
+        initiator_clear_seq_phase = CLEAR_PHASE_CLEAR;
+        if (clear_ack_i) begin
+          initiator_state_d = POST_CLEAR;
+        end
+      end
+
+      WAIT_CLEAR_PHASE_ACK: begin
+        initiator_phase_transition_req = 1'b1;
+        initiator_clear_seq_phase      = CLEAR_PHASE_CLEAR;
+        initiator_isolate_out          = 1'b1;
+        initiator_clear_out            = 1'b1;
+        if (initiator_phase_transition_ack) begin
+          initiator_state_d = POST_CLEAR;
+        end
+      end
+
+      POST_CLEAR: begin
+        initiator_isolate_out          = 1'b1;
+        initiator_clear_out            = 1'b0;
+        initiator_phase_transition_req = 1'b1;
+        initiator_clear_seq_phase      = CLEAR_PHASE_POST_CLEAR;
+        if (initiator_phase_transition_ack) begin
+          initiator_state_d = FINISHED;
+        end
+      end
+
+      FINISHED: begin
+        initiator_isolate_out          = 1'b1;
+        initiator_clear_out            = 1'b0;
+        initiator_phase_transition_req = 1'b1;
+        initiator_clear_seq_phase      = CLEAR_PHASE_IDLE;
+        if (initiator_phase_transition_ack) begin
+          initiator_state_d = IDLE;
+        end
+      end
+
+      default: begin
+        initiator_state_d = ISOLATE;
+      end
+    endcase
+  end
+
+  always_ff @(posedge clk_i, negedge rst_ni) begin
+    if (!rst_ni) begin
+      if (CLEAR_ON_ASYNC_RESET) begin
+        initiator_state_q <= ISOLATE; // Start in the ISOLATE state which is
+                                        // the first state of a clear sequence.
+      end else begin
+        initiator_state_q <= IDLE;
+      end
+    end else begin
+      initiator_state_q <= initiator_state_d;
+    end
+  end
+
+  // Initiator CDC SRC
+  // We use 4 phase handshaking. That way it doesn't matter if one side is
+  // sudenly reset asynchronously. With a 2phase CDC, one-sided async resets might
+  // introduce spurios transactions.
+
+  cdc_4phase_src #(
+    .T(clear_seq_phase_e),
+    .SYNC_STAGES(2),
+    .DECOUPLED(0), // Important! The CDC must not be in decoupled mode.
+                   // Otherwise we will proceed to the next state without
+                   // waiting for the new state to arrive on the other side.
+    .SEND_RESET_MSG(CLEAR_ON_ASYNC_RESET), // Send the ISOLATE phase request immediately on async
+                                           // reset if async reset synchronization is enabled.
+    .RESET_MSG(CLEAR_PHASE_ISOLATE)
+  ) i_state_transition_cdc_src(
+    .clk_i,
+    .rst_ni,
+    .data_i(initiator_clear_seq_phase),
+    .valid_i(initiator_phase_transition_req),
+    .ready_o(initiator_phase_transition_ack),
+    .async_req_o,
+    .async_ack_i,
+    .async_data_o(async_next_phase_o)
+  );
+
+
+  //---------------------- Receiver Side ----------------------
+  // This part of the circuit receives clear sequence state transitions from the
+  // other side.
+
+  clear_seq_phase_e receiver_phase_q;
+  clear_seq_phase_e receiver_next_phase;
+  logic receiver_phase_req, receiver_phase_ack;
+
+  logic receiver_isolate_out;
+  logic receiver_clear_out;
+
+  cdc_4phase_dst #(
+    .T(clear_seq_phase_e),
+    .SYNC_STAGES(2),
+    .DECOUPLED(0) // Important! The CDC must not be in decoupled mode. Otherwise
+                  // we will proceed to the next state without waiting for the
+                  // new state to arrive on the other side.
+  ) i_state_transition_cdc_dst(
+    .clk_i,
+    .rst_ni,
+    .data_o(receiver_next_phase),
+    .valid_o(receiver_phase_req),
+    .ready_i(receiver_phase_ack),
+    .async_req_i,
+    .async_ack_o,
+    .async_data_i(async_next_phase_i)
+  );
+
+  always_ff @(posedge clk_i, negedge rst_ni) begin
+    if (!rst_ni) begin
+      receiver_phase_q <= CLEAR_PHASE_IDLE;
+    end else if (receiver_phase_req && receiver_phase_ack) begin
+      receiver_phase_q <= receiver_next_phase;
+    end
+  end
+
+  always_comb begin
+    receiver_isolate_out = 1'b0;
+    receiver_clear_out   = 1'b0;
+    receiver_phase_ack   = 1'b0;
+
+    // If there is a new phase requestd, checkout which one it is and act accordingly
+    if (receiver_phase_req) begin
+      case (receiver_next_phase)
+        CLEAR_PHASE_IDLE: begin
+          receiver_clear_out   = 1'b0;
+          receiver_isolate_out = 1'b0;
+          receiver_phase_ack   = 1'b1;
+        end
+
+        CLEAR_PHASE_ISOLATE: begin
+          receiver_clear_out   = 1'b0;
+          receiver_isolate_out = 1'b1;
+          // Wait for the isolate to be acknowledged before ack'ing the phase
+          receiver_phase_ack = isolate_ack_i;
+        end
+
+        CLEAR_PHASE_CLEAR: begin
+          receiver_clear_out   = 1'b1;
+          receiver_isolate_out = 1'b1;
+          // Wait for the clear to be acknowledged before ack'ing the phase
+          receiver_phase_ack   = clear_ack_i;
+        end
+
+        CLEAR_PHASE_POST_CLEAR: begin
+          receiver_clear_out   = 1'b0;
+          receiver_isolate_out = 1'b1;
+          receiver_phase_ack   = 1'b1;
+        end
+
+        default: begin
+          receiver_clear_out   = 1'b0;
+          receiver_isolate_out = 1'b0;
+          receiver_phase_ack   = 1'b0;
+        end
+      endcase
+
+    end else begin
+      // No phase change is requested for the moment. Act according to the
+      // current phase signal
+      case (receiver_phase_q)
+        CLEAR_PHASE_IDLE: begin
+          receiver_clear_out   = 1'b0;
+          receiver_isolate_out = 1'b0;
+        end
+
+        CLEAR_PHASE_ISOLATE: begin
+          receiver_clear_out   = 1'b0;
+          receiver_isolate_out = 1'b1;
+        end
+
+        CLEAR_PHASE_CLEAR: begin
+          receiver_clear_out   = 1'b1;
+          receiver_isolate_out = 1'b1;
+        end
+
+        CLEAR_PHASE_POST_CLEAR: begin
+          receiver_clear_out   = 1'b0;
+          receiver_isolate_out = 1'b1;
+        end
+
+        default: begin
+          receiver_clear_out   = 1'b0;
+          receiver_isolate_out = 1'b0;
+          receiver_phase_ack   = 1'b0;
+        end
+      endcase
+    end
+  end
+
+  // Output Assignment
+
+  // The clear and isolate signal are the OR combination of the receiver and
+  // initiator's clear/isolate signal. This ensures that the correct sequence is
+  // followed even if both sides are cleared independently at roughly the same
+  // time.
+  assign clear_o = initiator_clear_out || receiver_clear_out;
+  assign isolate_o = initiator_isolate_out || receiver_isolate_out;
+
+endmodule : cdc_reset_ctrlr_half
diff --git a/vendor/pulp-platform/common_cells/src/cdc_reset_ctrlr_pkg.sv b/vendor/pulp-platform/common_cells/src/cdc_reset_ctrlr_pkg.sv
new file mode 100644
index 0000000000000000000000000000000000000000..177f0a961f5257328a67903b2936db98de59874a
--- /dev/null
+++ b/vendor/pulp-platform/common_cells/src/cdc_reset_ctrlr_pkg.sv
@@ -0,0 +1,27 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2022 ETH Zurich, University of Bologna
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this 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.
+// SPDX-License-Identifier: SHL-0.51
+//-----------------------------------------------------------------------------
+//
+// Author: Manuel Eggimann <meggimann@iis.ee.ethz.ch>
+//
+// Contains common defintions for the CDC Clear Synchronization Circuitry
+
+package cdc_reset_ctrlr_pkg;
+
+typedef enum logic[1:0] {
+  CLEAR_PHASE_IDLE,
+  CLEAR_PHASE_ISOLATE,
+  CLEAR_PHASE_CLEAR,
+  CLEAR_PHASE_POST_CLEAR
+} clear_seq_phase_e;
+
+endpackage : cdc_reset_ctrlr_pkg