Create sencha top level bitstream target

- Decouple ROM software target builds from matcha to top level targets
- Expose config attribute in rom scrambling rule and default to matcha
  when no top level target is specified
- Split off sencha and matcha linker scripts for both test rom and
  puppeteer

Bypass-Presubmit-Reason: tested manual bitstream in edacloud for both matcha and sencha with the file renaming

Change-Id: I00312226c6185530bbe358efde418b2ec745848d
diff --git a/hw/bitstream/vivado/BUILD b/hw/bitstream/vivado/BUILD
index 437241b..608baed 100644
--- a/hw/bitstream/vivado/BUILD
+++ b/hw/bitstream/vivado/BUILD
@@ -5,6 +5,7 @@
 load("@lowrisc_opentitan//rules:fusesoc.bzl", "fusesoc_build")
 load("@lowrisc_opentitan//rules:splice.bzl", "bitstream_splice")
 load("@rules_pkg//pkg:tar.bzl", "pkg_tar")
+load("//rules:targets.bzl", "get_targets")
 
 package(default_visibility = ["//visibility:public"])
 
@@ -16,147 +17,158 @@
 # relative $(location ...) resolved labels is up 10 subdirectories.
 _PREFIX = "../../../../../../../../../.."
 
-_FPGA_NEXUS_TESTROM = "//sw/device/lib/testing/test_rom:test_rom_fpga_nexus_scr_vmem"
+TARGETS = get_targets()
 
-_FPGA_NEXUS_OTP_RMA = "//hw/top_matcha/data:otp_img_rma"
+_FPGA_NEXUS_TESTROM = ["//sw/device/lib/testing/test_rom:{}_test_rom_fpga_nexus_scr_vmem".format(target) for target in TARGETS]
 
-_FPGA_NEXUS_TESTROM_PATH = "{}/$(location {})".format(_PREFIX, _FPGA_NEXUS_TESTROM)
+_FPGA_NEXUS_OTP_RMA = ["//hw/top_{}/data:otp_img_rma".format(target) for target in TARGETS]
 
-_FPGA_NEXUS_OTP_RMA_PATH = "{}/$(location {})".format(_PREFIX, _FPGA_NEXUS_OTP_RMA)
+_FPGA_NEXUS_TESTROM_PATHS = ["{}/$(location {})".format(_PREFIX, TESTROM) for TESTROM in _FPGA_NEXUS_TESTROM]
+
+_FPGA_NEXUS_OTP_RMA_PATHS = ["{}/$(location {})".format(_PREFIX, OTP_IMG) for OTP_IMG in _FPGA_NEXUS_OTP_RMA]
+
+_FPGA_NEXUS_TARGET_INFO = zip(
+    get_targets(),
+    _FPGA_NEXUS_TESTROM,
+    _FPGA_NEXUS_TESTROM_PATHS,
+    _FPGA_NEXUS_OTP_RMA,
+    _FPGA_NEXUS_OTP_RMA_PATHS,
+)
 
 # Note: all of the targets are tagged with "manual" to prevent them from being
 # matched by bazel wildcards like "//...".  In order to build the bitstream,
 # you need to ask for it directly or by dependency via another rule, such as
 # a functest.
 
-fusesoc_build(
-    name = "fpga_nexus",
+[fusesoc_build(
+    name = "{}_fpga_nexus".format(target),
     testonly = True,
     srcs = [
         "//hw:all_files",
-        _FPGA_NEXUS_TESTROM,
-        _FPGA_NEXUS_OTP_RMA,
+        TESTROM,
+        OTP_IMG,
     ],
     cores = [
         "//:cores",
         "//hw/ip:BUILD",
-        "//hw/top_matcha:BUILD"
+        "//hw/top_{}:BUILD".format(target),
     ],
     data = ["@lowrisc_opentitan//hw/ip/otbn:all_files"],
     flags = [
-        "--BootRomInitFile=" + _FPGA_NEXUS_TESTROM_PATH,
-        "--OtpCtrlMemInitFile=" + _FPGA_NEXUS_OTP_RMA_PATH,
+        "--BootRomInitFile=" + TESTROM_PATH,
+        "--OtpCtrlMemInitFile=" + OTP_PATH,
     ],
     output_groups = {
-        "bitstream": ["synth-vivado/google_systems_chip_matcha_nexus_0.1.bit"],
+        "bitstream": ["synth-vivado/google_systems_chip_{}_nexus_0.1.bit".format(target)],
         "rom_mmi": ["synth-vivado/rom.mmi"],
         "otp_mmi": ["synth-vivado/otp.mmi"],
         "logs": [
-            "synth-vivado/google_systems_chip_matcha_nexus_0.1.runs/synth_1/runme.log",
-            "synth-vivado/google_systems_chip_matcha_nexus_0.1.runs/impl_1/runme.log",
+            "synth-vivado/google_systems_chip_{}_nexus_0.1.runs/synth_1/runme.log".format(target),
+            "synth-vivado/google_systems_chip_{}_nexus_0.1.runs/impl_1/runme.log".format(target),
             "synth-vivado/vivado.log",
-            "synth-vivado/google_systems_chip_matcha_nexus_0.1.runs/synth_1/chip_matcha_nexus_utilization_synth.rpt",
-            "synth-vivado/google_systems_chip_matcha_nexus_0.1.runs/impl_1/chip_matcha_nexus_power_routed.rpt",
-            "synth-vivado/google_systems_chip_matcha_nexus_0.1.runs/impl_1/chip_matcha_nexus_utilization_placed.rpt",
-            "synth-vivado/google_systems_chip_matcha_nexus_0.1.runs/impl_1/chip_matcha_nexus_bus_skew_routed.rpt",
-            "synth-vivado/google_systems_chip_matcha_nexus_0.1.runs/impl_1/chip_matcha_nexus_drc_routed.rpt",
-            "synth-vivado/google_systems_chip_matcha_nexus_0.1.runs/impl_1/chip_matcha_nexus_io_placed.rpt",
-            "synth-vivado/google_systems_chip_matcha_nexus_0.1.runs/impl_1/chip_matcha_nexus_timing_summary_routed.rpt",
-            "synth-vivado/google_systems_chip_matcha_nexus_0.1.runs/impl_1/chip_matcha_nexus_control_sets_placed.rpt",
-            "synth-vivado/google_systems_chip_matcha_nexus_0.1.runs/impl_1/chip_matcha_nexus_methodology_drc_routed.rpt",
-            "synth-vivado/google_systems_chip_matcha_nexus_0.1.runs/impl_1/chip_matcha_nexus_drc_opted.rpt",
-            "synth-vivado/google_systems_chip_matcha_nexus_0.1.runs/impl_1/chip_matcha_nexus_clock_utilization_routed.rpt",
-            "synth-vivado/google_systems_chip_matcha_nexus_0.1.runs/impl_1/chip_matcha_nexus_route_status.rpt",
-            "synth-vivado/google_systems_chip_matcha_nexus_0.1.runs/impl_1/utilization_kelvin.rpt",
+            "synth-vivado/google_systems_chip_{}_nexus_0.1.runs/synth_1/chip_{}_nexus_utilization_synth.rpt".format(target, target),
+            "synth-vivado/google_systems_chip_{}_nexus_0.1.runs/impl_1/chip_{}_nexus_power_routed.rpt".format(target, target),
+            "synth-vivado/google_systems_chip_{}_nexus_0.1.runs/impl_1/chip_{}_nexus_utilization_placed.rpt".format(target, target),
+            "synth-vivado/google_systems_chip_{}_nexus_0.1.runs/impl_1/chip_{}_nexus_bus_skew_routed.rpt".format(target, target),
+            "synth-vivado/google_systems_chip_{}_nexus_0.1.runs/impl_1/chip_{}_nexus_drc_routed.rpt".format(target, target),
+            "synth-vivado/google_systems_chip_{}_nexus_0.1.runs/impl_1/chip_{}_nexus_io_placed.rpt".format(target, target),
+            "synth-vivado/google_systems_chip_{}_nexus_0.1.runs/impl_1/chip_{}_nexus_timing_summary_routed.rpt".format(target, target),
+            "synth-vivado/google_systems_chip_{}_nexus_0.1.runs/impl_1/chip_{}_nexus_control_sets_placed.rpt".format(target, target),
+            "synth-vivado/google_systems_chip_{}_nexus_0.1.runs/impl_1/chip_{}_nexus_methodology_drc_routed.rpt".format(target, target),
+            "synth-vivado/google_systems_chip_{}_nexus_0.1.runs/impl_1/chip_{}_nexus_drc_opted.rpt".format(target, target),
+            "synth-vivado/google_systems_chip_{}_nexus_0.1.runs/impl_1/chip_{}_nexus_clock_utilization_routed.rpt".format(target, target),
+            "synth-vivado/google_systems_chip_{}_nexus_0.1.runs/impl_1/chip_{}_nexus_route_status.rpt".format(target, target),
+            "synth-vivado/google_systems_chip_{}_nexus_0.1.runs/impl_1/utilization_kelvin.rpt".format(target, target),
         ],
     },
-    systems = ["google:systems:chip_matcha_nexus"],
+    systems = ["google:systems:chip_{}_nexus".format(target)],
     tags = ["manual"],
     target = "synth",
     use_system_fusesoc = True,
-)
+) for target, TESTROM, TESTROM_PATH, OTP_IMG, OTP_PATH in _FPGA_NEXUS_TARGET_INFO]
 
