refactor(fpga): Replace tlgen xbar with Chisel-based KelvinXbar

This commit replaces the legacy `tlgen`-based crossbar with the new,
data-driven Chisel-based `KelvinXbar` in the FPGA design. This change
simplifies the build system, improves maintainability, and provides a
more flexible and robust interconnect.

Key changes:
- Removed the `tlgen` and `post_process_xbar.py` infrastructure from
  the FPGA build system.
- Instantiated the new `KelvinXbar` in `kelvin_soc.sv`, replacing the
  old crossbar and all associated width-sizers.
- Updated the clocking and reset logic to support the new crossbar's
  asynchronous domains, placing the Ibex core on its own clock.
- Removed the now-redundant Verilog implementations of the TileLink-UL
  primitives (FIFOs, sockets, width bridges).
- Added integrity generation to the `CoreTlul` module to ensure data
  integrity on the TileLink bus.
- Increased the FPGA clock frequency to 80MHz.

Change-Id: I340658419ca5cc93acee481c16334aeb026b2e7e
diff --git a/fpga/BUILD b/fpga/BUILD
index f221189..4d8dc81 100644
--- a/fpga/BUILD
+++ b/fpga/BUILD
@@ -16,57 +16,10 @@
 load("@lowrisc_opentitan_gh//rules:fusesoc.bzl", "fusesoc_build")
 load("//rules:kelvin_v2.bzl", "kelvin_v2_binary")
 load("//rules:utils.bzl", "cc_embed_data")
-load(":rules.bzl", "tlgen_rule")
 
 package(default_visibility = ["//visibility:public"])
 
-_CLOCK_FREQUENCY_MHZ = "10"
-
-# This is the tlgen.py script itself
-py_binary(
-    name = "tlgen_tool",
-    srcs = ["@lowrisc_opentitan_gh//util:tlgen.py"],
-    main = "@lowrisc_opentitan_gh//util:tlgen.py",
-    deps = [
-        "@kelvin_pip_deps_hjson//:pkg",
-        "@lowrisc_opentitan_gh//util/tlgen",
-    ],
-)
-
-tlgen_rule(
-    name = "tl_crossbar_generated",
-    topcfg = "tl_config.hjson",
-)
-
-py_binary(
-    name = "post_process_xbar",
-    srcs = ["post_process_xbar.py"],
-)
-
-genrule(
-    name = "tl_crossbar_processed",
-    srcs = [":tl_crossbar_generated"],
-    outs = [
-        "tl_crossbar_processed_out",
-    ],
-    cmd = "$(execpath :post_process_xbar) " +
-          "--input-dir $(location :tl_crossbar_generated) " +
-          "--output-dir $(location tl_crossbar_processed_out) " +
-          "--cores kelvinv2:ip:kelvin_tlul:0.1",
-    tools = [":post_process_xbar"],
-)
-
-filegroup(
-    name = "tl_crossbar",
-    srcs = [
-        ":tl_crossbar_processed_out",
-    ],
-)
-
-filegroup(
-    name = "tl_crossbar_core",
-    srcs = [":tl_crossbar"],
-)
+_CLOCK_FREQUENCY_MHZ = "80"
 
 filegroup(
     name = "rtl_files",
@@ -75,7 +28,7 @@
         "//fpga/ip/rv_core_ibex:rtl_files",
         "//fpga/ip/rvv_core_mini_tlul:rtl_files",
         "//fpga/ip/sram:rtl_files",
-        "//fpga/ip/tlul_width_bridge:rtl_files",
+        "//fpga/ip/xbar_kelvin_soc_chisel:rtl_files",
         "//fpga/rtl:rtl_files",
     ],
 )
@@ -144,10 +97,11 @@
 
 KELVIN_SOC_CORES = [
     "//fpga/ip/rv_core_ibex:rv_core_ibex.core",
+    "//fpga/ip/rvv_core_mini_tlul:rvv_core_mini_tlul.core",
+    "//fpga/ip/xbar_kelvin_soc_chisel:xbar_kelvin_soc_chisel.core",
     ":kelvin_soc.core",
     ":kelvin_soc_pkg.core",
     ":racl_pkg.core",
-    ":tl_crossbar_core",
     "@lowrisc_opentitan_gh//hw:check_tool_requirements.core",
 ]
 
@@ -202,8 +156,6 @@
 
 _PREFIX = "../../../../../../../../.."
 
-#          "../../../../../../../"bazel-out/k8-fastbuild-ST-be77d280135c/bin/fpga
-#          "../../../../../../../"bazel-out/k8-fastbuild-ST-be77d280135c/bin/fpga/wfi.vmem
 _IBEX_BOOT_ROM_VMEM = ":ibex_boot_rom.vmem"
 
 IBEX_BOOT_ROM_VMEM_PATH = "{}/$(location {})".format(_PREFIX, _IBEX_BOOT_ROM_VMEM)
@@ -221,15 +173,7 @@
         "--ClockFrequencyMhz=" + _CLOCK_FREQUENCY_MHZ,
     ],
     output_groups = {
-        # /home/atv/.cache/bazel/_bazel_atv/cb485e413f28624e05d5dee28237de6d/sandbox/
-        # linux-sandbox/34/execroot/kelvin_hw/bazel-out/k8-fastbuild/bin/fpga/
-        # build.build_chip_nexus_bitstream/
-        # com.google.kelvin_fpga_chip_nexus_0.1/synth-vivado/com.google.kelvin_fpga_chip_nexus_0.1.runs/impl_1/chip_nexus.bit
         "bitstream": ["com.google.kelvin_fpga_chip_nexus_0.1/synth-vivado/com.google.kelvin_fpga_chip_nexus_0.1.runs/impl_1/chip_nexus.bit"],
-        # /home/atv/.cache/bazel/_bazel_atv/cb485e413f28624e05d5dee28237de6d/sandbox/
-        # linux-sandbox/34/execroot/kelvin_hw/bazel-out/k8-fastbuild/bin/fpga/
-        # build.build_chip_nexus_bitstream/
-        # com.google.kelvin_fpga_chip_nexus_0.1/synth-vivado/com.google.kelvin_fpga_chip_nexus_0.1.runs/
         "logs": ["com.google.kelvin_fpga_chip_nexus_0.1/synth-vivado/com.google.kelvin_fpga_chip_nexus_0.1.runs/"],
     },
     systems = ["com.google.kelvin:fpga:chip_nexus:0.1"],
diff --git a/fpga/chip_nexus.core b/fpga/chip_nexus.core
index 912ddaf..4d930dd 100644
--- a/fpga/chip_nexus.core
+++ b/fpga/chip_nexus.core
@@ -25,7 +25,7 @@
   ClockFrequencyMhz:
     datatype: int
     description: "Target clock frequency in MHz."
-    default: 10
+    default: 80
     paramtype: vlogparam
   MemInitFile:
     datatype: str
diff --git a/fpga/chip_verilator.core b/fpga/chip_verilator.core
index 0971b5a..343866e 100644
--- a/fpga/chip_verilator.core
+++ b/fpga/chip_verilator.core
@@ -6,7 +6,6 @@
   files_rtl:
     depend:
       - com.google.kelvin:fpga:kelvin_soc:0.2
-      - kelvinv2:ip:sram:0.1
       - kelvinv2:ip:kelvin_tlul:0.1
       - lowrisc:dv_dpi_c:uartdpi:0.1
       - lowrisc:dv_dpi_sv:uartdpi:0.1
@@ -25,7 +24,7 @@
   ClockFrequencyMhz:
     datatype: int
     description: "Target clock frequency in MHz."
-    default: 10
+    default: 80
     paramtype: vlogparam
   MemInitFile:
     datatype: str
diff --git a/fpga/ip/kelvin_tlul/kelvin_tlul.core b/fpga/ip/kelvin_tlul/kelvin_tlul.core
index 37336d3..f189753 100644
--- a/fpga/ip/kelvin_tlul/kelvin_tlul.core
+++ b/fpga/ip/kelvin_tlul/kelvin_tlul.core
@@ -9,10 +9,6 @@
     files:
       - kelvin_tlul_pkg_128.sv
       - kelvin_tlul_pkg_32.sv
-      - tlul_fifo_async_128.sv
-      - tlul_fifo_sync_128.sv
-      - tlul_socket_1n_128.sv
-      - tlul_socket_m1_128.sv
     file_type: systemVerilogSource
 
 targets:
