target/veer: Use a local emulator binary that always starts the I3C controller
diff --git a/target/veer/BUILD.bazel b/target/veer/BUILD.bazel
index 47322a4..576ce4a 100644
--- a/target/veer/BUILD.bazel
+++ b/target/veer/BUILD.bazel
@@ -4,7 +4,7 @@
 load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
 load("@pigweed//pw_build:merge_flags.bzl", "flags_from_dict")
 load("@pigweed//pw_kernel:flags.bzl", "KERNEL_DEVICE_COMMON_FLAGS")
-load("@rules_rust//rust:defs.bzl", "rust_library")
+load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library")
 load("//target/veer:defs.bzl", "TARGET_COMPATIBLE_WITH")
 
 platform(
@@ -86,6 +86,22 @@
     ],
 )
 
+rust_binary(
+    name = "caliptra_emulator",
+    srcs = ["caliptra_emulator_main.rs"],
+    aliases = {
+        "//third_party/caliptra/caliptra-mcu-sw:emulator_lib": "emulator",
+    },
+    edition = "2021",
+    deps = [
+        "//third_party/caliptra/caliptra-mcu-sw:emulator_lib",
+        "//third_party/caliptra/caliptra-mcu-sw:mcu_testing_common",
+        "//third_party/caliptra/caliptra-sw:caliptra_emu_cpu",
+        "@rust_caliptra_crates_host//:clap",
+    ],
+    visibility = [":__subpackages__"],
+)
+
 rust_library(
     name = "console",
     srcs = ["console.rs"],
diff --git a/target/veer/caliptra_emulator_main.rs b/target/veer/caliptra_emulator_main.rs
new file mode 100644
index 0000000..564dbd5
--- /dev/null
+++ b/target/veer/caliptra_emulator_main.rs
@@ -0,0 +1,33 @@
+// Licensed under the Apache-2.0 license
+// SPDX-License-Identifier: Apache-2.0
+
+//! Entry point for the Caliptra MCU emulator.
+//!
+//! Replaces the upstream `emulator/app/src/main.rs`, which only pumps I3C
+//! socket traffic into the emulated target in selected test modes
+//! (for example via `--test-feature ...`). Host-side tests drive firmware
+//! over the I3C TCP socket (`--i3c-port`), so this entry point unconditionally
+//! starts the I3C controller before entering the run loop.
+//!
+//! Firmware-requested exits terminate the process from within `step()` (the
+//! emulator's exit-control peripheral calls `std::process::exit`), so the
+//! loop only ends on fatal errors or breakpoints.
+
+use caliptra_emu_cpu::StepAction;
+use clap::Parser;
+use emulator::{Emulator, EmulatorArgs};
+use mcu_testing_common::MCU_RUNNING;
+use std::io;
+
+fn main() -> io::Result<()> {
+    let cli = EmulatorArgs::parse();
+    let mut emulator = Emulator::from_args(cli, false)?;
+    emulator.start_i3c_controller();
+    while MCU_RUNNING.load(std::sync::atomic::Ordering::Relaxed) {
+        match emulator.step() {
+            StepAction::Break | StepAction::Fatal => break,
+            _ => {}
+        }
+    }
+    Ok(())
+}
\ No newline at end of file
diff --git a/target/veer/tooling/BUILD.bazel b/target/veer/tooling/BUILD.bazel
index 2fa3dd0..29b66e4 100644
--- a/target/veer/tooling/BUILD.bazel
+++ b/target/veer/tooling/BUILD.bazel
@@ -45,7 +45,7 @@
 
 pw_py_importable_runfile(
     name = "emulator-exe-runfiles",
-    src = "//third_party/caliptra/caliptra-mcu-sw:emulator",
+    src = "//target/veer:caliptra_emulator",
     executable = True,
     import_location = "caliptra.emulator_exe",
 )