-filegroup(
-    name = "fpga_nexus_test_rom",
+[filegroup(
+    name = "{}_fpga_nexus_test_rom".format(target),
     testonly = True,
-    srcs = [":fpga_nexus"],
+    srcs = [":{}_fpga_nexus".format(target)],
     output_group = "bitstream",
     tags = ["manual"],
-)
+) for target in TARGETS]
 
-filegroup(
-    name = "rom_mmi",
+[filegroup(
+    name = "{}_rom_mmi".format(target),
     testonly = True,
-    srcs = [":fpga_nexus"],
+    srcs = [":{}_fpga_nexus".format(target)],
     output_group = "rom_mmi",
     tags = ["manual"],
-)
+) for target in TARGETS]
 
-filegroup(
-    name = "otp_mmi",
+[filegroup(
+    name = "{}_otp_mmi".format(target),
     testonly = True,
-    srcs = [":fpga_nexus"],
+    srcs = [":{}_fpga_nexus".format(target)],
     output_group = "otp_mmi",
     tags = ["manual"],
 )
+for target in TARGETS]
 
-filegroup(
-    name = "logs",
+[filegroup(
+    name = "{}.logs".format(target),
     testonly = True,
-    srcs = [":fpga_nexus"],
+    srcs = [":{}_fpga_nexus".format(target)],
     output_group = "logs",
     tags = ["manual"],
-)
+) for target in TARGETS]
 
-bitstream_splice(
-    name = "fpga_nexus_mask_test_rom",
+[bitstream_splice(
+    name = "{}_fpga_nexus_mask_test_rom".format(target),
     testonly = True,
-    src = ":fpga_nexus_test_rom",
-    data = "//sw/device/lib/testing/test_rom:test_rom_fpga_nexus_scr_vmem",
-    meminfo = ":rom_mmi",
+    src = ":{}_fpga_nexus_test_rom".format(target),
+    data = "//sw/device/lib/testing/test_rom:{}_test_rom_fpga_nexus_scr_vmem".format(target),
+    meminfo = ":{}_rom_mmi".format(target),
     tags = ["manual"],
-)
+) for target in TARGETS]
 
-bitstream_splice(
-    name = "fpga_nexus_mask_puppeteer_rom",
+[bitstream_splice(
+    name = "{}_fpga_nexus_mask_puppeteer_rom".format(target),
     testonly = True,
-    src = ":fpga_nexus_test_rom",
-    data = "//sw/device/lib/testing/test_rom:puppeteer_rom_fpga_nexus_scr_vmem",
-    meminfo = ":rom_mmi",
+    src = ":{}_fpga_nexus_test_rom".format(target),
+    data = "//sw/device/lib/testing/test_rom:{}_puppeteer_rom_fpga_nexus_scr_vmem".format(target),
+    meminfo = ":{}_rom_mmi".format(target),
     tags = ["manual"],
-)
+) for target in TARGETS]
 
-bitstream_splice(
-    name = "fpga_nexus_mask_test_rom_no_otp",
+[bitstream_splice(
+    name = "{}_fpga_nexus_mask_test_rom_no_otp".format(target),
     testonly = True,
-    src = ":fpga_nexus_test_rom",
-    data = "//sw/device/lib/testing/test_rom:test_rom_no_otp_fpga_nexus_scr_vmem",
-    meminfo = ":rom_mmi",
+    src = ":{}_fpga_nexus_test_rom".format(target),
+    data = "//sw/device/lib/testing/test_rom:{}_test_rom_no_otp_fpga_nexus_scr_vmem".format(target),
+    meminfo = ":{}_rom_mmi".format(target),
     tags = ["manual"],
-)
+) for target in TARGETS]
 
-bitstream_splice(
-    name = "fpga_nexus_mask_test_rom_no_otp_empty",
+[bitstream_splice(
+    name = "{}_fpga_nexus_mask_test_rom_no_otp_empty".format(target),
     testonly = True,
-    src = ":fpga_nexus_mask_test_rom_no_otp",
-    data = "//hw/top_matcha/data:otp_img_empty",
-    meminfo = ":otp_mmi",
+    src = ":{}_fpga_nexus_mask_test_rom_no_otp".format(target),
+    data = "//hw/top_{}/data:otp_img_empty".format(target),
+    meminfo = ":{}_otp_mmi".format(target),
     tags = ["manual"],
-)
+) for target in TARGETS]
 
-pkg_tar(
-    name = "fpga_nexus_smoketest",
+[pkg_tar(
+    name = "{}_fpga_nexus_smoketest".format(target),
     testonly = True,
     srcs = [
-        ":fpga_nexus_mask_test_rom",
-        ":fpga_nexus_mask_test_rom_no_otp_empty",
-        ":logs",
-        ":otp_mmi",
-        ":rom_mmi",
+        ":{}_fpga_nexus_mask_test_rom".format(target),
+        ":{}_fpga_nexus_mask_test_rom_no_otp_empty".format(target),
+        ":{}_logs".format(target),
+        ":{}_otp_mmi".format(target),
+        ":{}_rom_mmi".format(target),
         "//sw/device/examples/hello_world_multicore:hello_world_multicore_sc_embedded_fpga_nexus_bin",
     ],
     extension = "tar.gz",
     mode = "0755",
     strip_prefix = "/",
     tags = ["manual"],
-)
+) for target in TARGETS]
diff --git a/hw/top_matcha/chip_matcha_nexus.core b/hw/top_matcha/chip_matcha_nexus.core
index 49153c9..099231e 100644
--- a/hw/top_matcha/chip_matcha_nexus.core
+++ b/hw/top_matcha/chip_matcha_nexus.core
@@ -44,7 +44,7 @@
   BootRomInitFile:
     datatype: str
     description: Scrambled boot ROM initialization file in 40 bit vmem hex format
-    default: "../../../../../../out/matcha/hw/rom_splices/test_rom_fpga_nexus.scr.39.vmem"
+    default: "../../../../../../out/matcha/hw/rom_splices/matcha_test_rom_fpga_nexus.scr.39.vmem"
     paramtype: vlogparam
   OtpCtrlMemInitFile:
     datatype: str
diff --git a/hw/top_matcha/dv/chip_sim_cfg.hjson b/hw/top_matcha/dv/chip_sim_cfg.hjson
index 740c38d..9429ba6 100644
--- a/hw/top_matcha/dv/chip_sim_cfg.hjson
+++ b/hw/top_matcha/dv/chip_sim_cfg.hjson
@@ -318,7 +318,7 @@
     }
     {
       name: sw_test_mode_test_rom
-      sw_images: ["//sw/device/lib/testing/test_rom:test_rom:0"]
+      sw_images: ["//sw/device/lib/testing/test_rom:matcha_test_rom:0"]
       en_run_modes: ["sw_test_mode_common"]
     }
     {
@@ -378,7 +378,7 @@
     }
     {
       name: sw_test_mode_test_rom_with_smc
-      sw_images: ["//sw/device/lib/testing/test_rom:test_rom:0"]
+      sw_images: ["//sw/device/lib/testing/test_rom:matcha_test_rom:0"]
       en_run_modes: ["sw_test_mode_common_with_smc"]
     }
     {
diff --git a/hw/top_matcha/dv/verilator/verilator_sim_cfg.hjson b/hw/top_matcha/dv/verilator/verilator_sim_cfg.hjson
index 65c4a27..c19c874 100644
--- a/hw/top_matcha/dv/verilator/verilator_sim_cfg.hjson
+++ b/hw/top_matcha/dv/verilator/verilator_sim_cfg.hjson
@@ -56,7 +56,7 @@
   run_modes: [
     {
       name: sw_test_mode
-      sw_images: ["//sw/device/lib/testing/test_rom:test_rom:0",
+      sw_images: ["//sw/device/lib/testing/test_rom:matcha_test_rom:0",
                   "//hw/ip/otp_ctrl/data:img_rma:3"]
       run_opts: [
         // The following shell snippet converts the SW images specification to what's
diff --git a/hw/top_sencha/chip_sencha_nexus.core b/hw/top_sencha/chip_sencha_nexus.core
index fc0e7df..465b931 100644
--- a/hw/top_sencha/chip_sencha_nexus.core
+++ b/hw/top_sencha/chip_sencha_nexus.core
@@ -44,7 +44,7 @@
   BootRomInitFile:
     datatype: str
     description: Scrambled boot ROM initialization file in 40 bit vmem hex format
-    default: "../../../../../../out/sencha/hw/rom_splices/test_rom_fpga_nexus.scr.39.vmem"
+    default: "../../../../../../out/sencha/hw/rom_splices/sencha_test_rom_fpga_nexus.scr.39.vmem"
     paramtype: vlogparam
   OtpCtrlMemInitFile:
     datatype: str
diff --git a/hw/top_sencha/dv/chip_sim_cfg.hjson b/hw/top_sencha/dv/chip_sim_cfg.hjson
index 8d65c94..7a35131 100644
--- a/hw/top_sencha/dv/chip_sim_cfg.hjson
+++ b/hw/top_sencha/dv/chip_sim_cfg.hjson
@@ -318,7 +318,7 @@
     }
     {
       name: sw_test_mode_test_rom
-      sw_images: ["//sw/device/lib/testing/test_rom:test_rom:0"]
+      sw_images: ["//sw/device/lib/testing/test_rom:sencha_test_rom:0"]
       en_run_modes: ["sw_test_mode_common"]
     }
     {
@@ -378,7 +378,7 @@
     }
     {
       name: sw_test_mode_test_rom_with_smc
-      sw_images: ["//sw/device/lib/testing/test_rom:test_rom:0"]
+      sw_images: ["//sw/device/lib/testing/test_rom:sencha_test_rom:0"]
       en_run_modes: ["sw_test_mode_common_with_smc"]
     }
     {
diff --git a/hw/top_sencha/dv/verilator/verilator_sim_cfg.hjson b/hw/top_sencha/dv/verilator/verilator_sim_cfg.hjson
index 46e0f73..b76a742 100644
--- a/hw/top_sencha/dv/verilator/verilator_sim_cfg.hjson
+++ b/hw/top_sencha/dv/verilator/verilator_sim_cfg.hjson
@@ -56,7 +56,7 @@
   run_modes: [
     {
       name: sw_test_mode
-      sw_images: ["//sw/device/lib/testing/test_rom:test_rom:0",
+      sw_images: ["//sw/device/lib/testing/test_rom:sencha_test_rom:0",
                   "//hw/ip/otp_ctrl/data:img_rma:3"]
       run_opts: [
         // The following shell snippet converts the SW images specification to what's
diff --git a/hw/top_sencha/physical_pads.core b/hw/top_sencha/physical_pads.core
new file mode 100644
index 0000000..f2c1a1e
--- /dev/null
+++ b/hw/top_sencha/physical_pads.core
@@ -0,0 +1,46 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:systems:physical_pads:0.1"
+description: "Open-source place-holder for physical pads"
+
+filesets:
+  files_rtl:
+    depend:
+      - lowrisc:prim:assert
+    files:
+      - rtl/physical_pads.sv
+    file_type: systemVerilogSource
+
+  files_verilator_waiver:
+    depend:
+      # common waivers
+      - lowrisc:lint:common
+      - lowrisc:lint:comportable
+    files:
+      # - lint/physical_pads.vlt
+    file_type: vlt
+
+  files_ascentlint_waiver:
+    depend:
+      # common waivers
+      - lowrisc:lint:common
+      - lowrisc:lint:comportable
+    files:
+      # - lint/physical_pads.waiver
+    file_type: waiver
+
+  files_veriblelint_waiver:
+    depend:
+      # common waivers
+      - lowrisc:lint:common
+      - lowrisc:lint:comportable
+
+targets:
+  default: &default_target
+    filesets:
+      - tool_verilator   ? (files_verilator_waiver)
+      - tool_ascentlint  ? (files_ascentlint_waiver)
+      - tool_veriblelint ? (files_veriblelint_waiver)
+      - files_rtl
diff --git a/hw/top_sencha/rtl/clkgen_xilultrascaleplus.sv b/hw/top_sencha/rtl/clkgen_xilultrascaleplus.sv
new file mode 100644
index 0000000..58ba16b
--- /dev/null
+++ b/hw/top_sencha/rtl/clkgen_xilultrascaleplus.sv
@@ -0,0 +1,147 @@
+// Copyright 2024 Google LLC
+// Copyright lowRISC contributors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+module clkgen_xilultrascaleplus # (
+  // Add BUFG if not done by downstream logic
+  parameter bit AddClkBuf = 1
+) (
+  input  clk_i,
+  input  clk_n_i,
+  input  rst_ni,
+  input  srst_ni,
+  output clk_main_o,
+  output clk_48MHz_o,
+  output clk_aon_o,
+  output rst_no
+);
+  logic locked_pll;
+  logic io_clk_buf;
+  logic io_rst_buf_n;
+  logic clk_10_buf;
+  logic clk_10_unbuf;
+  logic clk_fb_buf;
+  logic clk_fb_unbuf;
+  logic clk_48_buf;
+  logic clk_48_unbuf;
+  logic clk_aon_buf;
+  logic clk_aon_unbuf;
+  logic clk_ibufds_o;
+
+  // Input IBUFDS conver diff-pair to single-end
+  IBUFDS clk_ibufds (
+    .I  (clk_i),
+    .IB (clk_n_i),
+    .O  (clk_ibufds_o)
+  );
+
+  MMCME2_ADV #(
+    .BANDWIDTH            ("OPTIMIZED"),
+    .COMPENSATION         ("ZHOLD"),
+    .STARTUP_WAIT         ("FALSE"),
+    .DIVCLK_DIVIDE        (1),
+    .CLKFBOUT_MULT_F      (12.000),
+    .CLKFBOUT_PHASE       (0.000),
+    .CLKOUT0_DIVIDE_F     (120.0),
+    .CLKOUT0_PHASE        (0.000),
+    .CLKOUT0_DUTY_CYCLE   (0.500),
+    .CLKOUT1_DIVIDE       (25),
+    .CLKOUT1_PHASE        (0.000),
+    .CLKOUT1_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),
+    .CLKOUT4_PHASE        (0.000),
+    .CLKOUT4_DUTY_CYCLE   (0.500),
+    .CLKOUT4_CASCADE      ("TRUE"),
+    .CLKOUT6_DIVIDE       (120),
+    .CLKIN1_PERIOD        (10.000)
+  ) pll (
+    .CLKFBOUT            (clk_fb_unbuf),
+    .CLKFBOUTB           (),
+    .CLKOUT0             (clk_10_unbuf),
+    .CLKOUT0B            (),
+    .CLKOUT1             (clk_48_unbuf),
+    .CLKOUT1B            (),
+    .CLKOUT2             (),
+    .CLKOUT2B            (),
+    .CLKOUT3             (),
+    .CLKOUT3B            (),
+    .CLKOUT4             (clk_aon_unbuf),
+    .CLKOUT5             (),
+    .CLKOUT6             (),
+     // Input clock control
+    .CLKFBIN             (clk_fb_buf),
+    .CLKIN1              (clk_ibufds_o),
+    .CLKIN2              (1'b0),
+     // Tied to always select the primary input clock
+    .CLKINSEL            (1'b1),
+    // Ports for dynamic reconfiguration
+    .DADDR               (7'h0),
+    .DCLK                (1'b0),
+    .DEN                 (1'b0),
+    .DI                  (16'h0),
+    .DO                  (),
+    .DRDY                (),
+    .DWE                 (1'b0),
+    // Phase shift signals
+    .PSCLK               (1'b0),
+    .PSEN                (1'b0),
+    .PSINCDEC            (1'b0),
+    .PSDONE              (),
+    // Other control and status signals
+    .CLKFBSTOPPED        (),
+    .CLKINSTOPPED        (),
+    .LOCKED              (locked_pll),
+    .PWRDWN              (1'b0),
+    // Do not reset MMCM on external reset, otherwise ILA disconnects at a reset
+    .RST                 (1'b0));
+
+  // output buffering
+  BUFGCE clk_fb_bufgce (
+    .I (clk_fb_unbuf),
+    .O (clk_fb_buf)
+  );
+
+  BUFGCE clk_aon_bufgce (
+    .I (clk_aon_unbuf),
+    .O (clk_aon_buf)
+  );
+
+  if (AddClkBuf == 1) begin : gen_clk_bufs
+    BUFGCE clk_10_bufgce (
+      .I (clk_10_unbuf),
+      .O (clk_10_buf)
+    );
+
+    BUFGCE clk_48_bufgce (
+      .I (clk_48_unbuf),
+      .O (clk_48_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;
+  end
+
+  // outputs
+  // clock
+  assign clk_main_o = clk_10_buf;
+  assign clk_48MHz_o = clk_48_buf;
+  assign clk_aon_o = clk_aon_buf;
+
+  // reset
+  assign rst_no = locked_pll & rst_ni & srst_ni;
+endmodule
diff --git a/hw/top_sencha/rtl/physical_pads.sv b/hw/top_sencha/rtl/physical_pads.sv
new file mode 100644
index 0000000..4d7cf8b
--- /dev/null
+++ b/hw/top_sencha/rtl/physical_pads.sv
@@ -0,0 +1,32 @@
+// Copyright 2024 Google LLC
+// Copyright lowRISC contributors
+//
+// 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.
+
+//
+// This is a physical pads placeholder for the open-source views.
+// Special physical pad outputs and power sequencing signals are just tied off.
+
+`include "prim_assert.sv"
+
+module physical_pads
+  import prim_pad_wrapper_pkg::*;
+#(
+  parameter int NIoBanks = 4
+) (
+  output pad_pok_t [NIoBanks-1:0] pad_pok_o
+);
+
+  assign pad_pok_o = '0;
+
+endmodule : physical_pads
diff --git a/hw/top_sencha/util/vivado_hook_opt_design_post.tcl b/hw/top_sencha/util/vivado_hook_opt_design_post.tcl
new file mode 100644
index 0000000..98b7fad
--- /dev/null
+++ b/hw/top_sencha/util/vivado_hook_opt_design_post.tcl
@@ -0,0 +1,33 @@
+# Copyright 2024 Google LLC
+# Copyright 2023 lowRISC contributors
+#
+# 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.
+
+# Hook to check BRAM implementation for Boot ROM. This is required for Boot ROM splicing.
+
+send_msg "Designcheck 2-1" INFO "Checking if Boot ROM is mapped to BRAM."
+
+if {[catch [get_cells -hierarchical -filter { NAME =~  "*u_rom_ctrl*u_rom*rdata_o_reg_0" && PRIMITIVE_TYPE =~ BLOCKRAM.*.* }]]\
+ && [catch [get_cells -hierarchical -filter { NAME =~  "*u_rom_ctrl*u_rom*rdata_o_reg_1" && PRIMITIVE_TYPE =~ BLOCKRAM.*.* }]]\
+ && [catch [get_cells -hierarchical -filter { NAME =~  "*u_rom_ctrl*u_rom*rdata_o_reg_2" && PRIMITIVE_TYPE =~ BLOCKRAM.*.* }]]\
+ && [catch [get_cells -hierarchical -filter { NAME =~  "*u_rom_ctrl*u_rom*rdata_o_reg_3" && PRIMITIVE_TYPE =~ BLOCKRAM.*.* }]]\
+ && [catch [get_cells -hierarchical -filter { NAME =~  "*u_rom_ctrl*u_rom*rdata_o_reg_4" && PRIMITIVE_TYPE =~ BLOCKRAM.*.* }]]\
+ && [catch [get_cells -hierarchical -filter { NAME =~  "*u_rom_ctrl*u_rom*rdata_o_reg_5" && PRIMITIVE_TYPE =~ BLOCKRAM.*.* }]]\
+ && [catch [get_cells -hierarchical -filter { NAME =~  "*u_rom_ctrl*u_rom*rdata_o_reg_6" && PRIMITIVE_TYPE =~ BLOCKRAM.*.* }]]\
+ && [catch [get_cells -hierarchical -filter { NAME =~  "*u_rom_ctrl*u_rom*rdata_o_reg_7" && PRIMITIVE_TYPE =~ BLOCKRAM.*.* }]]\
+ && [catch [get_cells -hierarchical -filter { NAME =~  "*u_rom_ctrl*u_rom*rdata_o_reg_8" && PRIMITIVE_TYPE =~ BLOCKRAM.*.* }]]\
+ && [catch [get_cells -hierarchical -filter { NAME =~  "*u_rom_ctrl*u_rom*rdata_o_reg_9" && PRIMITIVE_TYPE =~ BLOCKRAM.*.* }]] } {
+  send_msg "Designcheck 2-2" INFO "BRAM implementation found for Boot ROM."
+} else {
+  send_msg "Designcheck 2-3" ERROR "BRAM implementation not found for Boot ROM."
+}
diff --git a/hw/top_sencha/util/vivado_hook_synth_design_pre.tcl b/hw/top_sencha/util/vivado_hook_synth_design_pre.tcl
new file mode 100644
index 0000000..c8cb74e
--- /dev/null
+++ b/hw/top_sencha/util/vivado_hook_synth_design_pre.tcl
@@ -0,0 +1,34 @@
+# Copyright 2024 Google LLC
+# Copyright lowRISC contributors
+#
+# 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.
+
+# Change the severity of some messages.
+
+# Abort if the boot ROM init file cannot be found. This is normally just a critical warning
+# which is easily overlooked. The bitstream can still be generated but is not functional.
+set_msg_config -id {[Synth 8-4445]} -new_severity ERROR
+
+# Abort upon inferring latches. This is normally just a warning. We want to avoid that
+# code inferring latches ends up in the repo in the first place.
+set_msg_config -id {[Synth 8-327]} -new_severity ERROR
+
+# Abort if a create_clock command fails. This typically happens if anchor points for clock
+# constraints inside the design change. The failure is normally just reported as a critical
+# warning in batch mode which is easily overlooked. The design might still work but some clocks
+# will be unconstrained which can lead to other problems later on.
+set_msg_config -id {[Vivado 12-4739]} -new_severity ERROR
+
+# Abort if pblock constraints lose their target cells. This can happen if hierarchies change and
+# the constraint doesn't get updated.
+set_msg_config -id {[Vivado 12-1433]} -new_severity ERROR
diff --git a/hw/top_sencha/util/vivado_hook_write_bitstream_pre.tcl b/hw/top_sencha/util/vivado_hook_write_bitstream_pre.tcl
new file mode 100644
index 0000000..2f87a1f
--- /dev/null
+++ b/hw/top_sencha/util/vivado_hook_write_bitstream_pre.tcl
@@ -0,0 +1,197 @@
+# Copyright 2024 Google LLC
+# Copyright lowRISC contributors
+#
+# 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.
+
+send_msg "Designcheck 1-1" INFO "Checking design"
+
+# Ensure the design meets timing
+set slack_ns [get_property SLACK [get_timing_paths -delay_type min_max]]
+send_msg "Designcheck 1-2" INFO "Slack is ${slack_ns} ns."
+
+if {
+    [info exists ::env(VIVADO_FAIL_ON_TIMING)]
+    && $::env(VIVADO_FAIL_ON_TIMING) != 0
+} then {
+    if [expr {$slack_ns < 0}] {
+        send_msg "Designcheck 1-3" ERROR "Timing failed. Slack is ${slack_ns} ns."
+    }
+}
+# Write additional reports
+report_utilization -cells [get_cells top_sencha/u_ml_top/u_kelvin] -file utilization_kelvin.rpt
+
+
+# Enable bitstream identification via USR_ACCESS register.
+set_property BITSTREAM.CONFIG.USR_ACCESS TIMESTAMP [current_design]
+
+# Generate an MMI file for the given BRAM cells.
+#
+# Args:
+#   filename:            Path to the output file.
+#   brams:               A list of BRAM cells.
+#   mem_type:            The BRAM type, e.g. "RAMB36".
+#   fake_word_width:     If non-zero, pretend that $brams covers
+#                        `fake_word_width` bits. Influences the values of the
+#                        MMI's <AddressSpace> and <DataWidth> tags.
+#   addr_end_multiplier: A coefficient applied to the address space. Influences
+#                        the values of the MMI's <AddressSpace> and
+#                        <AddressRange> tags.
+#   designtask_count:    A number used for logging with `send_msg`.
+proc generate_mmi {filename brams mem_type fake_word_width addr_end_multiplier designtask_count} {
+    send_msg "${designtask_count}-1" INFO "Dumping MMI to ${filename}"
+
+    if {[llen $brams] == 0} {
+        send_msg "${designtask_count}-1" INFO "Cannot make MMI for zero BRAMs"
+        return
+    }
+
+    set workroot [file dirname [info script]]
+    set filepath "${workroot}/${filename}"
+    set fileout [open $filepath "w"]
+
+    set fake_slice_width [expr $fake_word_width / [llen $brams]]
+
+    # Calculate the overall address space.
+    set space 0
+    foreach inst [lsort -dictionary $brams] {
+        set slice_begin [get_property ram_slice_begin [get_cells $inst]]
+        set slice_end [get_property ram_slice_end [get_cells $inst]]
+        if {$slice_begin eq {} || $slice_end eq {}} {
+            send_msg "${designtask_count}-2" ERROR "Extraction of ${filename} information failed."
+        }
+        set slice_width [expr {$slice_end - $slice_begin + 1}]
+        if {$slice_width < $fake_slice_width} {
+            set slice_end [expr {$slice_begin + $fake_slice_width - 1}]
+            set slice_width $fake_slice_width
+        }
+        set addr_begin [get_property ram_addr_begin [get_cells $inst]]
+        set addr_end [get_property ram_addr_end [get_cells $inst]]
+        if {$addr_begin eq {} || $addr_end eq {}} {
+            send_msg "${designtask_count}-3" ERROR "Extraction of ${filename} MMI information failed."
+        }
+
+        # Calculate total number of bits.
+        set space [expr {$space + ($addr_end - $addr_begin + 1) * $slice_width}]
+        set last_slice_width $slice_width
+    }
+    set space [expr {($space * $addr_end_multiplier / 8) - 1}]
+
+    # Generate the MMI.
+    puts $fileout "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+    puts $fileout "<MemInfo Version=\"1\" Minor=\"1\">"
+    puts $fileout "  <Processor Endianness=\"Little\" InstPath=\"dummy\">"
+    puts $fileout "  <AddressSpace Name=\"dummy_addrspace\" Begin=\"0\" End=\"$space\">"
+    puts $fileout "      <BusBlock>"
+
+    set loc_prefix "${mem_type}_"
+
+    set part [get_property PART [current_design]]
+    foreach inst [lsort -dictionary $brams] {
+        set loc [get_property LOC [get_cells $inst]]
+        set loc [string trimleft $loc $loc_prefix]
+        set slice_begin [get_property ram_slice_begin [get_cells $inst]]
+        set slice_end [get_property ram_slice_end [get_cells $inst]]
+        set slice_width [expr {$slice_end - $slice_begin + 1}]
+        if {$slice_width < $fake_slice_width} {
+            set slice_end [expr {$slice_begin + $fake_slice_width - 1}]
+            set slice_width $fake_slice_width
+        }
+        set addr_begin [get_property ram_addr_begin [get_cells $inst]]
+        set addr_end [get_property ram_addr_end [get_cells $inst]]
+        set addr_end [expr {($addr_end + 1) * $addr_end_multiplier - 1}]
+        puts $fileout "        <BitLane MemType=\"$mem_type\" Placement=\"$loc\">"
+        puts $fileout "          <DataWidth MSB=\"$slice_end\" LSB=\"$slice_begin\"/>"
+        puts $fileout "          <AddressRange Begin=\"$addr_begin\" End=\"$addr_end\"/>"
+        puts $fileout "          <Parity ON=\"false\" NumBits=\"0\"/>"
+        puts $fileout "        </BitLane>"
+    }
+    puts $fileout "      </BusBlock>"
+    puts $fileout "    </AddressSpace>"
+    puts $fileout "  </Processor>"
+    puts $fileout "<Config>"
+    puts $fileout "  <Option Name=\"Part\" Val=\"$part\"/>"
+    puts $fileout "</Config>"
+    puts $fileout "</MemInfo>"
+    close $fileout
+    send_msg "${designtask_count}-4" INFO "MMI dumped to ${filepath}"
+}
+
+# Dump INIT_XX strings for the given BRAMs to an output file.
+#
+# In the output file, the BRAMs and their INIT_XX strings will be sorted in
+# increasing order. This proc is a time-saver because the Vivado GUI's property
+# viewer does not sort the INIT_XX strings numerically.
+#
+# Args:
+#   filename:         Where to write
+#   brams:            A list of BRAM cells.
+#   designtask_count: A number used for logging with `send_msg`.
+proc dump_init_strings {filename brams designtask_count} {
+    # For each OTP BRAM, dump all the INIT_XX strings.
+    send_msg "${designtask_count}-1" INFO "Dumping INIT_XX strings to ${filename}"
+
+    set workroot [file dirname [info script]]
+    set filepath "${workroot}/${filename}"
+    set fileout [open $filepath "w"]
+
+    foreach inst [lsort -dictionary $brams] {
+        set bram [get_cells $inst]
+
+        set loc [get_property LOC $bram]
+        puts $fileout "LOC: $loc"
+
+        set init_count 0
+        while 1 {
+            set key [format "INIT_%.2X" $init_count]
+            if { [llength [list_property $bram $key]] eq 0 } {
+                break
+            }
+            set val [get_property $key $bram]
+            puts $fileout "$key $val"
+            incr init_count
+        }
+
+        puts $fileout ""
+    }
+    close $fileout
+    send_msg "${designtask_count}-4" INFO "INIT_XX strings dumped to ${filepath}"
+}
+
+# The scrambled Boot ROM is actually 39 bits wide, but we need to pretend that
+# it's 40 bits, or else we will be unable to encode our ROM data in a MEM file
+# that updatemem will understand.
+#
+# Suppose we did not pad the width, leaving it at 39 bits. Now, if we encode a
+# word as a 10-digit hex string, updatemem would splice an additional zero bit
+# into the bitstream because each hex digit is strictly 4 bits. If we wrote four
+# words at a time, as a 39-digit hex string (39*4 is nicely divisible by 4),
+# updatemem would fail to parse the hex string, saying something like "Data
+# segment starting at 0x00000000, has exceeded data limits." The longest hex
+# string it will accept is 16 digits, or 64 bits.
+#
+# A hack that works is to pretend the data width is actually 40 bits. Updatemem
+# seems to write that extra zero bit into the ether without complaint.
+set rom_brams [split [get_cells -hierarchical -filter { PRIMITIVE_TYPE =~ BLOCKRAM.BRAM.* && NAME =~ *u_rom_ctrl*}] " "]
+generate_mmi "rom.mmi" $rom_brams "RAMB36" 40 1 1
+
+# OTP does not require faking the word width, but it has its own quirk. It seems
+# each 22-bit OTP word is followed by 15 zero words. The MMI's <AddressSpace>
+# and <AddressRange> tags need to account for this or else updatemem will think
+# that its data input overruns the address space. The workaround is to pretend
+# the address space is 16 times larger than we would normally compute.
+set otp_brams [split [get_cells -hierarchical -filter { PRIMITIVE_TYPE =~ BLOCKRAM.BRAM.* && NAME =~ *u_otp_ctrl*}] " "]
+generate_mmi "otp.mmi" $otp_brams "RAMB18" 0 16 2
+
+# For debugging purposes, dump the INIT_XX strings for ROM and OTP.
+dump_init_strings "rom_init_strings.txt" $rom_brams 3
+dump_init_strings "otp_init_strings.txt" $otp_brams 4
diff --git a/hw/top_sencha/util/vivado_setup_hooks.tcl b/hw/top_sencha/util/vivado_setup_hooks.tcl
new file mode 100644
index 0000000..cd51615
--- /dev/null
+++ b/hw/top_sencha/util/vivado_setup_hooks.tcl
@@ -0,0 +1,45 @@
+# Copyright 2024 Google LLC
+# Copyright lowRISC contributors
+#
+# 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.
+
+# Setup hook scripts, to be called at various stages during the build process
+# See Xilinx UG 894 ("Using Tcl Scripting") for documentation.
+
+# fusesoc-generated workroot containing the Vivado project file
+set workroot [pwd]
+
+# Pre synthesize design hook
+set_property STEPS.SYNTH_DESIGN.TCL.PRE "${workroot}/vivado_hook_synth_design_pre.tcl" [get_runs synth_1]
+
+# add placer directive for SLL balance due to congestion detected on SLR crossing.
+set_property STEPS.PLACE_DESIGN.ARGS.DIRECTIVE SSI_BalanceSLLs [get_runs impl_1]
+
+# Post opt design hook
+# Following directive ExploreWithAggressiveHoldFix" will increase compile time a lot,
+# comment out for now just for future hold time debug reference.
+#set_property STEPS.POST_ROUTE_PHYS_OPT_DESIGN.ARGS.DIRECTIVE ExploreWithAggressiveHoldFix [get_runs impl_1]
+set_property STEPS.PHYS_OPT_DESIGN.IS_ENABLED true [get_runs impl_1]
+set_property -name {STEPS.PHYS_OPT_DESIGN.ARGS.MORE OPTIONS} -value -hold_fix -objects [get_runs impl_1]
+set_property STEPS.OPT_DESIGN.TCL.POST "${workroot}/vivado_hook_opt_design_post.tcl" [get_runs impl_1]
+
+# TODO: This hook is not getting called by Vivado when running through our
+# fusesoc flow (it gets called when writing a bitstream through the GUI).
+# Requires an update to edalize, see https://github.com/olofk/edalize/pull/60.
+#set_property STEPS.WRITE_BITSTREAM.TCL.PRE "${workroot}/vivado_hook_write_bitstream_pre.tcl" [get_runs impl_1]
+
+# As workaround, we use the post route design hook, which gets called.
+set_property STEPS.ROUTE_DESIGN.TCL.POST "${workroot}/vivado_hook_write_bitstream_pre.tcl" [get_runs impl_1]
+
+# Set synth.xdc to only be used for synthesis (initial implementation is to force URAM instead of BRAM)
+set_property used_in_implementation false [filter -regexp [get_files -of [get_filesets constrs_1]] {NAME=~".*\/synth.xdc"}]
diff --git a/rules/matcha.bzl b/rules/matcha.bzl
index 49fac79..9e1c1d6 100644
--- a/rules/matcha.bzl
+++ b/rules/matcha.bzl
@@ -88,10 +88,10 @@
             inputs = [
                 src,
                 ctx.executable._scramble_tool,
-                ctx.file._config,
+                ctx.file.config,
             ],
             arguments = [
-                ctx.file._config.path,
+                ctx.file.config.path,
                 src.path,
                 scrambled.path,
             ],
@@ -111,7 +111,7 @@
             executable = True,
             cfg = "exec",
         ),
-        "_config": attr.label(
+        "config": attr.label(
             default = "@//hw/top_matcha:top_gen_rom_ctrl_hjson",
             allow_single_file = True,
         ),
@@ -174,6 +174,7 @@
           Containing all targets across all devices for the above generated rules.
     """
     deps = kwargs.pop("deps", [])
+    top_target = kwargs.pop("top_target", "matcha")
 
     # Place the default copts first to allow per-target override.
     copts = MATCHA_COPTS + kwargs.pop("copts", [])
@@ -216,12 +217,14 @@
         # Generate Scrambled ROM VMEM
         scr_vmem_name = "{}_scr_vmem".format(devname)
         dev_targets.append(":" + scr_vmem_name)
+        top_gen_hjson_target = "@//hw/top_{}:top_gen_rom_ctrl_hjson".format(top_target)
         elf_to_scrambled_rom_vmem(
             name = scr_vmem_name,
             srcs = [elf_name],
             platform = platform,
             testonly = testonly,
             tags = tags,
+            config = top_gen_hjson_target,
         )
 
         # Create a filegroup with just the current device's targets.
diff --git a/rules/matcha_test.bzl b/rules/matcha_test.bzl
index 115413b..94030f7 100644
--- a/rules/matcha_test.bzl
+++ b/rules/matcha_test.bzl
@@ -26,7 +26,7 @@
         sec_flash_binary,
         smc_flash_binary = "@//sw/device/tests/smc:simple_smc",
         ml_flash_binary = None,
-        rom_img = "@//sw/device/lib/testing/test_rom:test_rom_sim_verilator_scr_vmem",
+        rom_img = "@//sw/device/lib/testing/test_rom:matcha_test_rom_sim_verilator_scr_vmem",
         otp_img = "@//hw/top_matcha/data:otp_img_rma",
         verilator_testbench = "@//hw:matcha_verilator",
         timeout = "moderate",
@@ -96,7 +96,7 @@
         data = [],
         local = True,
         otp = "//hw/top_matcha/data:otp_img_rma",
-        rom = "//sw/device/lib/testing/test_rom:test_rom_sim_dv_scr_vmem",
+        rom = "//sw/device/lib/testing/test_rom:matcha_test_rom_sim_dv_scr_vmem",
         tags = [],
         timeout = "moderate",
         test_runner = "//util:dvsim_matcha_test_runner.sh",
diff --git a/sw/device/examples/hello_world/BUILD b/sw/device/examples/hello_world/BUILD
index 95bb48f..6c69df8 100644
--- a/sw/device/examples/hello_world/BUILD
+++ b/sw/device/examples/hello_world/BUILD
@@ -3,6 +3,9 @@
 # SPDX-License-Identifier: Apache-2.0
 
 load("//rules:matcha.bzl", "OPENTITAN_CPU", "sec_flash_binary")
+load("//rules:targets.bzl", "get_targets")
+
+TARGETS = get_targets()
 
 sec_flash_binary(
     name = "hello_world",
@@ -43,47 +46,47 @@
 )
 
 # Use shell test to run the interactive verilator test on UART and GPIO
-sh_test(
-    name = "verilator_hello_world_test",
+[sh_test(
+    name = "{}_verilator_hello_world_test".format(target),
     timeout = "long",
     srcs = [":run_verilator_hello_world.sh"],
     args = [
-        "$(location //hw:matcha_verilator)",
-        "$(location //sw/device/lib/testing/test_rom:test_rom_sim_verilator_scr_vmem)",
+        "$(location //hw:{}_verilator)".format(target),
+        "$(location //sw/device/lib/testing/test_rom:{}_test_rom_sim_verilator_scr_vmem)".format(target),
         "$(location :hello_world_sim_verilator_vmem)",
-        "$(location //hw/top_matcha/data:otp_img_rma)",
+        "$(location //hw/top_{}/data:otp_img_rma)".format(target),
     ],
     data = [
         ":hello_world_sim_verilator_vmem",
         ":hello_world_test_expected_gpio.txt",
-        "//hw:matcha_verilator",
-        "//hw/top_matcha/data:otp_img_rma",
-        "//sw/device/lib/testing/test_rom:test_rom_sim_verilator_scr_vmem",
+        "//hw:{}_verilator".format(target),
+        "//hw/top_{}/data:otp_img_rma".format(target),
+        "//sw/device/lib/testing/test_rom:{}_test_rom_sim_verilator_scr_vmem".format(target),
     ],
     tags = [
         "verilator",
     ],
     visibility = ["//sw/device/tests:sw_device_test_group"],
-)
+) for target in TARGETS]
 
-sh_test(
-    name = "verilator_hello_world_gpio_test",
+[sh_test(
+    name = "{}_verilator_hello_world_gpio_test".format(target),
     timeout = "long",
     srcs = [":run_verilator_hello_world.sh"],
     args = [
-        "$(location //hw:matcha_verilator)",
-        "$(location //sw/device/lib/testing/test_rom:test_rom_sim_verilator_scr_vmem)",
+        "$(location //hw:{}_verilator)".format(target),
+        "$(location //sw/device/lib/testing/test_rom:{}_test_rom_sim_verilator_scr_vmem)".format(target),
         "$(location :hello_world_sim_verilator_vmem)",
-        "$(location //hw/top_matcha/data:otp_img_rma)",
+        "$(location //hw/top_{}/data:otp_img_rma)".format(target),
         "gpio_test",
     ],
     data = [
         ":hello_world_sim_verilator_vmem",
-        "//hw:matcha_verilator",
-        "//hw/top_matcha/data:otp_img_rma",
-        "//sw/device/lib/testing/test_rom:test_rom_sim_verilator_scr_vmem",
+        "//hw:{}_verilator".format(target),
+        "//hw/top_{}/data:otp_img_rma".format(target),
+        "//sw/device/lib/testing/test_rom:{}_test_rom_sim_verilator_scr_vmem".format(target),
     ],
     tags = [
         "verilator",
     ],
-)
+) for target in TARGETS]
diff --git a/sw/device/lib/testing/test_rom/BUILD b/sw/device/lib/testing/test_rom/BUILD
index 4458399..6474063 100644
--- a/sw/device/lib/testing/test_rom/BUILD
+++ b/sw/device/lib/testing/test_rom/BUILD
@@ -3,75 +3,80 @@
 # Licensed under the Apache License, Version 2.0, see LICENSE for details.
 # SPDX-License-Identifier: Apache-2.0
 
-load("//rules:matcha.bzl", "NEXUS_CORE_TARGETS", "OPENTITAN_CPU", "opentitan_rom_binary")
 load("@lowrisc_opentitan//rules:autogen.bzl", "autogen_chip_info")
 load("@lowrisc_opentitan//rules:linker.bzl", "ld_library")
+load("//rules:matcha.bzl", "NEXUS_CORE_TARGETS", "OPENTITAN_CPU", "opentitan_rom_binary")
+load("//rules:targets.bzl", "get_targets")
 
 package(default_visibility = ["//visibility:public"])
 
+TARGETS = get_targets()
+
 autogen_chip_info(
     name = "chip_info",
     version = "//util:matcha_version_file",
 )
 
-ld_library(
-    name = "linker_script",
-    script = "test_rom.ld",
+[ld_library(
+    name = "{}_linker_script".format(target),
+    script = "{}_test_rom.ld".format(target),
     deps = [
-        "//hw/top_matcha/sw/autogen:top_matcha_memory",
+        "//hw/top_{}/sw/autogen:top_{}_memory".format(target, target),
         "@lowrisc_opentitan//sw/device:info_sections",
         "@lowrisc_opentitan//sw/device/silicon_creator/lib/base:static_critical_sections",
     ],
-)
+) for target in TARGETS]
 
-opentitan_rom_binary(
-    name = "test_rom",
+[opentitan_rom_binary(
+    name = "{}_test_rom".format(target),
+    top_target = target,
     deps = [
-        ":linker_script",
-        ":test_rom_otp_lib",
+        ":{}_linker_script".format(target),
+        ":{}_test_rom_otp_lib".format(target),
     ],
-)
+) for target in TARGETS]
 
-opentitan_rom_binary(
-    name = "test_rom_no_otp",
+[opentitan_rom_binary(
+    name = "{}_test_rom_no_otp".format(target),
     srcs = [
         "test_rom.c",
         "test_rom_start.S",
     ],
     defines = ["OTP_IS_RAM"],
+    top_target = target,
     deps = [
-        ":linker_script",
-        ":test_rom_lib",
-        "@lowrisc_opentitan//sw/device/lib/crt",
+        ":{}_linker_script".format(target),
+        ":{}_test_rom_lib".format(target),
         "//sw/device/silicon_creator/rom:bootstrap_no_otp",
+        "@lowrisc_opentitan//sw/device/lib/crt",
     ],
-)
+) for target in TARGETS]
 
-cc_library(
-    name = "test_rom_otp_lib",
+[cc_library(
+    name = "{}_test_rom_otp_lib".format(target),
     srcs = [
         "test_rom.c",
         "test_rom_start.S",
     ],
     deps = [
-        ":test_rom_lib",
-        "@lowrisc_opentitan//sw/device/lib/crt",
+        ":{}_test_rom_lib".format(target),
         "//sw/device/silicon_creator/rom:bootstrap",
+        "@lowrisc_opentitan//sw/device/lib/crt",
     ],
-)
+) for target in TARGETS]
 
-cc_library(
-    name = "test_rom_lib",
+[cc_library(
+    name = "{}_test_rom_lib".format(target),
     srcs = [
     ],
     target_compatible_with = [OPENTITAN_CPU],
     deps = [
         ":chip_info",
-        "//hw/top_matcha:ast_regs",
-        "//hw/top_matcha:clkmgr_regs",
-        "//hw/top_matcha/sw:top_matcha",
-        "//hw/top_matcha/ip/flash_ctrl/data/autogen:flash_ctrl_regs",
-        "//hw/top_matcha/ip/sensor_ctrl/data:sensor_ctrl_regs",
+        "//hw/top_{}:ast_regs".format(target),
+        "//hw/top_{}:clkmgr_regs".format(target),
+        "//hw/top_{}/sw:top_{}".format(target, target),
+        "//hw/top_{}/ip/flash_ctrl/data/autogen:flash_ctrl_regs".format(target),
+        "//hw/top_{}/ip/sensor_ctrl/data:sensor_ctrl_regs".format(target),
         "//sw/device/lib:spi_flash",
         "//sw/device/lib/dif:pinmux",
         "//sw/device/lib/testing:pinmux_testutils",
@@ -106,30 +111,31 @@
         "@lowrisc_opentitan//sw/device/silicon_creator/lib/drivers:flash_ctrl",
         "@lowrisc_opentitan//sw/device/silicon_creator/lib/drivers:retention_sram",
     ],
-)
+) for target in TARGETS]
 
-ld_library(
-    name = "puppeteer_linker_script",
-    script = "puppeteer_rom.ld",
+[ld_library(
+    name = "{}_puppeteer_linker_script".format(target),
+    script = "{}_puppeteer_rom.ld".format(target),
     deps = [
-        "//hw/top_matcha/sw/autogen:top_matcha_memory",
+        "//hw/top_{}/sw/autogen:top_{}_memory".format(target, target),
     ],
-)
+) for target in TARGETS]
 
 # Only build for nexus FPGA.
-opentitan_rom_binary(
-    name = "puppeteer_rom",
+[opentitan_rom_binary(
+    name = "{}_puppeteer_rom".format(target),
     per_device_deps = {
         "fpga_nexus": [NEXUS_CORE_TARGETS.get("secure_core")],
     },
+    top_target = target,
     deps = [
-        ":puppeteer_linker_script",
-        ":puppeteer_rom_lib",
+        ":{}_puppeteer_linker_script".format(target),
+        ":{}_puppeteer_rom_lib".format(target),
     ],
-)
+) for target in TARGETS]
 
-cc_library(
-    name = "puppeteer_rom_lib",
+[cc_library(
+    name = "{}_puppeteer_rom_lib".format(target),
     srcs = [
         "puppeteer.cc",
         "puppeteer_rom.cc",
@@ -145,11 +151,11 @@
     ],
     target_compatible_with = [OPENTITAN_CPU],
     deps = [
-        "//hw/top_matcha:ast_regs",
-        "//hw/top_matcha:clkmgr_regs",
-        "//hw/top_matcha:pinmux_regs",
-        "//hw/top_matcha/sw:top_matcha",
-        "//hw/top_matcha/ip/sensor_ctrl/data:sensor_ctrl_regs",
+        "//hw/top_{}:ast_regs".format(target),
+        "//hw/top_{}:clkmgr_regs".format(target),
+        "//hw/top_{}:pinmux_regs".format(target),
+        "//hw/top_{}/sw:top_{}".format(target, target),
+        "//hw/top_{}/ip/sensor_ctrl/data:sensor_ctrl_regs".format(target),
         "//sw/device/lib/testing/test_rom/puppeteer_utils",
         "@lowrisc_opentitan//hw/ip/csrng/data:csrng_regs",
         "@lowrisc_opentitan//hw/ip/edn/data:edn_regs",
@@ -163,18 +169,13 @@
         "@lowrisc_opentitan//sw/device/silicon_creator/lib:manifest",
         "@lowrisc_opentitan//sw/device/silicon_creator/lib/drivers:flash_ctrl",
     ],
-)
+) for target in TARGETS]
 
 # Only build for CHERIoT targets. Requires that bazel be invoked with
 # --config=cheriot-baremetal --copt=-D_CHERIOT_BAREMETAL_=1
 # so that all dependencies use those options.
 opentitan_rom_binary(
     name = "test_rom_no_otp_cheri",
-    visibility = ["//visibility:private"],
-    # NB: fpga_nexus is used for renode sims
-    per_device_deps = {
-        "fpga_nexus": [NEXUS_CORE_TARGETS.get("secure_core")],
-    },
     srcs = [
         "test_rom_cheri.c",
         "test_rom_start_cheri.S",
@@ -182,15 +183,20 @@
         "crt_cheri.S",
     ],
     defines = ["OTP_IS_RAM"],
-    deps = [
-        ":linker_script_cheri",
-        ":baremetal_lib",
-        ":test_rom_lib",
-        "//sw/device/silicon_creator/rom:bootstrap_no_otp",
-    ],
+    # NB: fpga_nexus is used for renode sims
+    per_device_deps = {
+        "fpga_nexus": [NEXUS_CORE_TARGETS.get("secure_core")],
+    },
     tags = [
         "cheri",
     ],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":baremetal_lib",
+        ":linker_script_cheri",
+        ":sencha_test_rom_lib",
+        "//sw/device/silicon_creator/rom:bootstrap_no_otp",
+    ],
 )
 
 cc_library(
@@ -202,14 +208,14 @@
 
 ld_library(
     name = "linker_script_cheri",
-    visibility = ["//visibility:private"],
     script = "test_rom_cheri.ld",
+    tags = [
+        "cheri",
+    ],
+    visibility = ["//visibility:private"],
     deps = [
         "//hw/top_matcha/sw/autogen:top_matcha_memory_cheri",
         "@lowrisc_opentitan//sw/device:info_sections",
         "@lowrisc_opentitan//sw/device/silicon_creator/lib/base:static_critical_sections",
     ],
-    tags = [
-        "cheri",
-    ],
 )
diff --git a/sw/device/lib/testing/test_rom/puppeteer_rom.ld b/sw/device/lib/testing/test_rom/matcha_puppeteer_rom.ld
similarity index 100%
rename from sw/device/lib/testing/test_rom/puppeteer_rom.ld
rename to sw/device/lib/testing/test_rom/matcha_puppeteer_rom.ld
diff --git a/sw/device/lib/testing/test_rom/test_rom.ld b/sw/device/lib/testing/test_rom/matcha_test_rom.ld
similarity index 100%
rename from sw/device/lib/testing/test_rom/test_rom.ld
rename to sw/device/lib/testing/test_rom/matcha_test_rom.ld
diff --git a/sw/device/lib/testing/test_rom/sencha_puppeteer_rom.ld b/sw/device/lib/testing/test_rom/sencha_puppeteer_rom.ld
new file mode 100644
index 0000000..fab76a1
--- /dev/null
+++ b/sw/device/lib/testing/test_rom/sencha_puppeteer_rom.ld
@@ -0,0 +1,177 @@
+/* Copyright 2023 Google LLC */
+/* Copyright lowRISC contributors. */
+/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+/**
+ * Linker script for an OpenTitan boot ROM.
+ *
+ * Portions of this file are Ibex-specific.
+ */
+
+OUTPUT_ARCH(riscv)
+/**
+ * Don't build with gcc.
+ * GROUP(-lgcc)
+*/
+
+/**
+ * Indicate that there are no dynamic libraries, whatsoever.
+ */
+__DYNAMIC = 0;
+
+INCLUDE hw/top_sencha/sw/autogen/top_sencha_memory.ld
+
+/**
+ * The boot address, which indicates the location of the initial interrupt
+ * vector.
+ */
+ ENTRY(_reset_start);
+_boot_address = ORIGIN(rom);
+
+_heap_size = 0xe000;
+_stack_size = LENGTH(ram_main) - _heap_size;
+_stack_end = ORIGIN(ram_main) + LENGTH(ram_main);
+_stack_start = _stack_end - _stack_size;
+_flash_start = ORIGIN(eflash);
+
+/**
+ * This symbol points at the header of the flash binary, which contains loading
+ * and signing information.
+ */
+_flash_header = _flash_start;
+
+_chip_info_size = 128;
+_chip_info_start = ORIGIN(rom) + LENGTH(rom) - _chip_info_size;
+
+/**
+ * NOTE: We have to align each section to word boundaries as our current
+ * s19->slm conversion scripts are not able to handle non-word aligned sections.
+ */
+SECTIONS {
+  /**
+   * Ibex interrupt vector. See test_rom_start.S for more information.
+   *
+   * This has to be set up at the boot address, so that execution jumps to the
+   * reset handler correctly.
+   */
+  .vectors _boot_address : ALIGN(4) {
+    KEEP(*(.vectors))
+  } > rom
+
+  /**
+   * C runtime (CRT) section, containing program initialization code.
+   */
+  .crt : ALIGN(4) {
+    KEEP(*(.crt))
+  } > rom
+
+  /**
+   * Standard text section, containing program code.
+   */
+  .text : ALIGN(4) {
+    *(.text)
+    *(.text.*)
+  } > rom
+
+  /**
+   * Read-only data section, containing all large compile-time constants, like
+   * strings.
+   */
+  .rodata : ALIGN(4) {
+    /* Small read-only data comes before regular read-only data for the same
+     * reasons as in the data section */
+    *(.srodata)
+    *(.srodata.*)
+    *(.rodata)
+    *(.rodata.*)
+  } > rom
+
+  /**
+   * "Intitial data" section, the initial values of the mutable data section
+   * initialized at runtime.
+   */
+  .idata : ALIGN(4) {
+    _data_init_start = .;
+  } > rom
+
+  /**
+   * Standard mutable data section, at the bottom of RAM. This will be
+   * initialized from the .idata section at runtime by the CRT.
+   */
+  .data ORIGIN(ram_main): AT(_data_init_start) ALIGN(4) {
+    _data_start = .;
+    __global_pointer$ = . + 2048;
+
+    /* Small data should come before larger data. This helps to ensure small
+     * globals are within 2048 bytes of the value of `gp`, making their accesses
+     * hopefully only take one instruction. */
+    *(.sdata)
+    *(.sdata.*)
+
+    /* Other data will likely need multiple instructions to load, so we're less
+     * concerned about address materialisation taking more than one instruction.
+     */
+    *(.data)
+    *(.data.*)
+    . = ALIGN(4);
+    _data_end = .;
+  } > ram_main
+
+  /**
+   * Immutable chip_info data, containing build-time-recorded information.
+   */
+  .chip_info _chip_info_start : ALIGN(4) {
+    *(.chip_info)
+  } > rom
+
+  /**
+   * Standard BSS section. This will be zeroed at runtime by the CRT.
+   */
+  .bss : ALIGN(4) {
+    _bss_start = .;
+    /* Small BSS comes before regular BSS for the same reasons as in the data
+     * section */
+    *(.sbss)
+    *(.sbss.*)
+    *(.bss)
+    *(.bss.*)
+    *(COMMON)
+    . = ALIGN(4);
+    _bss_end = .;
+  } > ram_main
+
+  /**
+   * STAB debug table.
+   */
+  .stab 0x0 (NOLOAD): {
+    [.stab]
+  }
+
+  /**
+   * STAB debug strings.
+   */
+  .stabstr 0x0 (NOLOAD): {
+    [.stabstr]
+  }
+
+  /**
+   * The following sections are used by DV to implement logging in an
+   * alternate way, which enables simulation speed up by completely avoiding
+   * any string format processing or even the actual transmission of log data
+   * to a real peripheral.
+   *
+   * These sections are marked as dummy so that they can still be extracted
+   * using readelf or similar utilities. As such, the content in these sections
+   * is not relevant for the actual SW code and can be safely discarded.
+   */
+
+  /**
+   * The following section contains log fields constructed from the logs using
+   * the log_fields_t struct defined in sw/device/lib/runtime/log.h. The size of
+   * each log field is fixed - 20 bytes, which is used as the delimiter.
+   */
+  .logs.fields 0x0 (DSECT): {
+    *(.logs.fields)
+  }
+}
diff --git a/sw/device/lib/testing/test_rom/sencha_test_rom.ld b/sw/device/lib/testing/test_rom/sencha_test_rom.ld
new file mode 100644
index 0000000..61fc735
--- /dev/null
+++ b/sw/device/lib/testing/test_rom/sencha_test_rom.ld
@@ -0,0 +1,165 @@
+/* Copyright 2024 Google LLC. */
+/* Copyright lowRISC contributors. */
+/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+/**
+ * Linker script for an OpenTitan (test) boot ROM.
+ *
+ * Portions of this file are Ibex-specific.
+ */
+
+OUTPUT_ARCH(riscv)
+
+/**
+ * Indicate that there are no dynamic libraries, whatsoever.
+ */
+__DYNAMIC = 0;
+
+INCLUDE hw/top_sencha/sw/autogen/top_sencha_memory.ld
+
+/**
+ * The boot address, which indicates the location of the initial interrupt
+ * vector.
+ */
+_boot_address = ORIGIN(rom);
+
+/**
+ * Symbols to be used in the setup of the address translation for ROM_EXT.
+ */
+
+/**
+ * This symbol points at the manifest of the OTTF + test binary, which contains
+ * loading and signing information.
+ *
+ * See `sw/device/lib/testing/test_framework/ottf.ld`, under the
+ * .manifest section, which populates it.
+ */
+_rom_ext_virtual_start_address = ORIGIN(rom_ext_virtual);
+_rom_ext_virtual_size = LENGTH(rom_ext_virtual);
+ASSERT((_rom_ext_virtual_size <= (LENGTH(eflash) / 2)),
+  "Error: rom ext flash is bigger than slot.");
+
+_rom_digest_size = 32;
+_chip_info_start = ORIGIN(rom) + LENGTH(rom) - _rom_digest_size - _chip_info_size;
+
+/* DV Log offset (has to be different to other boot stages). */
+_dv_log_offset = 0x0;
+
+/**
+ * We define an entry point only for documentation purposes (and to stop LLD
+ * erroring). In reality, we don't use this information within the ROM image, as
+ * we start at a fixed offset.
+ */
+ENTRY(_reset_start);
+
+/**
+ * NOTE: We have to align each section to word boundaries as our current
+ * s19->slm conversion scripts are not able to handle non-word aligned sections.
+ */
+SECTIONS {
+  /**
+   * Ibex interrupt vector. See test_rom_start.S for more information.
+   *
+   * This has to be set up at the boot address, so that execution jumps to the
+   * reset handler correctly.
+   */
+  .vectors _boot_address : ALIGN(4) {
+    KEEP(*(.vectors))
+  } > rom
+
+  /**
+   * C runtime (CRT) section, containing program initialization code.
+   */
+  .crt : ALIGN(4) {
+    KEEP(*(.crt))
+  } > rom
+
+  /**
+   * Standard text section, containing program code.
+   */
+  .text : ALIGN(4) {
+    *(.text)
+    *(.text.*)
+  } > rom
+
+  /**
+   * Read-only data section, containing all large compile-time constants, like
+   * strings.
+   */
+  .rodata : ALIGN(4) {
+    /* Small read-only data comes before regular read-only data for the same
+     * reasons as in the data section */
+    *(.srodata)
+    *(.srodata.*)
+    *(.rodata)
+    *(.rodata.*)
+  } > rom
+
+  /**
+   * Critical static data that is accessible by both the ROM and the ROM
+   * extension.
+   */
+  INCLUDE external/lowrisc_opentitan/sw/device/silicon_creator/lib/base/static_critical.ld
+
+  /**
+   * Standard mutable data section, at the bottom of RAM. This will be
+   * initialized from the .idata section at runtime by the CRT.
+   */
+  .data : ALIGN(4) {
+    _data_start = .;
+    _data_init_start = LOADADDR(.data);
+
+    /* This will get loaded into `gp`, and the linker will use that register for
+     * accessing data within [-2048,2047] of `__global_pointer$`.
+     *
+     * This is much cheaper (for small data) than materializing the
+     * address and loading from that (which will take one extra instruction). */
+    __global_pointer$ = . + 2048;
+
+    /* Small data should come before larger data. This helps to ensure small
+     * globals are within 2048 bytes of the value of `gp`, making their accesses
+     * hopefully only take one instruction. */
+    *(.sdata)
+    *(.sdata.*)
+
+    /* Other data will likely need multiple instructions to load, so we're less
+     * concerned about address materialisation taking more than one instruction.
+     */
+    *(.data)
+    *(.data.*)
+
+    /* Ensure section end is word-aligned. */
+    . = ALIGN(4);
+    _data_end = .;
+    _data_init_end = LOADADDR(.data) + SIZEOF(.data);
+
+    /* This puts it in ram_main at runtime (for the VMA), but puts the section
+     * into rom for load time (for the LMA). This is why `_data_init_*` uses
+     * `LOADADDR`. */
+  } > ram_main AT> rom
+
+  /**
+   * Immutable chip_info data, containing build-time-recorded information.
+   */
+  .chip_info _chip_info_start : ALIGN(4) {
+    KEEP(*(.chip_info))
+  } > rom
+
+  /**
+   * Standard BSS section. This will be zeroed at runtime by the CRT.
+   */
+  .bss : ALIGN(4) {
+    _bss_start = .;
+    /* Small BSS comes before regular BSS for the same reasons as in the data
+     * section */
+    *(.sbss)
+    *(.sbss.*)
+    *(.bss)
+    *(.bss.*)
+    . = ALIGN(4);
+    _bss_end = .;
+  } > ram_main
+
+  INCLUDE external/lowrisc_opentitan/sw/device/info_sections.ld
+}
diff --git a/sw/device/tests/BUILD b/sw/device/tests/BUILD
index 6316d7d..0f5d0f7 100644
--- a/sw/device/tests/BUILD
+++ b/sw/device/tests/BUILD
@@ -700,7 +700,7 @@
         "verilator_supervisor_mode_test",
         "verilator_tlul_mailbox_test",
         "verilator_virtual_memory_test",
-        "//sw/device/examples/hello_world:verilator_hello_world_test",
+        "//sw/device/examples/hello_world:matcha_verilator_hello_world_test",
         "//sw/device/tests/smc:verilator_kelvin_checksum_test",
         "//sw/device/tests/smc:verilator_kelvin_hello_test",
         "//sw/device/tests/smc:verilator_ml_top_irq_test",
@@ -735,8 +735,8 @@
     test_in_rom = True,
     deps = [
         ":test_lib_base",
-        "//sw/device/lib/testing/test_rom:linker_script",
-        "//sw/device/lib/testing/test_rom:test_rom_otp_lib",
+        "//sw/device/lib/testing/test_rom:matcha_linker_script",
+        "//sw/device/lib/testing/test_rom:matcha_test_rom_otp_lib",
     ],
 )