diff --git a/fpga/ip/kelvin_tlul/tlul_fifo_async_128.sv b/fpga/ip/kelvin_tlul/tlul_fifo_async_128.sv
deleted file mode 100644
index 22894bb..0000000
--- a/fpga/ip/kelvin_tlul/tlul_fifo_async_128.sv
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright lowRISC contributors (OpenTitan project).
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-//
-// TL-UL fifo, used to add elasticity or an asynchronous clock crossing
-// to an TL-UL bus.  This instantiates two FIFOs, one for the request side,
-// and one for the response side.
-
-`include "prim_assert.sv"
-
-module tlul_fifo_async_128
-    #(parameter int unsigned ReqDepth = 4,
-      parameter int unsigned RspDepth = 4)
-    (input clk_h_i,
-     input rst_h_ni,
-     input clk_d_i,
-     input rst_d_ni,
-     input kelvin_tlul_pkg_128::tl_h2d_t tl_h_i,
-     output kelvin_tlul_pkg_128::tl_d2h_t tl_h_o,
-     output kelvin_tlul_pkg_128::tl_h2d_t tl_d_o,
-     input kelvin_tlul_pkg_128::tl_d2h_t tl_d_i);
-
-  // Put everything on the request side into one FIFO
-  localparam int unsigned REQFIFO_WIDTH =
-                              $bits(kelvin_tlul_pkg_128::tl_h2d_t) - 2;
-
-  prim_fifo_async #(.Width(REQFIFO_WIDTH),
-                    .Depth(ReqDepth),
-                    .OutputZeroIfInvalid(1))
-      reqfifo(.clk_wr_i(clk_h_i),
-              .rst_wr_ni(rst_h_ni),
-              .clk_rd_i(clk_d_i),
-              .rst_rd_ni(rst_d_ni),
-              .wvalid_i(tl_h_i.a_valid),
-              .wready_o(tl_h_o.a_ready),
-              .wdata_i({tl_h_i.a_opcode, tl_h_i.a_param, tl_h_i.a_size,
-                        tl_h_i.a_source, tl_h_i.a_address, tl_h_i.a_mask,
-                        tl_h_i.a_data, tl_h_i.a_user}),
-              .rvalid_o(tl_d_o.a_valid),
-              .rready_i(tl_d_i.a_ready),
-              .rdata_o({tl_d_o.a_opcode, tl_d_o.a_param, tl_d_o.a_size,
-                        tl_d_o.a_source, tl_d_o.a_address, tl_d_o.a_mask,
-                        tl_d_o.a_data, tl_d_o.a_user}),
-              .wdepth_o(),
-              .rdepth_o());
-
-  // Put everything on the response side into the other FIFO
-
-  localparam int unsigned RSPFIFO_WIDTH =
-                              $bits(kelvin_tlul_pkg_128::tl_d2h_t) - 2;
-
-  prim_fifo_async #(.Width(RSPFIFO_WIDTH),
-                    .Depth(RspDepth),
-                    .OutputZeroIfInvalid(1))
-      rspfifo(.clk_wr_i(clk_d_i),
-              .rst_wr_ni(rst_d_ni),
-              .clk_rd_i(clk_h_i),
-              .rst_rd_ni(rst_h_ni),
-              .wvalid_i(tl_d_i.d_valid),
-              .wready_o(tl_d_o.d_ready),
-              .wdata_i({tl_d_i.d_opcode, tl_d_i.d_param, tl_d_i.d_size,
-                        tl_d_i.d_source, tl_d_i.d_sink, tl_d_i.d_data,
-                        tl_d_i.d_user, tl_d_i.d_error}),
-              .rvalid_o(tl_h_o.d_valid),
-              .rready_i(tl_h_i.d_ready),
-              .rdata_o({tl_h_o.d_opcode, tl_h_o.d_param, tl_h_o.d_size,
-                        tl_h_o.d_source, tl_h_o.d_sink, tl_h_o.d_data,
-                        tl_h_o.d_user, tl_h_o.d_error}),
-              .wdepth_o(),
-              .rdepth_o());
-endmodule
diff --git a/fpga/ip/kelvin_tlul/tlul_fifo_sync_128.sv b/fpga/ip/kelvin_tlul/tlul_fifo_sync_128.sv
deleted file mode 100644
index af404f1..0000000
--- a/fpga/ip/kelvin_tlul/tlul_fifo_sync_128.sv
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright lowRISC contributors (OpenTitan project).
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-//
-// TL-UL fifo, used to add elasticity or an asynchronous clock crossing
-// to an TL-UL bus.  This instantiates two FIFOs, one for the request side,
-// and one for the response side.
-
-module tlul_fifo_sync_128
-    #(parameter bit ReqPass = 1'b1,
-      parameter bit RspPass = 1'b1,
-      parameter int unsigned ReqDepth = 2,
-      parameter int unsigned RspDepth = 2,
-      parameter int unsigned SpareReqW = 1,
-      parameter int unsigned SpareRspW = 1)
-    (input clk_i,
-     input rst_ni,
-     input kelvin_tlul_pkg_128::tl_h2d_t tl_h_i,
-     output kelvin_tlul_pkg_128::tl_d2h_t tl_h_o,
-     output kelvin_tlul_pkg_128::tl_h2d_t tl_d_o,
-     input kelvin_tlul_pkg_128::tl_d2h_t tl_d_i,
-     input [SpareReqW - 1 : 0] spare_req_i,
-     output [SpareReqW - 1 : 0] spare_req_o,
-     input [SpareRspW - 1 : 0] spare_rsp_i,
-     output [SpareRspW - 1 : 0] spare_rsp_o);
-  import kelvin_tlul_pkg_128::*;
-  // Put everything on the request side into one FIFO
-  localparam int unsigned REQFIFO_WIDTH = $bits(kelvin_tlul_pkg_128::tl_h2d_t) -
-                                          2 + SpareReqW;
-
-  prim_fifo_sync #(.Width(REQFIFO_WIDTH),
-                   .Pass(ReqPass),
-                   .Depth(ReqDepth))
-      reqfifo(.clk_i,
-              .rst_ni,
-              .clr_i(1'b0),
-              .wvalid_i(tl_h_i.a_valid),
-              .wready_o(tl_h_o.a_ready),
-              .wdata_i({tl_h_i.a_opcode, tl_h_i.a_param, tl_h_i.a_size,
-                        tl_h_i.a_source, tl_h_i.a_address, tl_h_i.a_mask,
-                        tl_h_i.a_data, tl_h_i.a_user, spare_req_i}),
-              .rvalid_o(tl_d_o.a_valid),
-              .rready_i(tl_d_i.a_ready),
-              .rdata_o({tl_d_o.a_opcode, tl_d_o.a_param, tl_d_o.a_size,
-                        tl_d_o.a_source, tl_d_o.a_address, tl_d_o.a_mask,
-                        tl_d_o.a_data, tl_d_o.a_user, spare_req_o}),
-              .full_o(),
-              .depth_o(),
-              .err_o());
-
-  // Put everything on the response side into the other FIFO
-
-  localparam int unsigned RSPFIFO_WIDTH = $bits(kelvin_tlul_pkg_128::tl_d2h_t) -
-                                          2 + SpareRspW;
-
-  prim_fifo_sync #(.Width(RSPFIFO_WIDTH),
-                   .Pass(RspPass),
-                   .Depth(RspDepth))
-      rspfifo(.clk_i,
-              .rst_ni,
-              .clr_i(1'b0),
-              .wvalid_i(tl_d_i.d_valid),
-              .wready_o(tl_d_o.d_ready),
-              .wdata_i({tl_d_i.d_opcode, tl_d_i.d_param, tl_d_i.d_size,
-                        tl_d_i.d_source, tl_d_i.d_sink,
-                        (tl_d_i.d_opcode == tlul_pkg::AccessAckData)
-                            ? tl_d_i.d_data
-                            : {kelvin_tlul_pkg_128::TL_DW{1'b0}},
-                        tl_d_i.d_user, tl_d_i.d_error, spare_rsp_i}),
-              .rvalid_o(tl_h_o.d_valid),
-              .rready_i(tl_h_i.d_ready),
-              .rdata_o({tl_h_o.d_opcode, tl_h_o.d_param, tl_h_o.d_size,
-                        tl_h_o.d_source, tl_h_o.d_sink, tl_h_o.d_data,
-                        tl_h_o.d_user, tl_h_o.d_error, spare_rsp_o}),
-              .full_o(),
-              .depth_o(),
-              .err_o());
-endmodule
diff --git a/fpga/ip/kelvin_tlul/tlul_socket_1n_128.sv b/fpga/ip/kelvin_tlul/tlul_socket_1n_128.sv
deleted file mode 100644
index 2b333f0..0000000
--- a/fpga/ip/kelvin_tlul/tlul_socket_1n_128.sv
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright lowRISC contributors (OpenTitan project).
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-//
-// TL-UL socket 1:N module
-//
-// configuration settings
-//   device_count: 4
-//
-// Verilog parameters
-//   HReqPass:      if 1 then host requests can pass through on empty fifo,
-//                  default 1
-//   HRspPass:      if 1 then host responses can pass through on empty fifo,
-//                  default 1
-//   DReqPass:      (one per device_count) if 1 then device i requests can
-//                  pass through on empty fifo, default 1
-//   DRspPass:      (one per device_count) if 1 then device i responses can
-//                  pass through on empty fifo, default 1
-//   HReqDepth:     Depth of host request FIFO, default 2
-//   HRspDepth:     Depth of host response FIFO, default 2
-//   DReqDepth:     (one per device_count) Depth of device i request FIFO,
-//                  default 2
-//   DRspDepth:     (one per device_count) Depth of device i response FIFO,
-//                  default 2
-//   ExplicitErrs:  This module always returns a request error if dev_select_i
-//                  is greater than N-1. If ExplicitErrs is set then the width
-//                  of the dev_select_i signal will be chosen to make sure that
-//                  this is possible. This only makes a difference if N is a
-//                  power of 2.
-//
-// Requests must stall to one device until all responses from other devices
-// have returned.  Need to keep a counter of all outstanding requests and
-// wait until that counter is zero before switching devices.
-//
-// This module will return a request error if the input value of 'dev_select_i'
-// is not within the range 0..N-1. Thus the instantiator of the socket
-// can indicate error by any illegal value of dev_select_i. 4'b1111 is
-// recommended for visibility
-//
-// The maximum value of N is 63
-
-`include "prim_assert.sv"
-
-module tlul_socket_1n_128
-    #(parameter int unsigned N = 4,
-      parameter bit HReqPass = 1'b1,
-      parameter bit HRspPass = 1'b1,
-      parameter bit [N - 1 : 0] DReqPass = {N{1'b1}},
-      parameter bit [N - 1 : 0] DRspPass = {N{1'b1}},
-      parameter bit [3 : 0] HReqDepth = 4'h1,
-      parameter bit [3 : 0] HRspDepth = 4'h1,
-      parameter bit [N * 4 - 1 : 0] DReqDepth = {N{4'h1}},
-      parameter bit [N * 4 - 1 : 0] DRspDepth = {N{4'h1}},
-      parameter bit ExplicitErrs = 1'b1,
-
-      // The width of dev_select_i. We must be able to select any of the N
-      // devices (i.e. values 0..N-1). If ExplicitErrs is set, we also need to
-      // be able to represent N.
-      localparam int unsigned NWD = $clog2(ExplicitErrs ? N + 1 : N))
-    (input clk_i,
-     input rst_ni,
-     input kelvin_tlul_pkg_128::tl_h2d_t tl_h_i,
-     output kelvin_tlul_pkg_128::tl_d2h_t tl_h_o,
-     output kelvin_tlul_pkg_128::tl_h2d_t tl_d_o[N],
-     input kelvin_tlul_pkg_128::tl_d2h_t tl_d_i[N],
-     input [NWD - 1 : 0] dev_select_i);
-
-  `ASSERT_INIT(maxN, N < 64)
-
-  // Since our steering is done after potential FIFOing, we need to
-  // shove our device select bits into spare bits of reqfifo
-
-  // instantiate the host fifo, create intermediate bus 't'
-
-  // FIFO'd version of device select
-  logic [NWD - 1 : 0] dev_select_t;
-
-  kelvin_tlul_pkg_128::tl_h2d_t tl_t_o;
-  kelvin_tlul_pkg_128::tl_d2h_t tl_t_i;
-
-  tlul_fifo_sync_128 #(.ReqPass(HReqPass),
-                       .RspPass(HRspPass),
-                       .ReqDepth(HReqDepth),
-                       .RspDepth(HRspDepth),
-                       .SpareReqW(NWD))
-      fifo_h(.clk_i,
-             .rst_ni,
-             .tl_h_i,
-             .tl_h_o,
-             .tl_d_o(tl_t_o),
-             .tl_d_i(tl_t_i),
-             .spare_req_i(dev_select_i),
-             .spare_req_o(dev_select_t),
-             .spare_rsp_i(1'b0),
-             .spare_rsp_o());
-
-  // We need to keep track of how many requests are outstanding,
-  // and to which device. New requests are compared to this and
-  // stall until that number is zero.
-  localparam int MaxOutstanding =
-                     2 ** top_pkg::TL_AIW;  // Up to 256 outstanding
-  localparam int OutstandingW = $clog2(MaxOutstanding + 1);
-  logic [OutstandingW - 1 : 0] num_req_outstanding;
-  logic [NWD - 1 : 0] dev_select_outstanding;
-  logic hold_all_requests;
-  logic accept_t_req, accept_t_rsp;
-
-  assign accept_t_req = tl_t_o.a_valid & tl_t_i.a_ready;
-  assign accept_t_rsp = tl_t_i.d_valid & tl_t_o.d_ready;
-
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      num_req_outstanding <= '0;
-      dev_select_outstanding <= '0;
-    end else if (accept_t_req) begin
-      if (!accept_t_rsp) begin
-        num_req_outstanding <= num_req_outstanding + 1'b1;
-      end
-      dev_select_outstanding <= dev_select_t;
-    end else if (accept_t_rsp) begin
-      num_req_outstanding <= num_req_outstanding - 1'b1;
-    end
-  end
-
-  `ASSERT(NotOverflowed_A, accept_t_req && !accept_t_rsp ->
-          num_req_outstanding <= MaxOutstanding)
-
-  assign hold_all_requests = (num_req_outstanding != '0) &
-                             (dev_select_t != dev_select_outstanding);
-
-  // Make N copies of 't' request side with modified reqvalid, call
-  // them 'u[0]' .. 'u[n-1]'.
-
-  kelvin_tlul_pkg_128::tl_h2d_t tl_u_o[N + 1];
-  kelvin_tlul_pkg_128::tl_d2h_t tl_u_i[N + 1];
-
-  // ensure that when a device is not selected, both command
-  // data integrity can never match
-  kelvin_tlul_pkg_128::tl_a_user_t blanked_auser;
-  assign blanked_auser = '{
-    rsvd: tl_t_o.a_user.rsvd,
-    instr_type: tl_t_o.a_user.instr_type,
-    cmd_intg: kelvin_tlul_pkg_128::get_bad_cmd_intg(tl_t_o),
-    data_intg: kelvin_tlul_pkg_128::get_bad_data_intg(
-        kelvin_tlul_pkg_128::BlankedAData)
-  };
-
-  // if a host is not selected, or if requests are held off, blank the bus
-  for (genvar i = 0; i < N; i++) begin : gen_u_o
-    logic dev_select;
-    assign dev_select = dev_select_t == NWD'(i) & ~hold_all_requests;
-
-    assign tl_u_o[i].a_valid = tl_t_o.a_valid & dev_select;
-    assign tl_u_o[i].a_opcode = tl_t_o.a_opcode;
-    assign tl_u_o[i].a_param = tl_t_o.a_param;
-    assign tl_u_o[i].a_size = tl_t_o.a_size;
-    assign tl_u_o[i].a_source = tl_t_o.a_source;
-    assign tl_u_o[i].a_address = tl_t_o.a_address;
-    assign tl_u_o[i].a_mask = tl_t_o.a_mask;
-    assign tl_u_o[i].a_data =
-               dev_select ? tl_t_o.a_data : kelvin_tlul_pkg_128::BlankedAData;
-    assign tl_u_o[i].a_user = dev_select ? tl_t_o.a_user : blanked_auser;
-
-    assign tl_u_o[i].d_ready = tl_t_o.d_ready;
-  end
-
-  kelvin_tlul_pkg_128::tl_d2h_t tl_t_p;
-
-  // for the returning reqready, only look at the device we're addressing
-  logic hfifo_reqready;
-  always_comb begin
-    hfifo_reqready = tl_u_i[N].a_ready;  // default to error
-    for (int idx = 0; idx < N; idx++) begin
-      // if (dev_select_outstanding == NWD'(idx)) hfifo_reqready =
-      // tl_u_i[idx].a_ready;
-      if (dev_select_t == NWD'(idx)) hfifo_reqready = tl_u_i[idx].a_ready;
-    end
-    if (hold_all_requests) hfifo_reqready = 1'b0;
-  end
-  // Adding a_valid as a qualifier. This prevents the a_ready from having
-  // unknown value when the address is unknown and the Host TL-UL FIFO is bypass
-  // mode.
-  assign tl_t_i.a_ready = tl_t_o.a_valid & hfifo_reqready;
-
-  always_comb begin
-    tl_t_p = tl_u_i[N];
-    for (int idx = 0; idx < N; idx++) begin
-      if (dev_select_outstanding == NWD'(idx)) tl_t_p = tl_u_i[idx];
-    end
-  end
-  assign tl_t_i.d_valid = tl_t_p.d_valid;
-  assign tl_t_i.d_opcode = tl_t_p.d_opcode;
-  assign tl_t_i.d_param = tl_t_p.d_param;
-  assign tl_t_i.d_size = tl_t_p.d_size;
-  assign tl_t_i.d_source = tl_t_p.d_source;
-  assign tl_t_i.d_sink = tl_t_p.d_sink;
-  assign tl_t_i.d_data = tl_t_p.d_data;
-  assign tl_t_i.d_user = tl_t_p.d_user;
-  assign tl_t_i.d_error = tl_t_p.d_error;
-
-  // Instantiate all the device FIFOs
-  for (genvar i = 0; i < N; i++) begin : gen_dfifo
-    tlul_fifo_sync_128 #(.ReqPass(DReqPass[i]),
-                         .RspPass(DRspPass[i]),
-                         .ReqDepth(DReqDepth[i * 4 +: 4]),
-                         .RspDepth(DRspDepth[i * 4 +: 4]))
-        fifo_d(.clk_i,
-               .rst_ni,
-               .tl_h_i(tl_u_o[i]),
-               .tl_h_o(tl_u_i[i]),
-               .tl_d_o(tl_d_o[i]),
-               .tl_d_i(tl_d_i[i]),
-               .spare_req_i(1'b0),
-               .spare_req_o(),
-               .spare_rsp_i(1'b0),
-               .spare_rsp_o());
-  end
-
-  // Instantiate the error responder. It's only needed if a value greater than
-  // N-1 is actually representable in NWD bits.
-  if ($clog2(N + 1) <= NWD) begin : gen_err_resp
-    assign tl_u_o[N].d_ready = tl_t_o.d_ready;
-    assign tl_u_o[N].a_valid =
-               tl_t_o.a_valid & (dev_select_t >= NWD'(N)) & ~hold_all_requests;
-    assign tl_u_o[N].a_opcode = tl_t_o.a_opcode;
-    assign tl_u_o[N].a_param = tl_t_o.a_param;
-    assign tl_u_o[N].a_size = tl_t_o.a_size;
-    assign tl_u_o[N].a_source = tl_t_o.a_source;
-    assign tl_u_o[N].a_address = tl_t_o.a_address;
-    assign tl_u_o[N].a_mask = tl_t_o.a_mask;
-    assign tl_u_o[N].a_data = tl_t_o.a_data;
-    assign tl_u_o[N].a_user = tl_t_o.a_user;
-    tlul_err_resp err_resp(.clk_i,
-                           .rst_ni,
-                           .tl_h_i(tl_u_o[N]),
-                           .tl_h_o(tl_u_i[N]));
-  end else begin : gen_no_err_resp  // block: gen_err_resp
-    assign tl_u_o[N] = '0;
-    assign tl_u_i[N] = '0;
-    logic unused_sig;
-    assign unused_sig = ^tl_u_o[N];
-  end
-endmodule
diff --git a/fpga/ip/kelvin_tlul/tlul_socket_m1_128.sv b/fpga/ip/kelvin_tlul/tlul_socket_m1_128.sv
deleted file mode 100644
index cded907..0000000
--- a/fpga/ip/kelvin_tlul/tlul_socket_m1_128.sv
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright lowRISC contributors (OpenTitan project).
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-//
-// TL-UL socket M:1 module
-//
-// Verilog parameters
-//   M:             Number of host ports.
-//   HReqPass:      M bit array to allow requests to pass through the host i
-//                  FIFO with no clock delay if the request FIFO is empty. If
-//                  1'b0, at least one clock cycle of latency is created.
-//                  Default is 1'b1.
-//   HRspPass:      Same as HReqPass but for host response FIFO.
-//   HReqDepth:     Mx4 bit array. bit[i*4+:4] is depth of host i request FIFO.
-//                  Depth of zero is allowed if ReqPass is true. A maximum value
-//                  of 16 is allowed, default is 2.
-//   HRspDepth:     Same as HReqDepth but for host response FIFO.
-//   DReqPass:      Same as HReqPass but for device request FIFO.
-//   DRspPass:      Same as HReqPass but for device response FIFO.
-//   DReqDepth:     Same as HReqDepth but for device request FIFO.
-//   DRspDepth:     Same as HReqDepth but for device response FIFO.
-
-`include "prim_assert.sv"
-
-module tlul_socket_m1_128
-    #(parameter int unsigned M = 4,
-      parameter bit [M - 1 : 0] HReqPass = {M{1'b1}},
-      parameter bit [M - 1 : 0] HRspPass = {M{1'b1}},
-      parameter bit [M * 4 - 1 : 0] HReqDepth = {M{4'h1}},
-      parameter bit [M * 4 - 1 : 0] HRspDepth = {M{4'h1}},
-      parameter bit DReqPass = 1'b1,
-      parameter bit DRspPass = 1'b1,
-      parameter bit [3 : 0] DReqDepth = 4'h1,
-      parameter bit [3 : 0] DRspDepth = 4'h1)
-    (input clk_i,
-     input rst_ni,
-
-     input kelvin_tlul_pkg_128::tl_h2d_t tl_h_i[M],
-     output kelvin_tlul_pkg_128::tl_d2h_t tl_h_o[M],
-
-     output kelvin_tlul_pkg_128::tl_h2d_t tl_d_o,
-     input kelvin_tlul_pkg_128::tl_d2h_t tl_d_i);
-
-  `ASSERT_INIT(maxM, M < 16)
-
-  // Signals
-  //
-  //  tl_h_i/o[0] |  tl_h_i/o[1] | ... |  tl_h_i/o[M-1]
-  //      |              |                    |
-  // u_hostfifo[0]  u_hostfifo[1]        u_hostfifo[M-1]
-  //      |              |                    |
-  //       hreq_fifo_o(i) / hrsp_fifo_i(i)
-  //     ---------------------------------------
-  //     |       request/grant/req_data        |
-  //     |                                     |
-  //     |           PRIM_ARBITER              |
-  //     |                                     |
-  //     |  arb_valid / arb_ready / arb_data   |
-  //     ---------------------------------------
-  //                     |
-  //                dreq_fifo_i / drsp_fifo_o
-  //                     |
-  //                u_devicefifo
-  //                     |
-  //                  tl_d_o/i
-  //
-  // Required ID width to distinguish between host ports
-  //  Used in response steering
-  localparam int unsigned IDW = top_pkg::TL_AIW;
-  localparam int unsigned STIDW = $clog2(M);
-
-  kelvin_tlul_pkg_128::tl_h2d_t hreq_fifo_o[M];
-  kelvin_tlul_pkg_128::tl_d2h_t hrsp_fifo_i[M];
-
-  logic [M - 1 : 0] hrequest;
-  logic [M - 1 : 0] hgrant;
-
-  kelvin_tlul_pkg_128::tl_h2d_t dreq_fifo_i;
-  kelvin_tlul_pkg_128::tl_d2h_t drsp_fifo_o;
-
-  logic arb_valid;
-  logic arb_ready;
-  kelvin_tlul_pkg_128::tl_h2d_t arb_data;
-
-  // Host Req/Rsp FIFO
-  for (genvar i = 0; i < M; i++) begin : gen_host_fifo
-    kelvin_tlul_pkg_128::tl_h2d_t hreq_fifo_i;
-
-    // ID Shifting
-    logic [STIDW - 1 : 0] reqid_sub;
-    logic [IDW - 1 : 0] shifted_id;
-    assign reqid_sub = i;  // can cause conversion error?
-    assign shifted_id = {tl_h_i[i].a_source[0 +: (IDW - STIDW)], reqid_sub};
-
-    `ASSERT(idInRange, tl_h_i[i].a_valid |->
-            tl_h_i[i].a_source[IDW - 1 -: STIDW] == '0)
-
-    // assign not connected bits to nc_* signal to make lint happy
-    logic [IDW - 1 : IDW - STIDW] unused_tl_h_source;
-    assign unused_tl_h_source = tl_h_i[i].a_source[IDW - 1 -: STIDW];
-
-    // Put shifted ID
-    assign hreq_fifo_i = '{
-      a_valid: tl_h_i[i].a_valid,
-      a_opcode: tl_h_i[i].a_opcode,
-      a_param: tl_h_i[i].a_param,
-      a_size: tl_h_i[i].a_size,
-      a_source: shifted_id,
-      a_address: tl_h_i[i].a_address,
-      a_mask: tl_h_i[i].a_mask,
-      a_data: tl_h_i[i].a_data,
-      a_user: tl_h_i[i].a_user,
-      d_ready: tl_h_i[i].d_ready
-    };
-
-    tlul_fifo_sync_128 #(.ReqPass(HReqPass[i]),
-                         .RspPass(HRspPass[i]),
-                         .ReqDepth(HReqDepth[i * 4 +: 4]),
-                         .RspDepth(HRspDepth[i * 4 +: 4]),
-                         .SpareReqW(1))
-        u_hostfifo(.clk_i,
-                   .rst_ni,
-                   .tl_h_i(hreq_fifo_i),
-                   .tl_h_o(tl_h_o[i]),
-                   .tl_d_o(hreq_fifo_o[i]),
-                   .tl_d_i(hrsp_fifo_i[i]),
-                   .spare_req_i(1'b0),
-                   .spare_req_o(),
-                   .spare_rsp_i(1'b0),
-                   .spare_rsp_o());
-  end
-
-  // Device Req/Rsp FIFO
-  tlul_fifo_sync_128 #(.ReqPass(DReqPass),
-                       .RspPass(DRspPass),
-                       .ReqDepth(DReqDepth),
-                       .RspDepth(DRspDepth),
-                       .SpareReqW(1))
-      u_devicefifo(.clk_i,
-                   .rst_ni,
-                   .tl_h_i(dreq_fifo_i),
-                   .tl_h_o(drsp_fifo_o),
-                   .tl_d_o(tl_d_o),
-                   .tl_d_i(tl_d_i),
-                   .spare_req_i(1'b0),
-                   .spare_req_o(),
-                   .spare_rsp_i(1'b0),
-                   .spare_rsp_o());
-
-  // Request Arbiter
-  for (genvar i = 0; i < M; i++) begin : gen_arbreqgnt
-    assign hrequest[i] = hreq_fifo_o[i].a_valid;
-  end
-
-  assign arb_ready = drsp_fifo_o.a_ready;
-
-  if (kelvin_tlul_pkg_128::ArbiterImpl == "PPC") begin : gen_arb_ppc
-    prim_arbiter_ppc #(.N(M),
-                       .DW($bits(kelvin_tlul_pkg_128::tl_h2d_t)))
-        u_reqarb(.clk_i,
-                 .rst_ni,
-                 .req_chk_i(1'b0),
-                 // TL-UL allows dropping valid without ready. See #3354.
-                 .req_i(hrequest),
-                 .data_i(hreq_fifo_o),
-                 .gnt_o(hgrant),
-                 .idx_o(),
-                 .valid_o(arb_valid),
-                 .data_o(arb_data),
-                 .ready_i(arb_ready));
-  end else if (kelvin_tlul_pkg_128::ArbiterImpl == "BINTREE")
-  begin : gen_tree_arb
-    prim_arbiter_tree #(.N(M),
-                        .DW($bits(kelvin_tlul_pkg_128::tl_h2d_t)))
-        u_reqarb(.clk_i,
-                 .rst_ni,
-                 .req_chk_i(1'b0),
-                 // TL-UL allows dropping valid without ready. See #3354.
-                 .req_i(hrequest),
-                 .data_i(hreq_fifo_o),
-                 .gnt_o(hgrant),
-                 .idx_o(),
-                 .valid_o(arb_valid),
-                 .data_o(arb_data),
-                 .ready_i(arb_ready));
-  end else begin : gen_unknown
-    `ASSERT_INIT(UnknownArbImpl_A, 0)
-  end
-
-  logic [M - 1 : 0] hfifo_rspvalid;
-  logic [M - 1 : 0] dfifo_rspready;
-  logic [IDW - 1 : 0] hfifo_rspid;
-  logic dfifo_rspready_merged;
-
-  // arb_data --> dreq_fifo_i
-  //   dreq_fifo_i.hd_rspready <= dfifo_rspready
-
-  assign dfifo_rspready_merged = |dfifo_rspready;
-  assign dreq_fifo_i = '{
-    a_valid: arb_valid,
-    a_opcode: arb_data.a_opcode,
-    a_param: arb_data.a_param,
-    a_size: arb_data.a_size,
-    a_source: arb_data.a_source,
-    a_address: arb_data.a_address,
-    a_mask: arb_data.a_mask,
-    a_data: arb_data.a_data,
-    a_user: arb_data.a_user,
-
-    d_ready: dfifo_rspready_merged
-  };
-
-  // Response ID steering
-  // drsp_fifo_o --> hrsp_fifo_i[i]
-
-  // Response ID shifting before put into host fifo
-  assign hfifo_rspid = {{STIDW{1'b0}}, drsp_fifo_o.d_source[IDW - 1 : STIDW]};
-  for (genvar i = 0; i < M; i++) begin : gen_idrouting
-    assign hfifo_rspvalid[i] =
-               drsp_fifo_o.d_valid & (drsp_fifo_o.d_source[0 +: STIDW] == i);
-    assign dfifo_rspready[i] = hreq_fifo_o[i].d_ready &
-                               (drsp_fifo_o.d_source[0 +: STIDW] == i) &
-                               drsp_fifo_o.d_valid;
-
-    assign hrsp_fifo_i[i] = '{
-      d_valid: hfifo_rspvalid[i],
-      d_opcode: drsp_fifo_o.d_opcode,
-      d_param: drsp_fifo_o.d_param,
-      d_size: drsp_fifo_o.d_size,
-      d_source: hfifo_rspid,
-      d_sink: drsp_fifo_o.d_sink,
-      d_data: drsp_fifo_o.d_data,
-      d_user: drsp_fifo_o.d_user,
-      d_error: drsp_fifo_o.d_error,
-      a_ready: hgrant[i]
-    };
-  end
-
-  // this assertion fails when rspid[0+:STIDW] not in [0..M-1]
-  `ASSERT(rspIdInRange, drsp_fifo_o.d_valid |->
-          drsp_fifo_o.d_source[0 +: STIDW] >= 0 &&
-              drsp_fifo_o.d_source[0 +: STIDW] < M)
-endmodule
diff --git a/fpga/ip/tlul_width_bridge/tlul_device_downsizer.core b/fpga/ip/tlul_width_bridge/tlul_device_downsizer.core
deleted file mode 100644
index 5cc6203..0000000
--- a/fpga/ip/tlul_width_bridge/tlul_device_downsizer.core
+++ /dev/null
@@ -1,32 +0,0 @@
-CAPI=2:
-# Copyright 2025 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-name: "kelvinv2:ip:tlul_device_downsizer"
-description: "TL-UL Device Downsizer"
-
-filesets:
-  files_rtl:
-    depend:
-      - "lowrisc:prim:all"
-      - "lowrisc:tlul:headers"
-      - "kelvinv2:ip:kelvin_tlul:0.1"
-    files:
-      - tlul_device_downsizer.sv: { file_type: systemVerilogSource }
-    file_type: systemVerilogSource
-
-targets:
-  default:
-    filesets:
-      - files_rtl
diff --git a/fpga/ip/tlul_width_bridge/tlul_device_downsizer.sv b/fpga/ip/tlul_width_bridge/tlul_device_downsizer.sv
deleted file mode 100644
index 524fb6b..0000000
--- a/fpga/ip/tlul_width_bridge/tlul_device_downsizer.sv
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2025 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-`include "prim_assert.sv"
-
-module tlul_device_downsizer
-    #(parameter int AddrWidth = 32)
-    (input clk_i,
-     input rst_ni,
-
-     // Slave (Upsizer-facing) TL-UL Interface
-     input kelvin_tlul_pkg_128::tl_h2d_t s_tl_i,
-     output kelvin_tlul_pkg_128::tl_d2h_t s_tl_o,
-
-     // Master (Crossbar-facing) TL-UL Interface
-     output kelvin_tlul_pkg_32::tl_h2d_t m_tl_o,
-     input kelvin_tlul_pkg_32::tl_d2h_t m_tl_i);
-
-  localparam int SlaveDataWidth = 128;
-  localparam int MasterDataWidth = 32;
-  localparam int LaneWidth = MasterDataWidth / 8;
-  localparam int NumLanes = SlaveDataWidth / MasterDataWidth;
-  localparam int LaneIndexWidth = $clog2(NumLanes);
-
-  // Response path skid buffer
-  kelvin_tlul_pkg_128::tl_d2h_t d_skid_reg;
-  logic d_skid_valid_q, d_skid_valid_d;
-  logic d_skid_ready;
-
-  // Internal signals
-  logic [LaneIndexWidth - 1 : 0] lane_idx;
-  logic [LaneIndexWidth - 1 : 0] lane_idx_reg;
-  logic [MasterDataWidth - 1 : 0] m_a_data;
-  logic [MasterDataWidth / 8 - 1 : 0] m_a_mask;
-  logic [1 : 0] a_size_from_mask;
-
-  // Lane index calculation from mask
-  always_comb begin
-    // Priority encode the mask to find the active lane
-    unique case (1'b1)
-      |s_tl_i.a_mask[3 : 0]:
-        lane_idx = 2'b00;
-      |s_tl_i.a_mask[7 : 4]:
-        lane_idx = 2'b01;
-      |s_tl_i.a_mask[11 : 8]:
-        lane_idx = 2'b10;
-      |s_tl_i.a_mask[15 : 12]:
-        lane_idx = 2'b11;
-      default:
-        lane_idx = 2'b00;  // Should not happen for valid requests
-    endcase
-  end
-
-  // Master port data and mask generation
-  always_comb begin
-    m_a_data = s_tl_i.a_data >> (lane_idx * MasterDataWidth);
-    m_a_mask = s_tl_i.a_mask >> (lane_idx * LaneWidth);
-  end
-
-  // Calculate master port a_size from mask
-  always_comb begin
-    case ($countones(m_a_mask))
-      1:
-        a_size_from_mask = 2'h0;
-      2:
-        a_size_from_mask = 2'h1;
-      3, 4:
-        a_size_from_mask = 2'h2;
-      default:
-        a_size_from_mask = 2'h0;
-    endcase
-  end
-
-  logic [15 : 0] dbg_s_tl_i_a_size = s_tl_i.a_size;
-  // Master port connections
-  assign m_tl_o.a_valid = s_tl_i.a_valid;
-  assign m_tl_o.a_opcode = s_tl_i.a_opcode;
-  assign m_tl_o.a_param = s_tl_i.a_param;
-  assign m_tl_o.a_size =
-             (s_tl_i.a_opcode == tlul_pkg::Get) ? 2 : a_size_from_mask;
-  assign m_tl_o.a_address = {s_tl_i.a_address[AddrWidth - 1 : 4], lane_idx,
-                             2'b00};
-  assign m_tl_o.a_source = s_tl_i.a_source;
-  assign m_tl_o.a_data = m_a_data;
-  assign m_tl_o.a_mask = m_a_mask;
-  assign m_tl_o.a_user = s_tl_i.a_user;
-  assign m_tl_o.d_ready = d_skid_ready;
-
-  // Slave port connections
-  assign s_tl_o.d_opcode = d_skid_reg.d_opcode;
-  assign s_tl_o.d_param = d_skid_reg.d_param;
-  assign s_tl_o.d_sink = d_skid_reg.d_sink;
-  assign s_tl_o.d_source = d_skid_reg.d_source;
-  assign s_tl_o.d_data = d_skid_reg.d_data;
-  assign s_tl_o.d_error = d_skid_reg.d_error;
-  assign s_tl_o.d_user = d_skid_reg.d_user;
-  assign s_tl_o.d_size = d_skid_reg.d_size;
-  assign s_tl_o.d_valid = d_skid_valid_q;
-  assign s_tl_o.a_ready = m_tl_i.a_ready;
-  logic d_skid_reg_size = d_skid_reg.d_size;
-
-  // Skid buffer logic
-  assign d_skid_ready = !d_skid_valid_q || s_tl_i.d_ready;
-
-  always_comb begin
-    d_skid_valid_d = d_skid_valid_q;
-    if (d_skid_ready) begin
-      d_skid_valid_d = m_tl_i.d_valid;
-    end
-  end
-
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      d_skid_valid_q <= 1'b0;
-      d_skid_reg <= '0;
-      lane_idx_reg <= '0;
-    end else begin
-      d_skid_valid_q <= d_skid_valid_d;
-      if (d_skid_ready && m_tl_i.d_valid) begin
-        d_skid_reg.d_opcode <= m_tl_i.d_opcode;
-        d_skid_reg.d_param <= m_tl_i.d_param;
-        d_skid_reg.d_sink <= m_tl_i.d_sink;
-        d_skid_reg.d_source <= m_tl_i.d_source;
-        d_skid_reg.d_data <= m_tl_i.d_data << (lane_idx_reg * MasterDataWidth);
-        d_skid_reg.d_error <= m_tl_i.d_error;
-        d_skid_reg.d_user <= m_tl_i.d_user;
-        d_skid_reg.d_size <= m_tl_i.d_size;
-      end
-      if (s_tl_i.a_valid && s_tl_o.a_ready) begin
-        lane_idx_reg <= lane_idx;
-      end
-    end
-  end
-endmodule
diff --git a/fpga/ip/tlul_width_bridge/tlul_host_upsizer.core b/fpga/ip/tlul_width_bridge/tlul_host_upsizer.core
deleted file mode 100644
index 3c25112..0000000
--- a/fpga/ip/tlul_width_bridge/tlul_host_upsizer.core
+++ /dev/null
@@ -1,32 +0,0 @@
-CAPI=2:
-# Copyright 2025 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-name: "kelvinv2:ip:tlul_host_upsizer"
-description: "TL-UL Host Upsizer"
-
-filesets:
-  files_rtl:
-    depend:
-      - "lowrisc:prim:all"
-      - "lowrisc:tlul:headers"
-      - "kelvinv2:ip:kelvin_tlul:0.1"
-    files:
-      - tlul_host_upsizer.sv: { file_type: systemVerilogSource }
-    file_type: systemVerilogSource
-
-targets:
-  default:
-    filesets:
-      - files_rtl
diff --git a/fpga/ip/tlul_width_bridge/tlul_host_upsizer.sv b/fpga/ip/tlul_width_bridge/tlul_host_upsizer.sv
deleted file mode 100644
index 6958dfd..0000000
--- a/fpga/ip/tlul_width_bridge/tlul_host_upsizer.sv
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2025 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-`include "prim_assert.sv"
-
-module tlul_host_upsizer
-    #(parameter int AddrWidth = 32)
-    (input clk_i,
-     input rst_ni,
-
-     // Slave (Host-facing) TL-UL Interface
-     input kelvin_tlul_pkg_32::tl_h2d_t s_tl_i,
-     output kelvin_tlul_pkg_32::tl_d2h_t s_tl_o,
-
-     // Master (Crossbar-facing) TL-UL Interface
-     output kelvin_tlul_pkg_128::tl_h2d_t m_tl_o,
-     input kelvin_tlul_pkg_128::tl_d2h_t m_tl_i);
-
-  localparam int SlaveDataWidth = 32;
-  localparam int MasterDataWidth = 128;
-  localparam int LaneWidth = SlaveDataWidth / 8;
-  localparam int NumLanes = MasterDataWidth / SlaveDataWidth;
-  localparam int LaneIndexWidth = $clog2(NumLanes);
-
-  // Response path skid buffer
-  kelvin_tlul_pkg_32::tl_d2h_t d_skid_reg;
-  logic d_skid_valid_q, d_skid_valid_d;
-  logic d_skid_ready;
-
-  // Internal signals
-  logic [LaneIndexWidth - 1 : 0] lane_idx;
-  logic [LaneIndexWidth - 1 : 0] lane_idx_reg;
-  logic [MasterDataWidth - 1 : 0] m_a_data;
-  logic [MasterDataWidth / 8 - 1 : 0] m_a_mask;
-
-  // Lane index calculation
-  assign lane_idx = s_tl_i.a_address[LaneIndexWidth + 1 : 2];
-
-  // Master port data and mask generation
-  always_comb begin
-    m_a_data = '0;
-    m_a_mask = '0;
-    m_a_data[lane_idx * SlaveDataWidth +: SlaveDataWidth] = s_tl_i.a_data;
-    m_a_mask[lane_idx * LaneWidth +: LaneWidth] = s_tl_i.a_mask;
-  end
-
-  // Master port connections
-  assign m_tl_o.a_valid = s_tl_i.a_valid;
-  assign m_tl_o.a_opcode = s_tl_i.a_opcode;
-  assign m_tl_o.a_param = s_tl_i.a_param;
-  assign m_tl_o.a_size = s_tl_i.a_size;
-  assign m_tl_o.a_address = {
-             s_tl_i.a_address[AddrWidth - 1 : LaneIndexWidth + 2],
-             {(LaneIndexWidth + 2){1'b0}}};
-  assign m_tl_o.a_source = s_tl_i.a_source;
-  assign m_tl_o.a_data = m_a_data;
-  assign m_tl_o.a_mask = m_a_mask;
-  assign m_tl_o.a_user = s_tl_i.a_user;
-  assign m_tl_o.d_ready = d_skid_ready;
-
-  // Slave port connections
-  assign s_tl_o.d_opcode = d_skid_reg.d_opcode;
-  assign s_tl_o.d_param = d_skid_reg.d_param;
-  assign s_tl_o.d_sink = d_skid_reg.d_sink;
-  assign s_tl_o.d_source = d_skid_reg.d_source;
-  assign s_tl_o.d_data = d_skid_reg.d_data;
-  assign s_tl_o.d_error = d_skid_reg.d_error;
-  assign s_tl_o.d_user = d_skid_reg.d_user;
-  assign s_tl_o.d_size = d_skid_reg.d_size;
-  assign s_tl_o.d_valid = d_skid_valid_q;
-  assign s_tl_o.a_ready = m_tl_i.a_ready;
-
-  // Skid buffer logic
-  assign d_skid_ready = !d_skid_valid_q || s_tl_i.d_ready;
-
-  always_comb begin
-    d_skid_valid_d = d_skid_valid_q;
-    if (d_skid_ready) begin
-      d_skid_valid_d = m_tl_i.d_valid;
-    end
-  end
-
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      d_skid_valid_q <= 1'b0;
-      d_skid_reg <= '0;
-      lane_idx_reg <= '0;
-    end else begin
-      d_skid_valid_q <= d_skid_valid_d;
-      if (d_skid_ready && m_tl_i.d_valid) begin
-        d_skid_reg.d_opcode <= m_tl_i.d_opcode;
-        d_skid_reg.d_param <= m_tl_i.d_param;
-        d_skid_reg.d_sink <= m_tl_i.d_sink;
-        d_skid_reg.d_source <= m_tl_i.d_source;
-        d_skid_reg.d_data <= m_tl_i.d_data >> (lane_idx_reg * SlaveDataWidth);
-        d_skid_reg.d_error <= m_tl_i.d_error;
-        d_skid_reg.d_user <= m_tl_i.d_user;
-        d_skid_reg.d_size <= m_tl_i.d_size;
-      end
-      if (s_tl_i.a_valid && s_tl_o.a_ready) begin
-        lane_idx_reg <= lane_idx;
-      end
-    end
-  end
-endmodule
\ No newline at end of file
diff --git a/fpga/ip/tlul_width_bridge/BUILD b/fpga/ip/xbar_kelvin_soc_chisel/BUILD
similarity index 60%
rename from fpga/ip/tlul_width_bridge/BUILD
rename to fpga/ip/xbar_kelvin_soc_chisel/BUILD
index d78f918..fe7f6ab 100644
--- a/fpga/ip/tlul_width_bridge/BUILD
+++ b/fpga/ip/xbar_kelvin_soc_chisel/BUILD
@@ -14,10 +14,29 @@
 
 package(default_visibility = ["//visibility:public"])
 
+genrule(
+    name = "kelvin_xbar",
+    srcs = ["//hdl/chisel/src/soc:KelvinXbar.sv"],
+    outs = ["KelvinXbar.sv"],
+    cmd = "cp $< $@",
+)
+
+genrule(
+    name = "generate_core_file",
+    srcs = [
+        "xbar_kelvin_soc_chisel.core.tpl",
+        ":kelvin_xbar",
+    ],
+    outs = ["xbar_kelvin_soc_chisel.core"],
+    cmd = "sed 's|__VERILOG_FILE__|KelvinXbar.sv|' $(location xbar_kelvin_soc_chisel.core.tpl) > $@",
+)
+
 filegroup(
     name = "rtl_files",
     srcs = glob([
         "*.sv",
         "*.core",
-    ]),
+    ]) + [
+        ":KelvinXbar.sv",
+    ],
 )
diff --git a/fpga/ip/xbar_kelvin_soc_chisel/xbar_kelvin_soc_chisel.core b/fpga/ip/xbar_kelvin_soc_chisel/xbar_kelvin_soc_chisel.core
new file mode 100644
index 0000000..b469a7a
--- /dev/null
+++ b/fpga/ip/xbar_kelvin_soc_chisel/xbar_kelvin_soc_chisel.core
@@ -0,0 +1,14 @@
+CAPI=2:
+name: "kelvinv2:ip:xbar_kelvin_soc_chisel:0.1"
+description: "Kelvin SoC Chisel-Generated Crossbar"
+
+filesets:
+  rtl:
+    files:
+      - KelvinXbar.sv
+    file_type: systemVerilogSource
+
+targets:
+  default:
+    filesets:
+      - rtl
diff --git a/fpga/ip/xbar_kelvin_soc_chisel/xbar_kelvin_soc_chisel.core.tpl b/fpga/ip/xbar_kelvin_soc_chisel/xbar_kelvin_soc_chisel.core.tpl
new file mode 100644
index 0000000..88044d9
--- /dev/null
+++ b/fpga/ip/xbar_kelvin_soc_chisel/xbar_kelvin_soc_chisel.core.tpl
@@ -0,0 +1,14 @@
+CAPI=2:
+name: "kelvinv2:ip:xbar_kelvin_soc_chisel:0.1"
+description: "Kelvin SoC Chisel-Generated Crossbar"
+
+filesets:
+  rtl:
+    files:
+      - __VERILOG_FILE__
+    file_type: systemVerilogSource
+
+targets:
+  default:
+    filesets:
+      - rtl
diff --git a/fpga/kelvin_soc.core b/fpga/kelvin_soc.core
index 3db97b4..7cfb9e2 100644
--- a/fpga/kelvin_soc.core
+++ b/fpga/kelvin_soc.core
@@ -5,7 +5,7 @@
 filesets:
   rtl:
     depend:
-      - lowrisc:ip:xbar_kelvin_soc_xbar:0.1
+      - kelvinv2:ip:xbar_kelvin_soc_chisel:0.1
       - com.google.kelvin:fpga:kelvin_soc_pkg:0.1
       - com.google.kelvin:fpga:racl_pkg:0.1
       - lowrisc:ip:uart:0.1
@@ -15,8 +15,6 @@
       - lowrisc:ip:spi_device:0.1
       - lowrisc:kelvin_ip:rv_core_ibex:0.1
       - google:kelvin:rvv_core_mini_tlul
-      - kelvinv2:ip:tlul_host_upsizer
-      - kelvinv2:ip:tlul_device_downsizer
       - lowrisc:ibex:ibex_tracer
       - kelvinv2:ip:sram:0.1
       - kelvinv2:ip:kelvin_tlul:0.1
diff --git a/fpga/main.cc b/fpga/main.cc
index 3e1d352..bc5fe64 100644
--- a/fpga/main.cc
+++ b/fpga/main.cc
@@ -45,7 +45,7 @@
   memutil.RegisterMemoryArea("dtcm", 0x00010000, &dtcm);
   simctrl.RegisterExtension(&memutil);
 
-  simctrl.SetInitialResetDelay(20000);
+  simctrl.SetInitialResetDelay(2000);
   simctrl.SetResetDuration(10);
 
   std::cout << "Simulation of Kelvin SoC" << std::endl
diff --git a/fpga/post_process_xbar.py b/fpga/post_process_xbar.py
deleted file mode 100644
index 20179ab..0000000
--- a/fpga/post_process_xbar.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# Copyright 2025 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""A script to post-process the output of tlgen.
-
-This script takes an input directory and an output directory. It copies the
-contents of the input directory to the output directory, and then modifies the
-generated SystemVerilog file to use the correct TileLink types.
-"""
-
-import argparse
-import os
-import re
-import shutil
-import stat
-
-
-def main():
-    parser = argparse.ArgumentParser(description=__doc__)
-    parser.add_argument(
-        "--input-dir",
-        required=True,
-        help="The input directory.",
-    )
-    parser.add_argument(
-        "--output-dir",
-        required=True,
-        help="The output directory.",
-    )
-    parser.add_argument(
-        "--cores",
-        nargs="+",
-        required=True,
-        help="The cores to add as dependencies.",
-    )
-    args = parser.parse_args()
-
-    # Copy the contents of the input directory to the output directory.
-    if os.path.exists(args.output_dir):
-        shutil.rmtree(args.output_dir)
-    shutil.copytree(args.input_dir, args.output_dir)
-
-    # Find the generated SystemVerilog file.
-    sv_file = None
-    for root, _, files in os.walk(args.output_dir):
-        for f in files:
-            if f == "xbar_kelvin_soc_xbar.sv":
-                sv_file = os.path.join(root, f)
-                break
-        if sv_file:
-            break
-
-    if sv_file is None:
-        raise RuntimeError("Could not find generated SystemVerilog file.")
-
-    # Make the file writable.
-    os.chmod(sv_file, stat.S_IWRITE | stat.S_IREAD)
-
-    # Read the file and perform the replacements.
-    with open(sv_file, "r") as f:
-        content = f.read()
-    original_content = content
-    content = content.replace("tlul_pkg::tl_h2d_t",
-                              "kelvin_tlul_pkg_128::tl_h2d_t")
-    content = content.replace("tlul_pkg::tl_d2h_t",
-                              "kelvin_tlul_pkg_128::tl_d2h_t")
-    content = content.replace("import tlul_pkg::*",
-                              "import kelvin_tlul_pkg_128::*")
-    content = content.replace("tlul_socket_1n #", "tlul_socket_1n_128 #")
-    content = content.replace("tlul_socket_m1 #", "tlul_socket_m1_128 #")
-    content = content.replace("tlul_fifo_async #", "tlul_fifo_async_128 #")
-
-    if original_content == content:
-        print("Warning: No replacements made.")
-    else:
-        print("Success: Replacements made.")
-
-    with open(sv_file, "w") as f:
-        f.write(content)
-
-    core_file = None
-    for root, _, files in os.walk(args.output_dir):
-        for f in files:
-            if f == "xbar_kelvin_soc_xbar.core":
-                core_file = os.path.join(root, f)
-                break
-            if core_file:
-                break
-    if core_file is None:
-        raise RuntimeError("Could not find generated core file.")
-    os.chmod(core_file, stat.S_IWRITE | stat.S_IREAD)
-    with open(core_file, "r") as f:
-        content = f.read()
-    original_content = content
-    for core in args.cores:
-        content = re.sub(r"(\s+)depend:", r"\1depend:\n\1  - " + core, content)
-    if original_content == content:
-        print("Warning: No replacements made (core).")
-    else:
-        print("Success: replacesments made (core).")
-    with open(core_file, "w") as f:
-        f.write(content)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/fpga/rtl/chip_nexus.sv b/fpga/rtl/chip_nexus.sv
index 30f8dff..50dd228 100644
--- a/fpga/rtl/chip_nexus.sv
+++ b/fpga/rtl/chip_nexus.sv
@@ -14,7 +14,7 @@
 
 module chip_nexus
     #(parameter MemInitFile = "",
-      parameter int ClockFrequencyMhz = 10)
+      parameter int ClockFrequencyMhz = 80)
     (input clk_p_i,
      input clk_n_i,
      input rst_ni,
@@ -28,6 +28,8 @@
 
   logic clk;
   logic rst_n;
+  logic clk_ibex;
+  logic rst_ibex_n;
   logic clk_48MHz;
   logic clk_aon;
 
@@ -50,12 +52,27 @@
                .clk_main_o(clk),
                .clk_48MHz_o(clk_48MHz),
                .clk_aon_o(clk_aon),
+               .clk_ibex_o(clk_ibex),
                .rst_no(rst_n));
 
+  // Reset synchronizer for Ibex reset.
+  logic rst_n_sync;
+  always_ff @(posedge clk_ibex or negedge rst_n) begin
+    if (!rst_n) begin
+      rst_n_sync <= 1'b0;
+      rst_ibex_n <= 1'b0;
+    end else begin
+      rst_n_sync <= 1'b1;
+      rst_ibex_n <= rst_n_sync;
+    end
+  end
+
   kelvin_soc #(.MemInitFile(MemInitFile),
                .ClockFrequencyMhz(ClockFrequencyMhz))
       i_kelvin_soc(.clk_i(clk),
                    .rst_ni(rst_n),
+                   .ibex_clk_i(clk_ibex),
+                   .ibex_rst_ni(rst_ibex_n),
                    .spi_clk_i(spi_clk_i),
                    .scanmode_i(prim_mubi_pkg::MuBi4False),
                    .uart_sideband_i(uart_sideband_i),
diff --git a/fpga/rtl/chip_verilator.sv b/fpga/rtl/chip_verilator.sv
index b94ffcb..ce495ed 100644
--- a/fpga/rtl/chip_verilator.sv
+++ b/fpga/rtl/chip_verilator.sv
@@ -14,7 +14,7 @@
 
 module chip_verilator
     #(parameter MemInitFile = "",
-      parameter int ClockFrequencyMhz = 10)
+      parameter int ClockFrequencyMhz = 80)
     (input clk_i,
      input rst_ni,
      input spi_clk_i,
@@ -52,6 +52,8 @@
                .ClockFrequencyMhz(ClockFrequencyMhz))
       i_kelvin_soc(.clk_i(clk_i),
                    .rst_ni(rst_ni),
+                   .ibex_clk_i(ibex_clk_i),
+                   .ibex_rst_ni(ibex_rst_ni),
                    .spi_clk_i(spi_clk_i),
                    .scanmode_i(scanmode_i),
                    .uart_sideband_i(
@@ -62,4 +64,29 @@
 
   assign uart0_tx = uart_sideband_o[0].cio_tx;
   assign uart1_tx = uart_sideband_o[1].cio_tx;
+
+  // Clock divider for Ibex clock.
+  logic [1:0] clk_divider;
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      clk_divider <= 2'b0;
+    end else begin
+      clk_divider <= clk_divider + 1;
+    end
+  end
+  logic ibex_clk_i;
+  assign ibex_clk_i = clk_divider[1];
+
+  // Reset synchronizer for Ibex reset.
+  logic ibex_rst_ni;
+  logic rst_n_sync;
+  always_ff @(posedge ibex_clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      rst_n_sync <= 1'b0;
+      ibex_rst_ni <= 1'b0;
+    end else begin
+      rst_n_sync <= 1'b1;
+      ibex_rst_ni <= rst_n_sync;
+    end
+  end
 endmodule
diff --git a/fpga/rtl/clkgen_wrapper.sv b/fpga/rtl/clkgen_wrapper.sv
index 55339ef..bcc8bcc 100644
--- a/fpga/rtl/clkgen_wrapper.sv
+++ b/fpga/rtl/clkgen_wrapper.sv
@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
 module clkgen_wrapper
-    #(parameter int ClockFrequencyMhz = 10)
+    #(parameter int ClockFrequencyMhz = 80)
     (input clk_p_i,
      input clk_n_i,
      input rst_ni,
@@ -11,6 +11,7 @@
      output clk_main_o,
      output clk_48MHz_o,
      output clk_aon_o,
+     output clk_ibex_o,
      output rst_no);
 
   clkgen_xilultrascaleplus #(.ClockFrequencyMhz(ClockFrequencyMhz))
@@ -21,5 +22,6 @@
                .clk_main_o(clk_main_o),
                .clk_48MHz_o(clk_48MHz_o),
                .clk_aon_o(clk_aon_o),
+               .clk_ibex_o(clk_ibex_o),
                .rst_no(rst_no));
 endmodule
\ No newline at end of file
diff --git a/fpga/rtl/clkgen_xilultrascaleplus.sv b/fpga/rtl/clkgen_xilultrascaleplus.sv
index 9817265..bedc4a5 100644
--- a/fpga/rtl/clkgen_xilultrascaleplus.sv
+++ b/fpga/rtl/clkgen_xilultrascaleplus.sv
@@ -14,7 +14,7 @@
 // limitations under the License.
 
 module clkgen_xilultrascaleplus
-    #(parameter int ClockFrequencyMhz = 10,
+    #(parameter int ClockFrequencyMhz = 80,
       // Add BUFG if not done by downstream logic
       parameter bit AddClkBuf = 1)
     (input clk_i,
@@ -24,6 +24,7 @@
      output clk_main_o,
      output clk_48MHz_o,
      output clk_aon_o,
+     output clk_ibex_o,
      output rst_no);
   logic locked_pll;
   logic io_clk_buf;
@@ -36,6 +37,8 @@
   logic clk_48_unbuf;
   logic clk_aon_buf;
   logic clk_aon_unbuf;
+  logic clk_ibex_buf;
+  logic clk_ibex_unbuf;
   logic clk_ibufds_o;
 
   // Input IBUFDS conver diff-pair to single-end
@@ -44,6 +47,7 @@
                     .O(clk_ibufds_o));
 
   localparam real CLKOUT0_DIVIDE_F_CALC = 1200.0 / ClockFrequencyMhz;
+  localparam int CLKOUT2_DIVIDE_CALC = CLKOUT0_DIVIDE_F_CALC * 4;
 
   MMCME2_ADV #(
           .BANDWIDTH("OPTIMIZED"),
@@ -58,6 +62,9 @@
           .CLKOUT1_DIVIDE(25),
           .CLKOUT1_PHASE(0.000),
           .CLKOUT1_DUTY_CYCLE(0.500),
+          .CLKOUT2_DIVIDE(CLKOUT2_DIVIDE_CALC),
+          .CLKOUT2_PHASE(0.000),
+          .CLKOUT2_DUTY_CYCLE(0.500),
           // With CLKOUT4_CASCADE, CLKOUT6's divider is an input to CLKOUT4's
           // divider. The effective ratio is a multiplication of the two.
           .CLKOUT4_DIVIDE(40),
@@ -72,7 +79,7 @@
           .CLKOUT0B(),
           .CLKOUT1(clk_48_unbuf),
           .CLKOUT1B(),
-          .CLKOUT2(),
+          .CLKOUT2(clk_ibex_unbuf),
           .CLKOUT2B(),
           .CLKOUT3(),
           .CLKOUT3B(),
@@ -120,10 +127,14 @@
 
     BUFGCE clk_48_bufgce(.I(clk_48_unbuf),
                          .O(clk_48_buf));
+
+    BUFGCE clk_ibex_bufgce(.I(clk_ibex_unbuf),
+                         .O(clk_ibex_buf));
   end else begin : gen_no_clk_bufs
     // BUFGs added by downstream modules, no need to add here
     assign clk_10_buf = clk_10_unbuf;
     assign clk_48_buf = clk_48_unbuf;
+    assign clk_ibex_buf = clk_ibex_unbuf;
   end
 
   // outputs
@@ -131,6 +142,7 @@
   assign clk_main_o = clk_10_buf;
   assign clk_48MHz_o = clk_48_buf;
   assign clk_aon_o = clk_aon_buf;
+  assign clk_ibex_o = clk_ibex_buf;
 
   // reset
   assign rst_no = locked_pll & rst_ni & srst_ni;
diff --git a/fpga/rtl/kelvin_soc.sv b/fpga/rtl/kelvin_soc.sv
index 1c23def..479f887 100644
--- a/fpga/rtl/kelvin_soc.sv
+++ b/fpga/rtl/kelvin_soc.sv
@@ -14,9 +14,11 @@
 
 module kelvin_soc
     #(parameter MemInitFile = "",
-      parameter int ClockFrequencyMhz = 10)
+      parameter int ClockFrequencyMhz = 80)
     (input clk_i,
      input rst_ni,
+     input ibex_clk_i,
+     input ibex_rst_ni,
      input spi_clk_i,
      input prim_mubi_pkg::mubi4_t scanmode_i,
      input top_pkg::uart_sideband_i_t[1 : 0] uart_sideband_i,
@@ -34,102 +36,257 @@
 
   kelvin_tlul_pkg_32::tl_h2d_t tl_ibex_core_i_o_32;
   kelvin_tlul_pkg_32::tl_d2h_t tl_ibex_core_i_i_32;
-  kelvin_tlul_pkg_128::tl_h2d_t tl_ibex_core_i_o_xbar;
-  kelvin_tlul_pkg_128::tl_d2h_t tl_ibex_core_i_i_xbar;
-
-  tlul_host_upsizer i_ibex_core_i_upsizer(.clk_i(clk_i),
-                                          .rst_ni(rst_ni),
-                                          .s_tl_i(tl_ibex_core_i_o_32),
-                                          .s_tl_o(tl_ibex_core_i_i_32),
-                                          .m_tl_o(tl_ibex_core_i_o_xbar),
-                                          .m_tl_i(tl_ibex_core_i_i_xbar));
 
   kelvin_tlul_pkg_32::tl_h2d_t tl_rom_o_32;
   kelvin_tlul_pkg_32::tl_d2h_t tl_rom_i_32;
-  kelvin_tlul_pkg_128::tl_h2d_t tl_rom_o_xbar;
-  kelvin_tlul_pkg_128::tl_d2h_t tl_rom_i_xbar;
-  tlul_device_downsizer i_rom_downsizer(.clk_i(clk_i),
-                                        .rst_ni(rst_ni),
-                                        .s_tl_i(tl_rom_o_xbar),
-                                        .s_tl_o(tl_rom_i_xbar),
-                                        .m_tl_o(tl_rom_o_32),
-                                        .m_tl_i(tl_rom_i_32));
 
   kelvin_tlul_pkg_32::tl_h2d_t tl_ibex_core_d_o_32;
   kelvin_tlul_pkg_32::tl_d2h_t tl_ibex_core_d_i_32;
 
-  kelvin_tlul_pkg_128::tl_h2d_t tl_ibex_core_d_o_xbar;
-  kelvin_tlul_pkg_128::tl_d2h_t tl_ibex_core_d_i_xbar;
-  tlul_host_upsizer i_ibex_core_d_upsizer(.clk_i(clk_i),
-                                          .rst_ni(rst_ni),
-                                          .s_tl_i(tl_ibex_core_d_o_32),
-                                          .s_tl_o(tl_ibex_core_d_i_32),
-                                          .m_tl_o(tl_ibex_core_d_o_xbar),
-                                          .m_tl_i(tl_ibex_core_d_i_xbar));
-
-  kelvin_tlul_pkg_128::tl_h2d_t tl_sram_o_xbar;
-  kelvin_tlul_pkg_128::tl_d2h_t tl_sram_i_xbar;
   tl_h2d_t tl_sram_o;
   tl_d2h_t tl_sram_i;
-  tlul_device_downsizer i_sram_downsizer(.clk_i(clk_i),
-                                         .rst_ni(rst_ni),
-                                         .s_tl_i(tl_sram_o_xbar),
-                                         .s_tl_o(tl_sram_i_xbar),
-                                         .m_tl_o(tl_sram_o),
-                                         .m_tl_i(tl_sram_i));
-  kelvin_tlul_pkg_128::tl_h2d_t tl_uart0_o_xbar;
-  kelvin_tlul_pkg_128::tl_d2h_t tl_uart0_i_xbar;
+
   tl_h2d_t tl_uart0_o;
   tl_d2h_t tl_uart0_i;
-  tlul_device_downsizer i_uart0_downsizer(.clk_i(clk_i),
-                                          .rst_ni(rst_ni),
-                                          .s_tl_i(tl_uart0_o_xbar),
-                                          .s_tl_o(tl_uart0_i_xbar),
-                                          .m_tl_o(tl_uart0_o),
-                                          .m_tl_i(tl_uart0_i));
-  kelvin_tlul_pkg_128::tl_h2d_t tl_uart1_o_xbar;
-  kelvin_tlul_pkg_128::tl_d2h_t tl_uart1_i_xbar;
+
   tl_h2d_t tl_uart1_o;
   tl_d2h_t tl_uart1_i;
-  tlul_device_downsizer i_uart1_downsizer(.clk_i(clk_i),
-                                          .rst_ni(rst_ni),
-                                          .s_tl_i(tl_uart1_o_xbar),
-                                          .s_tl_o(tl_uart1_i_xbar),
-                                          .m_tl_o(tl_uart1_o),
-                                          .m_tl_i(tl_uart1_i));
-  kelvin_tlul_pkg_128::tl_h2d_t tl_spi0_o_xbar;
-  kelvin_tlul_pkg_128::tl_d2h_t tl_spi0_i_xbar;
+
   tl_h2d_t tl_spi0_o;
   tl_d2h_t tl_spi0_i;
-  tlul_device_downsizer i_spi0_downsizer(.clk_i(clk_i),
-                                         .rst_ni(rst_ni),
-                                         .s_tl_i(tl_spi0_o_xbar),
-                                         .s_tl_o(tl_spi0_i_xbar),
-                                         .m_tl_o(tl_spi0_o),
-                                         .m_tl_i(tl_spi0_i));
 
-  xbar_kelvin_soc_xbar i_xbar(.clk_i(clk_i),
-                              .rst_ni(rst_ni),
-                              .spi_clk_i(spi_clk_i),
-                              .scanmode_i(scanmode_i),
-                              .tl_kelvin_core_i(tl_kelvin_core_i),
-                              .tl_kelvin_core_o(tl_kelvin_core_o),
-                              .tl_ibex_core_i_o(tl_ibex_core_i_i_xbar),
-                              .tl_ibex_core_i_i(tl_ibex_core_i_o_xbar),
-                              .tl_ibex_core_d_o(tl_ibex_core_d_i_xbar),
-                              .tl_ibex_core_d_i(tl_ibex_core_d_o_xbar),
-                              .tl_kelvin_device_o(tl_kelvin_device_o),
-                              .tl_kelvin_device_i(tl_kelvin_device_i),
-                              .tl_rom_o(tl_rom_o_xbar),
-                              .tl_rom_i(tl_rom_i_xbar),
-                              .tl_sram_o(tl_sram_o_xbar),
-                              .tl_sram_i(tl_sram_i_xbar),
-                              .tl_uart0_o(tl_uart0_o_xbar),
-                              .tl_uart0_i(tl_uart0_i_xbar),
-                              .tl_uart1_o(tl_uart1_o_xbar),
-                              .tl_uart1_i(tl_uart1_i_xbar),
-                              .tl_spi0_o(tl_spi0_o_xbar),
-                              .tl_spi0_i(tl_spi0_i_xbar));
+  KelvinXbar i_xbar(
+    .io_clk_i(clk_i),
+    .io_rst_ni(rst_ni),
+    .io_async_ports_devices_0_clock(spi_clk_i),
+    .io_async_ports_devices_0_reset(rst_ni),
+    .io_async_ports_hosts_0_clock(ibex_clk_i),
+    .io_async_ports_hosts_0_reset(ibex_rst_ni),
+
+    // Host connections
+    .io_hosts_0_a_valid(tl_kelvin_core_i.a_valid),
+    .io_hosts_0_a_bits_opcode(tl_kelvin_core_i.a_opcode),
+    .io_hosts_0_a_bits_param(tl_kelvin_core_i.a_param),
+    .io_hosts_0_a_bits_size(tl_kelvin_core_i.a_size),
+    .io_hosts_0_a_bits_source(tl_kelvin_core_i.a_source),
+    .io_hosts_0_a_bits_address(tl_kelvin_core_i.a_address),
+    .io_hosts_0_a_bits_mask(tl_kelvin_core_i.a_mask),
+    .io_hosts_0_a_bits_data(tl_kelvin_core_i.a_data),
+    .io_hosts_0_a_bits_user_rsvd(tl_kelvin_core_i.a_user.rsvd),
+    .io_hosts_0_a_bits_user_instr_type(tl_kelvin_core_i.a_user.instr_type),
+    .io_hosts_0_a_bits_user_cmd_intg(tl_kelvin_core_i.a_user.cmd_intg),
+    .io_hosts_0_a_bits_user_data_intg(tl_kelvin_core_i.a_user.data_intg),
+    .io_hosts_0_d_ready(tl_kelvin_core_i.d_ready),
+    .io_hosts_1_a_valid(tl_ibex_core_i_o_32.a_valid),
+    .io_hosts_1_a_bits_opcode(tl_ibex_core_i_o_32.a_opcode),
+    .io_hosts_1_a_bits_param(tl_ibex_core_i_o_32.a_param),
+    .io_hosts_1_a_bits_size(tl_ibex_core_i_o_32.a_size),
+    .io_hosts_1_a_bits_source(tl_ibex_core_i_o_32.a_source),
+    .io_hosts_1_a_bits_address(tl_ibex_core_i_o_32.a_address),
+    .io_hosts_1_a_bits_mask(tl_ibex_core_i_o_32.a_mask),
+    .io_hosts_1_a_bits_data(tl_ibex_core_i_o_32.a_data),
+    .io_hosts_1_a_bits_user_rsvd(tl_ibex_core_i_o_32.a_user.rsvd),
+    .io_hosts_1_a_bits_user_instr_type(tl_ibex_core_i_o_32.a_user.instr_type),
+    .io_hosts_1_a_bits_user_cmd_intg(tl_ibex_core_i_o_32.a_user.cmd_intg),
+    .io_hosts_1_a_bits_user_data_intg(tl_ibex_core_i_o_32.a_user.data_intg),
+    .io_hosts_1_d_ready(tl_ibex_core_i_o_32.d_ready),
+    .io_hosts_2_a_valid(tl_ibex_core_d_o_32.a_valid),
+    .io_hosts_2_a_bits_opcode(tl_ibex_core_d_o_32.a_opcode),
+    .io_hosts_2_a_bits_param(tl_ibex_core_d_o_32.a_param),
+    .io_hosts_2_a_bits_size(tl_ibex_core_d_o_32.a_size),
+    .io_hosts_2_a_bits_source(tl_ibex_core_d_o_32.a_source),
+    .io_hosts_2_a_bits_address(tl_ibex_core_d_o_32.a_address),
+    .io_hosts_2_a_bits_mask(tl_ibex_core_d_o_32.a_mask),
+    .io_hosts_2_a_bits_data(tl_ibex_core_d_o_32.a_data),
+    .io_hosts_2_a_bits_user_rsvd(tl_ibex_core_d_o_32.a_user.rsvd),
+    .io_hosts_2_a_bits_user_instr_type(tl_ibex_core_d_o_32.a_user.instr_type),
+    .io_hosts_2_a_bits_user_cmd_intg(tl_ibex_core_d_o_32.a_user.cmd_intg),
+    .io_hosts_2_a_bits_user_data_intg(tl_ibex_core_d_o_32.a_user.data_intg),
+    .io_hosts_2_d_ready(tl_ibex_core_d_o_32.d_ready),
+
+    // Host response connections
+    .io_hosts_0_a_ready(tl_kelvin_core_o.a_ready),
+    .io_hosts_0_d_valid(tl_kelvin_core_o.d_valid),
+    .io_hosts_0_d_bits_opcode(tl_kelvin_core_o.d_opcode),
+    .io_hosts_0_d_bits_param(tl_kelvin_core_o.d_param),
+    .io_hosts_0_d_bits_size(tl_kelvin_core_o.d_size),
+    .io_hosts_0_d_bits_source(tl_kelvin_core_o.d_source),
+    .io_hosts_0_d_bits_sink(tl_kelvin_core_o.d_sink),
+    .io_hosts_0_d_bits_data(tl_kelvin_core_o.d_data),
+    .io_hosts_0_d_bits_error(tl_kelvin_core_o.d_error),
+    .io_hosts_0_d_bits_user_rsp_intg(tl_kelvin_core_o.d_user.rsp_intg),
+    .io_hosts_0_d_bits_user_data_intg(tl_kelvin_core_o.d_user.data_intg),
+    .io_hosts_1_a_ready(tl_ibex_core_i_i_32.a_ready),
+    .io_hosts_1_d_valid(tl_ibex_core_i_i_32.d_valid),
+    .io_hosts_1_d_bits_opcode(tl_ibex_core_i_i_32.d_opcode),
+    .io_hosts_1_d_bits_param(tl_ibex_core_i_i_32.d_param),
+    .io_hosts_1_d_bits_size(tl_ibex_core_i_i_32.d_size),
+    .io_hosts_1_d_bits_source(tl_ibex_core_i_i_32.d_source),
+    .io_hosts_1_d_bits_sink(tl_ibex_core_i_i_32.d_sink),
+    .io_hosts_1_d_bits_data(tl_ibex_core_i_i_32.d_data),
+    .io_hosts_1_d_bits_error(tl_ibex_core_i_i_32.d_error),
+    .io_hosts_1_d_bits_user_rsp_intg(tl_ibex_core_i_i_32.d_user.rsp_intg),
+    .io_hosts_1_d_bits_user_data_intg(tl_ibex_core_i_i_32.d_user.data_intg),
+    .io_hosts_2_a_ready(tl_ibex_core_d_i_32.a_ready),
+    .io_hosts_2_d_valid(tl_ibex_core_d_i_32.d_valid),
+    .io_hosts_2_d_bits_opcode(tl_ibex_core_d_i_32.d_opcode),
+    .io_hosts_2_d_bits_param(tl_ibex_core_d_i_32.d_param),
+    .io_hosts_2_d_bits_size(tl_ibex_core_d_i_32.d_size),
+    .io_hosts_2_d_bits_source(tl_ibex_core_d_i_32.d_source),
+    .io_hosts_2_d_bits_sink(tl_ibex_core_d_i_32.d_sink),
+    .io_hosts_2_d_bits_data(tl_ibex_core_d_i_32.d_data),
+    .io_hosts_2_d_bits_error(tl_ibex_core_d_i_32.d_error),
+    .io_hosts_2_d_bits_user_rsp_intg(tl_ibex_core_d_i_32.d_user.rsp_intg),
+    .io_hosts_2_d_bits_user_data_intg(tl_ibex_core_d_i_32.d_user.data_intg),
+
+    // Device connections
+    .io_devices_0_a_ready(tl_kelvin_device_i.a_ready),
+    .io_devices_0_d_valid(tl_kelvin_device_i.d_valid),
+    .io_devices_0_d_bits_opcode(tl_kelvin_device_i.d_opcode),
+    .io_devices_0_d_bits_param(tl_kelvin_device_i.d_param),
+    .io_devices_0_d_bits_size(tl_kelvin_device_i.d_size),
+    .io_devices_0_d_bits_source(tl_kelvin_device_i.d_source),
+    .io_devices_0_d_bits_sink(tl_kelvin_device_i.d_sink),
+    .io_devices_0_d_bits_data(tl_kelvin_device_i.d_data),
+    .io_devices_0_d_bits_error(tl_kelvin_device_i.d_error),
+    .io_devices_0_d_bits_user_rsp_intg(tl_kelvin_device_i.d_user.rsp_intg),
+    .io_devices_0_d_bits_user_data_intg(tl_kelvin_device_i.d_user.data_intg),
+    .io_devices_1_a_ready(tl_rom_i_32.a_ready),
+    .io_devices_1_d_valid(tl_rom_i_32.d_valid),
+    .io_devices_1_d_bits_opcode(tl_rom_i_32.d_opcode),
+    .io_devices_1_d_bits_param(tl_rom_i_32.d_param),
+    .io_devices_1_d_bits_size(tl_rom_i_32.d_size),
+    .io_devices_1_d_bits_source(tl_rom_i_32.d_source),
+    .io_devices_1_d_bits_sink(tl_rom_i_32.d_sink),
+    .io_devices_1_d_bits_data(tl_rom_i_32.d_data),
+    .io_devices_1_d_bits_error(tl_rom_i_32.d_error),
+    .io_devices_1_d_bits_user_rsp_intg(tl_rom_i_32.d_user.rsp_intg),
+    .io_devices_1_d_bits_user_data_intg(tl_rom_i_32.d_user.data_intg),
+    .io_devices_2_a_ready(tl_sram_i.a_ready),
+    .io_devices_2_d_valid(tl_sram_i.d_valid),
+    .io_devices_2_d_bits_opcode(tl_sram_i.d_opcode),
+    .io_devices_2_d_bits_param(tl_sram_i.d_param),
+    .io_devices_2_d_bits_size(tl_sram_i.d_size),
+    .io_devices_2_d_bits_source(tl_sram_i.d_source),
+    .io_devices_2_d_bits_sink(tl_sram_i.d_sink),
+    .io_devices_2_d_bits_data(tl_sram_i.d_data),
+    .io_devices_2_d_bits_error(tl_sram_i.d_error),
+    .io_devices_2_d_bits_user_rsp_intg(tl_sram_i.d_user.rsp_intg),
+    .io_devices_2_d_bits_user_data_intg(tl_sram_i.d_user.data_intg),
+    .io_devices_3_a_ready(tl_uart0_i.a_ready),
+    .io_devices_3_d_valid(tl_uart0_i.d_valid),
+    .io_devices_3_d_bits_opcode(tl_uart0_i.d_opcode),
+    .io_devices_3_d_bits_param(tl_uart0_i.d_param),
+    .io_devices_3_d_bits_size(tl_uart0_i.d_size),
+    .io_devices_3_d_bits_source(tl_uart0_i.d_source),
+    .io_devices_3_d_bits_sink(tl_uart0_i.d_sink),
+    .io_devices_3_d_bits_data(tl_uart0_i.d_data),
+    .io_devices_3_d_bits_error(tl_uart0_i.d_error),
+    .io_devices_3_d_bits_user_rsp_intg(tl_uart0_i.d_user.rsp_intg),
+    .io_devices_3_d_bits_user_data_intg(tl_uart0_i.d_user.data_intg),
+    .io_devices_4_a_ready(tl_uart1_i.a_ready),
+    .io_devices_4_d_valid(tl_uart1_i.d_valid),
+    .io_devices_4_d_bits_opcode(tl_uart1_i.d_opcode),
+    .io_devices_4_d_bits_param(tl_uart1_i.d_param),
+    .io_devices_4_d_bits_size(tl_uart1_i.d_size),
+    .io_devices_4_d_bits_source(tl_uart1_i.d_source),
+    .io_devices_4_d_bits_sink(tl_uart1_i.d_sink),
+    .io_devices_4_d_bits_data(tl_uart1_i.d_data),
+    .io_devices_4_d_bits_error(tl_uart1_i.d_error),
+    .io_devices_4_d_bits_user_rsp_intg(tl_uart1_i.d_user.rsp_intg),
+    .io_devices_4_d_bits_user_data_intg(tl_uart1_i.d_user.data_intg),
+    .io_devices_5_a_ready(tl_spi0_i.a_ready),
+    .io_devices_5_d_valid(tl_spi0_i.d_valid),
+    .io_devices_5_d_bits_opcode(tl_spi0_i.d_opcode),
+    .io_devices_5_d_bits_param(tl_spi0_i.d_param),
+    .io_devices_5_d_bits_size(tl_spi0_i.d_size),
+    .io_devices_5_d_bits_source(tl_spi0_i.d_source),
+    .io_devices_5_d_bits_sink(tl_spi0_i.d_sink),
+    .io_devices_5_d_bits_data(tl_spi0_i.d_data),
+    .io_devices_5_d_bits_error(tl_spi0_i.d_error),
+    .io_devices_5_d_bits_user_rsp_intg(tl_spi0_i.d_user.rsp_intg),
+    .io_devices_5_d_bits_user_data_intg(tl_spi0_i.d_user.data_intg),
+
+    // Device response connections
+    .io_devices_0_a_valid(tl_kelvin_device_o.a_valid),
+    .io_devices_0_a_bits_opcode(tl_kelvin_device_o.a_opcode),
+    .io_devices_0_a_bits_param(tl_kelvin_device_o.a_param),
+    .io_devices_0_a_bits_size(tl_kelvin_device_o.a_size),
+    .io_devices_0_a_bits_source(tl_kelvin_device_o.a_source),
+    .io_devices_0_a_bits_address(tl_kelvin_device_o.a_address),
+    .io_devices_0_a_bits_mask(tl_kelvin_device_o.a_mask),
+    .io_devices_0_a_bits_data(tl_kelvin_device_o.a_data),
+    .io_devices_0_a_bits_user_rsvd(tl_kelvin_device_o.a_user.rsvd),
+    .io_devices_0_a_bits_user_instr_type(tl_kelvin_device_o.a_user.instr_type),
+    .io_devices_0_a_bits_user_cmd_intg(tl_kelvin_device_o.a_user.cmd_intg),
+    .io_devices_0_a_bits_user_data_intg(tl_kelvin_device_o.a_user.data_intg),
+    .io_devices_0_d_ready(tl_kelvin_device_o.d_ready),
+    .io_devices_1_a_valid(tl_rom_o_32.a_valid),
+    .io_devices_1_a_bits_opcode(tl_rom_o_32.a_opcode),
+    .io_devices_1_a_bits_param(tl_rom_o_32.a_param),
+    .io_devices_1_a_bits_size(tl_rom_o_32.a_size),
+    .io_devices_1_a_bits_source(tl_rom_o_32.a_source),
+    .io_devices_1_a_bits_address(tl_rom_o_32.a_address),
+    .io_devices_1_a_bits_mask(tl_rom_o_32.a_mask),
+    .io_devices_1_a_bits_data(tl_rom_o_32.a_data),
+    .io_devices_1_a_bits_user_rsvd(tl_rom_o_32.a_user.rsvd),
+    .io_devices_1_a_bits_user_instr_type(tl_rom_o_32.a_user.instr_type),
+    .io_devices_1_a_bits_user_cmd_intg(tl_rom_o_32.a_user.cmd_intg),
+    .io_devices_1_a_bits_user_data_intg(tl_rom_o_32.a_user.data_intg),
+    .io_devices_1_d_ready(tl_rom_o_32.d_ready),
+    .io_devices_2_a_valid(tl_sram_o.a_valid),
+    .io_devices_2_a_bits_opcode(tl_sram_o.a_opcode),
+    .io_devices_2_a_bits_param(tl_sram_o.a_param),
+    .io_devices_2_a_bits_size(tl_sram_o.a_size),
+    .io_devices_2_a_bits_source(tl_sram_o.a_source),
+    .io_devices_2_a_bits_address(tl_sram_o.a_address),
+    .io_devices_2_a_bits_mask(tl_sram_o.a_mask),
+    .io_devices_2_a_bits_data(tl_sram_o.a_data),
+    .io_devices_2_a_bits_user_rsvd(tl_sram_o.a_user.rsvd),
+    .io_devices_2_a_bits_user_instr_type(tl_sram_o.a_user.instr_type),
+    .io_devices_2_a_bits_user_cmd_intg(tl_sram_o.a_user.cmd_intg),
+    .io_devices_2_a_bits_user_data_intg(tl_sram_o.a_user.data_intg),
+    .io_devices_2_d_ready(tl_sram_o.d_ready),
+    .io_devices_3_a_valid(tl_uart0_o.a_valid),
+    .io_devices_3_a_bits_opcode(tl_uart0_o.a_opcode),
+    .io_devices_3_a_bits_param(tl_uart0_o.a_param),
+    .io_devices_3_a_bits_size(tl_uart0_o.a_size),
+    .io_devices_3_a_bits_source(tl_uart0_o.a_source),
+    .io_devices_3_a_bits_address(tl_uart0_o.a_address),
+    .io_devices_3_a_bits_mask(tl_uart0_o.a_mask),
+    .io_devices_3_a_bits_data(tl_uart0_o.a_data),
+    .io_devices_3_a_bits_user_rsvd(tl_uart0_o.a_user.rsvd),
+    .io_devices_3_a_bits_user_instr_type(tl_uart0_o.a_user.instr_type),
+    .io_devices_3_a_bits_user_cmd_intg(tl_uart0_o.a_user.cmd_intg),
+    .io_devices_3_a_bits_user_data_intg(tl_uart0_o.a_user.data_intg),
+    .io_devices_3_d_ready(tl_uart0_o.d_ready),
+    .io_devices_4_a_valid(tl_uart1_o.a_valid),
+    .io_devices_4_a_bits_opcode(tl_uart1_o.a_opcode),
+    .io_devices_4_a_bits_param(tl_uart1_o.a_param),
+    .io_devices_4_a_bits_size(tl_uart1_o.a_size),
+    .io_devices_4_a_bits_source(tl_uart1_o.a_source),
+    .io_devices_4_a_bits_address(tl_uart1_o.a_address),
+    .io_devices_4_a_bits_mask(tl_uart1_o.a_mask),
+    .io_devices_4_a_bits_data(tl_uart1_o.a_data),
+    .io_devices_4_a_bits_user_rsvd(tl_uart1_o.a_user.rsvd),
+    .io_devices_4_a_bits_user_instr_type(tl_uart1_o.a_user.instr_type),
+    .io_devices_4_a_bits_user_cmd_intg(tl_uart1_o.a_user.cmd_intg),
+    .io_devices_4_a_bits_user_data_intg(tl_uart1_o.a_user.data_intg),
+    .io_devices_4_d_ready(tl_uart1_o.d_ready),
+    .io_devices_5_a_valid(tl_spi0_o.a_valid),
+    .io_devices_5_a_bits_opcode(tl_spi0_o.a_opcode),
+    .io_devices_5_a_bits_param(tl_spi0_o.a_param),
+    .io_devices_5_a_bits_size(tl_spi0_o.a_size),
+    .io_devices_5_a_bits_source(tl_spi0_o.a_source),
+    .io_devices_5_a_bits_address(tl_spi0_o.a_address),
+    .io_devices_5_a_bits_mask(tl_spi0_o.a_mask),
+    .io_devices_5_a_bits_data(tl_spi0_o.a_data),
+    .io_devices_5_a_bits_user_rsvd(tl_spi0_o.a_user.rsvd),
+    .io_devices_5_a_bits_user_instr_type(tl_spi0_o.a_user.instr_type),
+    .io_devices_5_a_bits_user_cmd_intg(tl_spi0_o.a_user.cmd_intg),
+    .io_devices_5_a_bits_user_data_intg(tl_spi0_o.a_user.data_intg),
+    .io_devices_5_d_ready(tl_spi0_o.d_ready)
+  );
 
   uart i_uart0(.clk_i(clk_i),
                .rst_ni(rst_ni),
@@ -308,226 +465,11 @@
 
   logic rst_cpu_n;
 
-  // Data and Response integrity generation for Kelvin Device Port
-  localparam int XbarSourceWidth = kelvin_tlul_pkg_128::TL_AIW;
-  localparam int XbarSourceCount = 1 << XbarSourceWidth;
-  logic [1 : 0] host_lane_reg[XbarSourceCount - 1 : 0];
-
-  logic [38 : 0] dev_ecc_full_0, dev_ecc_full_1, dev_ecc_full_2, dev_ecc_full_3;
-  logic [6 : 0] dev_ecc_0, dev_ecc_1, dev_ecc_2, dev_ecc_3;
-  logic [6 : 0] dev_selected_ecc;
-  tl_d2h_rsp_intg_t dev_rsp_metadata;
-  logic [63 : 0] dev_rsp_ecc_full;
-  logic [6 : 0] dev_rsp_ecc;
-
-  assign dev_ecc_0 = dev_ecc_full_0[38 : 32];
-  assign dev_ecc_1 = dev_ecc_full_1[38 : 32];
-  assign dev_ecc_2 = dev_ecc_full_2[38 : 32];
-  assign dev_ecc_3 = dev_ecc_full_3[38 : 32];
-  assign dev_rsp_ecc = dev_rsp_ecc_full[63 : 57];
-
-  prim_secded_inv_39_32_enc dev_enc0(.data_i(tl_kelvin_device_i.d_data[31 : 0]),
-                                     .data_o(dev_ecc_full_0));
-  prim_secded_inv_39_32_enc dev_enc1(.data_i(
-                                         tl_kelvin_device_i.d_data[63 : 32]),
-                                     .data_o(dev_ecc_full_1));
-  prim_secded_inv_39_32_enc dev_enc2(.data_i(
-                                         tl_kelvin_device_i.d_data[95 : 64]),
-                                     .data_o(dev_ecc_full_2));
-  prim_secded_inv_39_32_enc dev_enc3(.data_i(
-                                         tl_kelvin_device_i.d_data[127 : 96]),
-                                     .data_o(dev_ecc_full_3));
-
-  always_ff @(posedge clk_i or negedge rst_ni) begin
-    if (!rst_ni) begin
-      for (int i = 0; i < XbarSourceCount; i++) begin
-        host_lane_reg[i] <= 2'b0;
-      end
-    end else begin
-      // Capture lane index from Ibex data core requests
-      if (tl_ibex_core_d_o_xbar.a_valid && tl_ibex_core_d_i_xbar.a_ready) begin
-        unique case (4'hF)
-          tl_ibex_core_d_o_xbar.a_mask[3 : 0]:
-            host_lane_reg[tl_ibex_core_d_o_xbar.a_source] <= 2'b00;
-          tl_ibex_core_d_o_xbar.a_mask[7 : 4]:
-            host_lane_reg[tl_ibex_core_d_o_xbar.a_source] <= 2'b01;
-          tl_ibex_core_d_o_xbar.a_mask[11 : 8]:
-            host_lane_reg[tl_ibex_core_d_o_xbar.a_source] <= 2'b10;
-          tl_ibex_core_d_o_xbar.a_mask[15 : 12]:
-            host_lane_reg[tl_ibex_core_d_o_xbar.a_source] <= 2'b11;
-        endcase
-      end
-
-      // Capture lane index from Ibex instruction core requests
-      if (tl_ibex_core_i_o_xbar.a_valid && tl_ibex_core_i_i_xbar.a_ready) begin
-        unique case (4'hF)
-          tl_ibex_core_i_o_xbar.a_mask[3 : 0]:
-            host_lane_reg[tl_ibex_core_i_o_xbar.a_source] <= 2'b00;
-          tl_ibex_core_i_o_xbar.a_mask[7 : 4]:
-            host_lane_reg[tl_ibex_core_i_o_xbar.a_source] <= 2'b01;
-          tl_ibex_core_i_o_xbar.a_mask[11 : 8]:
-            host_lane_reg[tl_ibex_core_i_o_xbar.a_source] <= 2'b10;
-          tl_ibex_core_i_o_xbar.a_mask[15 : 12]:
-            host_lane_reg[tl_ibex_core_i_o_xbar.a_source] <= 2'b11;
-        endcase
-      end
-
-      // Capture lane index from Kelvin core requests
-      if (tl_kelvin_core_i.a_valid && tl_kelvin_core_o.a_ready) begin
-        unique case (4'hF)
-          tl_kelvin_core_i.a_mask[3 : 0]:
-            host_lane_reg[tl_kelvin_core_i.a_source] <= 2'b00;
-          tl_kelvin_core_i.a_mask[7 : 4]:
-            host_lane_reg[tl_kelvin_core_i.a_source] <= 2'b01;
-          tl_kelvin_core_i.a_mask[11 : 8]:
-            host_lane_reg[tl_kelvin_core_i.a_source] <= 2'b10;
-          tl_kelvin_core_i.a_mask[15 : 12]:
-            host_lane_reg[tl_kelvin_core_i.a_source] <= 2'b11;
-        endcase
-      end
-    end
-  end
-
-  always_comb begin
-    logic [1 : 0] lane_idx;
-    lane_idx = host_lane_reg[tl_from_kelvin_core.d_source];
-    case (lane_idx)
-      2'b00:
-        dev_selected_ecc = dev_ecc_0;
-      2'b01:
-        dev_selected_ecc = dev_ecc_1;
-      2'b10:
-        dev_selected_ecc = dev_ecc_2;
-      2'b11:
-        dev_selected_ecc = dev_ecc_3;
-      default:
-        dev_selected_ecc = dev_ecc_0;
-    endcase
-  end
-
-  assign dev_rsp_metadata = '{
-    opcode: tl_from_kelvin_core.d_opcode,
-    size: 2'b10,
-    error: tl_from_kelvin_core.d_error
-  };
-
-  prim_secded_inv_64_57_enc dev_enc_rsp(.data_i(
-                                            D2HRspMaxWidth'(dev_rsp_metadata)),
-                                        .data_o(dev_rsp_ecc_full));
-
   // Kelvin Core Instantiation
   logic kelvin_halted, kelvin_fault, kelvin_wfi;
-  kelvin_tlul_pkg_128::tl_d2h_t tl_from_kelvin_core;
-
   assign io_halted = kelvin_halted;
   assign io_fault = kelvin_fault;
 
-  // Assign all fields for the device D-channel from the Kelvin core's output,
-  // except for the user integrity bits, which we override with our generated
-  // ECC.
-  assign tl_kelvin_device_i.d_valid = tl_from_kelvin_core.d_valid;
-  assign tl_kelvin_device_i.d_opcode = tl_from_kelvin_core.d_opcode;
-  assign tl_kelvin_device_i.d_param = tl_from_kelvin_core.d_param;
-  assign tl_kelvin_device_i.d_size = tl_from_kelvin_core.d_size;
-  assign tl_kelvin_device_i.d_source = tl_from_kelvin_core.d_source;
-  assign tl_kelvin_device_i.d_sink = tl_from_kelvin_core.d_sink;
-  assign tl_kelvin_device_i.d_data = tl_from_kelvin_core.d_data;
-  assign tl_kelvin_device_i.d_error = tl_from_kelvin_core.d_error;
-  assign tl_kelvin_device_i.a_ready = tl_from_kelvin_core.a_ready;
-  assign tl_kelvin_device_i.d_user.rsp_intg = dev_rsp_ecc;
-  assign tl_kelvin_device_i.d_user.data_intg = dev_selected_ecc;
-
-  // Command and Data integrity generation for Kelvin Host Port
-  logic [38 : 0] host_a_data_ecc_full_0, host_a_data_ecc_full_1,
-                 host_a_data_ecc_full_2, host_a_data_ecc_full_3;
-  logic [6 : 0] host_a_data_ecc_0, host_a_data_ecc_1, host_a_data_ecc_2,
-                host_a_data_ecc_3;
-  logic [6 : 0] host_a_data_selected_ecc;
-  tl_h2d_cmd_intg_t host_a_cmd_metadata;
-  logic [63 : 0] host_a_cmd_ecc_full;
-  logic [6 : 0] host_a_cmd_ecc;
-
-  assign host_a_data_ecc_0 = host_a_data_ecc_full_0[38 : 32];
-  assign host_a_data_ecc_1 = host_a_data_ecc_full_1[38 : 32];
-  assign host_a_data_ecc_2 = host_a_data_ecc_full_2[38 : 32];
-  assign host_a_data_ecc_3 = host_a_data_ecc_full_3[38 : 32];
-  assign host_a_cmd_ecc = host_a_cmd_ecc_full[63 : 57];
-
-  prim_secded_inv_39_32_enc host_a_data_enc0(
-                                    .data_i(tl_kelvin_core_i.a_data[31 : 0]),
-                                    .data_o(host_a_data_ecc_full_0));
-  prim_secded_inv_39_32_enc host_a_data_enc1(
-                                    .data_i(tl_kelvin_core_i.a_data[63 : 32]),
-                                    .data_o(host_a_data_ecc_full_1));
-  prim_secded_inv_39_32_enc host_a_data_enc2(
-                                    .data_i(tl_kelvin_core_i.a_data[95 : 64]),
-                                    .data_o(host_a_data_ecc_full_2));
-  prim_secded_inv_39_32_enc host_a_data_enc3(
-                                    .data_i(tl_kelvin_core_i.a_data[127 : 96]),
-                                    .data_o(host_a_data_ecc_full_3));
-
-  logic [top_pkg::TL_DBW - 1 : 0] host_a_cmd_mask;
-
-  localparam logic [top_pkg::TL_AW - 1 : 0] Uart1BaseAddr = 32'h40010000;
-  logic [15 : 0] computed_mask;
-  logic [3 : 0] host_a_cmd_mask_4b;
-  logic [1 : 0] host_a_cmd_lane;
-  tl_h2d_cmd_intg_t host_a_cmd_payload;
-  logic [15 : 0] kelvin_core_i_a_mask;
-
-  always_comb begin
-    if (tl_kelvin_core_i.a_opcode == tlul_pkg::Get) begin
-      computed_mask = ((1 << (1 << tl_kelvin_core_i.a_size)) - 1)
-                      << (tl_kelvin_core_i.a_address[3 : 0]);
-    end else begin
-      computed_mask = kelvin_core_i_a_mask;
-    end
-    host_a_data_selected_ecc = 7'b0;
-    host_a_cmd_mask_4b = '0;
-    host_a_cmd_lane = '0;
-    // This is a priority mux, which is what we want.
-    if (|computed_mask[3 : 0]) begin
-      host_a_data_selected_ecc = host_a_data_ecc_0;
-      host_a_cmd_mask_4b = computed_mask[3 : 0];
-      host_a_cmd_lane = 2'b00;
-    end else if (|computed_mask[7 : 4]) begin
-      host_a_data_selected_ecc = host_a_data_ecc_1;
-      host_a_cmd_mask_4b = computed_mask[7 : 4];
-      host_a_cmd_lane = 2'b01;
-    end else if (|computed_mask[11 : 8]) begin
-      host_a_data_selected_ecc = host_a_data_ecc_2;
-      host_a_cmd_mask_4b = computed_mask[11 : 8];
-      host_a_cmd_lane = 2'b10;
-    end else if (|computed_mask[15 : 12]) begin
-      host_a_data_selected_ecc = host_a_data_ecc_3;
-      host_a_cmd_mask_4b = computed_mask[15 : 12];
-      host_a_cmd_lane = 2'b11;
-    end
-  end
-
-  // Manually pack the command integrity payload to match the 32-bit
-  // peripheral's view. The packing order is derived from the tl_h2d_cmd_intg_t
-  // struct definition.
-  assign host_a_cmd_payload = '{
-    instr_type: prim_mubi_pkg::MuBi4False,  // instr_type (4 bits)
-    addr: tl_kelvin_core_i.a_address,       // addr (32 bits)
-    opcode: tl_kelvin_core_i.a_opcode,      // opcode (3 bits)
-    mask: host_a_cmd_mask_4b                // mask (4 bits)
-  };
-  logic [31 : 0] dbg_uart1_addr = host_a_cmd_payload.addr;
-  logic [2 : 0] dbg_uart1_opcode = host_a_cmd_payload.opcode;
-  logic [3 : 0] dbg_uart1_mask = host_a_cmd_payload.mask;
-  logic [3 : 0] dbg_uart1_instr_type = host_a_cmd_payload.instr_type;
-
-  prim_secded_inv_64_57_enc host_a_cmd_enc(.data_i(H2DCmdMaxWidth'(
-                                               host_a_cmd_payload)),
-                                           .data_o(host_a_cmd_ecc_full));
-
-  assign tl_kelvin_core_i.a_user.cmd_intg = host_a_cmd_ecc;
-  assign tl_kelvin_core_i.a_user.data_intg = host_a_data_selected_ecc;
-  assign tl_kelvin_core_i.a_user.instr_type = prim_mubi_pkg::MuBi4False;
-  assign tl_kelvin_core_i.a_mask = computed_mask;
-
   RvvCoreMiniTlul
       i_kelvin_core(
               .io_clk(clk_i),
@@ -539,12 +481,12 @@
               .io_tl_host_a_bits_size(tl_kelvin_core_i.a_size),
               .io_tl_host_a_bits_source(tl_kelvin_core_i.a_source),
               .io_tl_host_a_bits_address(tl_kelvin_core_i.a_address),
-              .io_tl_host_a_bits_mask(kelvin_core_i_a_mask),
+              .io_tl_host_a_bits_mask(tl_kelvin_core_i.a_mask),
               .io_tl_host_a_bits_data(tl_kelvin_core_i.a_data),
               .io_tl_host_a_bits_user_rsvd(tl_kelvin_core_i.a_user.rsvd),
-              .io_tl_host_a_bits_user_instr_type(),
-              .io_tl_host_a_bits_user_cmd_intg(),
-              .io_tl_host_a_bits_user_data_intg(),
+              .io_tl_host_a_bits_user_instr_type(tl_kelvin_core_i.a_user.instr_type),
+              .io_tl_host_a_bits_user_cmd_intg(tl_kelvin_core_i.a_user.cmd_intg),
+              .io_tl_host_a_bits_user_data_intg(tl_kelvin_core_i.a_user.data_intg),
               .io_tl_host_d_ready(tl_kelvin_core_i.d_ready),
               .io_tl_host_d_valid(tl_kelvin_core_o.d_valid),
               .io_tl_host_d_bits_opcode(tl_kelvin_core_o.d_opcode),
@@ -574,17 +516,17 @@
               .io_tl_device_a_bits_user_data_intg(
                   tl_kelvin_device_o.a_user.data_intg),
               .io_tl_device_d_ready(tl_kelvin_device_o.d_ready),
-              .io_tl_device_a_ready(tl_from_kelvin_core.a_ready),
-              .io_tl_device_d_valid(tl_from_kelvin_core.d_valid),
-              .io_tl_device_d_bits_opcode(tl_from_kelvin_core.d_opcode),
-              .io_tl_device_d_bits_param(tl_from_kelvin_core.d_param),
-              .io_tl_device_d_bits_size(tl_from_kelvin_core.d_size),
-              .io_tl_device_d_bits_source(tl_from_kelvin_core.d_source),
-              .io_tl_device_d_bits_sink(tl_from_kelvin_core.d_sink),
-              .io_tl_device_d_bits_data(tl_from_kelvin_core.d_data),
-              .io_tl_device_d_bits_error(tl_from_kelvin_core.d_error),
-              .io_tl_device_d_bits_user_rsp_intg(),
-              .io_tl_device_d_bits_user_data_intg(),
+              .io_tl_device_a_ready(tl_kelvin_device_i.a_ready),
+              .io_tl_device_d_valid(tl_kelvin_device_i.d_valid),
+              .io_tl_device_d_bits_opcode(tl_kelvin_device_i.d_opcode),
+              .io_tl_device_d_bits_param(tl_kelvin_device_i.d_param),
+              .io_tl_device_d_bits_size(tl_kelvin_device_i.d_size),
+              .io_tl_device_d_bits_source(tl_kelvin_device_i.d_source),
+              .io_tl_device_d_bits_sink(tl_kelvin_device_i.d_sink),
+              .io_tl_device_d_bits_data(tl_kelvin_device_i.d_data),
+              .io_tl_device_d_bits_error(tl_kelvin_device_i.d_error),
+              .io_tl_device_d_bits_user_rsp_intg(tl_kelvin_device_i.d_user.rsp_intg),
+              .io_tl_device_d_bits_user_data_intg(tl_kelvin_device_i.d_user.data_intg),
               .io_halted(kelvin_halted),
               .io_fault(kelvin_fault),
               .io_wfi(kelvin_wfi),
@@ -594,8 +536,8 @@
   // Ibex Core Instantiation
   rv_core_ibex #(.PipeLine(1'b1),
                  .PMPEnable(1'b0))
-      i_ibex_core(.clk_i(clk_i),
-                  .rst_ni(rst_ni),
+      i_ibex_core(.clk_i(ibex_clk_i),
+                  .rst_ni(ibex_rst_ni),
                   .corei_tl_h_o(tl_ibex_core_i_o_32),
                   .corei_tl_h_i(tl_ibex_core_i_i_32),
                   .cored_tl_h_o(tl_ibex_core_d_o_32),
diff --git a/fpga/rules.bzl b/fpga/rules.bzl
deleted file mode 100644
index df307ad..0000000
--- a/fpga/rules.bzl
+++ /dev/null
@@ -1,43 +0,0 @@
-"""Starlark rules for FPGA development."""
-
-def _tlgen_impl(ctx):
-    """Implementation of the tlgen_rule."""
-    topcfg = ctx.file.topcfg
-    out_dir = ctx.actions.declare_directory(ctx.label.name + "_out")
-    core_file = ctx.actions.declare_file(ctx.label.name + "_out/" + "xbar_kelvin_soc_xbar.core")
-
-    ctx.actions.run(
-        outputs = [out_dir, core_file],
-        inputs = [topcfg],
-        executable = ctx.executable._tool,
-        arguments = [
-            "--topcfg",
-            topcfg.path,
-            "--outdir",
-            out_dir.path,
-        ],
-        progress_message = "Running tlgen and extracting core for %s" % topcfg.short_path,
-    )
-
-    return [
-        DefaultInfo(files = depset([out_dir])),
-        OutputGroupInfo(
-            core_file_output = depset([core_file, out_dir]),
-        ),
-    ]
-
-tlgen_rule = rule(
-    implementation = _tlgen_impl,
-    attrs = {
-        "topcfg": attr.label(
-            allow_single_file = True,
-            mandatory = True,
-            doc = "HJSON top-level configuration file.",
-        ),
-        "_tool": attr.label(
-            default = Label("//fpga:tlgen_tool"),
-            executable = True,
-            cfg = "exec",
-        ),
-    },
-)
diff --git a/fpga/sw/main.cc b/fpga/sw/main.cc
index 3ff561f..f9c7b8e 100644
--- a/fpga/sw/main.cc
+++ b/fpga/sw/main.cc
@@ -6,8 +6,15 @@
 
 extern "C" int main() {
   // Copy the embedded binary to Kelvin's ITCM at 0x0.
-  void *itcm_base = reinterpret_cast<void *>(static_cast<uintptr_t>(0x0));
-  memcpy(itcm_base, add_uint32_m1_bin, add_uint32_m1_bin_len);
+  // NB: Use this copy loop instead of memcpy to get word writes
+  // instead of byte writes.
+  uint32_t* itcm_base =
+      reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(0x0));
+  const uint32_t* add_uint32_m1_bin_u32 =
+      reinterpret_cast<const uint32_t*>(add_uint32_m1_bin);
+  for (unsigned int i = 0; i < add_uint32_m1_bin_len / 4; i++) {
+    *(itcm_base + i) = add_uint32_m1_bin_u32[i];
+  }
 
   // Kelvin run sequence
   volatile unsigned int *kelvin_reset_csr =
diff --git a/fpga/tl_config.hjson b/fpga/tl_config.hjson
deleted file mode 100644
index 82f5a83..0000000
--- a/fpga/tl_config.hjson
+++ /dev/null
@@ -1,95 +0,0 @@
-{
-  // Top-level configuration for the Kelvin SoC crossbar.
-  name: "kelvin_soc_xbar",
-  clock: "clk_i",
-  reset: "rst_ni",
-
-  // Define all the hosts (masters) and devices (slaves) in the system.
-  nodes: [
-    // Hosts (CPU Cores)
-    { name: "kelvin_core", type: "host", clock: "clk_i", reset: "rst_ni", addr_space: "asid0" },
-    { name: "ibex_core_i", type: "host", clock: "clk_i", reset: "rst_ni", addr_space: "asid0" },
-    { name: "ibex_core_d", type: "host", clock: "clk_i", reset: "rst_ni", addr_space: "asid0" },
-
-    // Devices (Peripherals and Memory)
-    {
-      name: "kelvin_device",
-      type: "device",
-      clock: "clk_i",
-      reset: "rst_ni",
-      xbar: false,
-      addr_range: [
-        { base_addrs: {"asid0": "0x00000000"}, size_byte: "0x2000" }, // 8kB
-        { base_addrs: {"asid0": "0x00010000"}, size_byte: "0x8000" }, // 32kB
-        { base_addrs: {"asid0": "0x00030000"}, size_byte: "0x1000" }  // 4kB
-      ]
-    },
-    {
-      name: "rom",
-      type: "device",
-      clock: "clk_i",
-      reset: "rst_ni",
-      xbar: false,
-      addr_range: [{ base_addrs: {"asid0": "0x10000000"}, size_byte: "0x8000" }] // 32kB
-    },
-    {
-      name: "sram",
-      type: "device",
-      clock: "clk_i",
-      reset: "rst_ni",
-      xbar: false,
-      addr_range: [{ base_addrs: {"asid0": "0x20000000"}, size_byte: "0x400000" }] // 4MB
-    },
-    {
-      name: "uart0",
-      type: "device",
-      clock: "clk_i",
-      reset: "rst_ni",
-      xbar: false,
-      addr_range: [{ base_addrs: {"asid0": "0x40000000"}, size_byte: "0x1000" }]
-    },
-    {
-      name: "uart1",
-      type: "device",
-      clock: "clk_i",
-      reset: "rst_ni",
-      xbar: false,
-      addr_range: [{ base_addrs: {"asid0": "0x40010000"}, size_byte: "0x1000" }]
-    },
-    {
-      name: "spi0",
-      type: "device",
-      clock: "spi_clk_i", // Using a separate clock for the SPI peripheral
-      reset: "rst_ni",
-      xbar: false,
-      addr_range: [{ base_addrs: {"asid0": "0x40020000"}, size_byte: "0x1000" }]
-    }
-  ],
-
-  // Define which hosts can access which devices.
-  connections: {
-    kelvin_core: [ "sram", "uart1", "spi0" ],
-    ibex_core_i: [ "rom", "sram" ],
-    ibex_core_d: [ "rom", "sram", "uart0", "kelvin_device" ]
-  },
-
-  // Define clock connections for all components.
-  clock_connections: {
-    clk_i: [
-      "kelvin_core",
-      "ibex_core_i",
-      "ibex_core_d",
-      "kelvin_device",
-      "rom",
-      "sram",
-      "uart0",
-      "uart1"
-    ],
-    spi_clk_i: [
-      "spi0"
-    ]
-  },
-  reset_connections: {
-    rst_ni: "rst_ni"
-  }
-}
diff --git a/hdl/chisel/src/kelvin/CoreTlul.scala b/hdl/chisel/src/kelvin/CoreTlul.scala
index 7c41c55..88ba92b 100644
--- a/hdl/chisel/src/kelvin/CoreTlul.scala
+++ b/hdl/chisel/src/kelvin/CoreTlul.scala
@@ -20,6 +20,7 @@
 class CoreTlul(p: Parameters, coreModuleName: String) extends RawModule {
     override val desiredName = coreModuleName + "Tlul"
     val memoryRegions = p.m
+    val tlul_p = new TLULParameters(p)
     val io = IO(new Bundle {
         val clk = Input(Clock())
         val rst_ni = Input(AsyncReset())
@@ -51,9 +52,22 @@
     hostBridge.io.axi <> coreAxi.io.axi_master
     deviceBridge.io.axi <> coreAxi.io.axi_slave
 
-    io.tl_host.a <> hostBridge.io.tl_a
+    val host_req_intg_gen = withClockAndReset(io.clk, (!io.rst_ni.asBool).asAsyncReset) {
+        Module(new RequestIntegrityGen(tlul_p))
+    }
+    io.tl_host.a.valid := hostBridge.io.tl_a.valid
+    hostBridge.io.tl_a.ready := io.tl_host.a.ready
+    host_req_intg_gen.io.a_i := hostBridge.io.tl_a.bits
+    host_req_intg_gen.io.a_i.user.instr_type := 9.U // MuBi4False
+    io.tl_host.a.bits := host_req_intg_gen.io.a_o
     hostBridge.io.tl_d <> io.tl_host.d
 
+    val device_rsp_intg_gen = withClockAndReset(io.clk, (!io.rst_ni.asBool).asAsyncReset) {
+        Module(new ResponseIntegrityGen(tlul_p))
+    }
     deviceBridge.io.tl_a <> io.tl_device.a
-    io.tl_device.d <> deviceBridge.io.tl_d
+    io.tl_device.d.valid := deviceBridge.io.tl_d.valid 
+    deviceBridge.io.tl_d.ready := io.tl_device.d.ready 
+    device_rsp_intg_gen.io.d_i := deviceBridge.io.tl_d.bits
+    io.tl_device.d.bits := device_rsp_intg_gen.io.d_o
 }
\ No newline at end of file