32#include <capstone/capstone.h>
42#include <unicorn/unicorn.h>
80alignas(max_align_t)
static uint8_t
102 (void)
priv_emu_io_errf(
"ra8_emulator: memory backing failed (%u): logical=%llu os=%d\n",
103 (
unsigned int)result.
status,
133 bool have_panel =
false;
136 if (have_panel && !args->
size_set) {
141 return (have_panel && (
s_panel.name[0] !=
'\0')) ?
s_panel.name :
"ra8_emulator";
164 .panel_width = view_w,
165 .panel_height = view_h,
177 "surface=%zu scratch-required=%zu scratch-supplied=%zu os=%d\n",
178 (
unsigned int)result.
status,
212 uc_engine* uc =
nullptr;
213 if (uc_open(UC_ARCH_ARM, (uc_mode)(UC_MODE_THUMB | UC_MODE_MCLASS), &uc) != UC_ERR_OK) {
217 (void)uc_ctl_set_cpu_model(uc, UC_CPU_ARM_CORTEX_M33);
251 if (touch_seq_str ==
nullptr) {
255 k_touch_seq_parse_max = 32U,
258 const char* p = touch_seq_str;
259 uint32_t pushed = 0U;
260 for (uint32_t n = 0U; (n < (uint32_t)k_touch_seq_parse_max) && (*p !=
'\0'); n++) {
263 if ((end == p) || (*end !=
':')) {
279 (void)
priv_emu_io_errf(
"ra8_emulator: --touch-seq armed %u raw point(s)\n", (
unsigned)pushed);
304 (void)
priv_emu_io_errf(
"ra8_emulator: --button %d held (SW pin P00%u low/pressed)\n",
309 uint8_t cur_soc = 0U;
313 (void)
priv_emu_io_errf(
"ra8_emulator: battery %u%% %s (MAX17048 @ I2C 0x36)\n",
342 (void)
priv_emu_io_errf(
"ra8_emulator: queued %u byte(s) to SCI%u RX from --input\n",
349 for (uint32_t k = 0U; k < n; k++) {
352 (void)
priv_emu_io_errf(
"ra8_emulator: queued %u keystroke(s) via --keys (window-key path)\n",
359 (void)
priv_emu_io_errf(
"ra8_emulator: queued %u byte(s) to the USB CDC bulk OUT pipe\n", n);
427 (
unsigned long long)elf_out->
length);
430 ?
"RA8P1 (R7KA8P1KFLCAC) -- +Ethos-U55 NPU"
431 :
"RA8D2 (R7KA8D2KFLCAC)");
434 ?
"Cortex-M33 (Armv8-M)"
435 :
"Cortex-M85 (Armv8.1-M, MVE seams armed)",
467 const char* ns_elf_path,
471 if (ns_elf_path !=
nullptr) {
480 (
unsigned long long)ns_out->
length);
490 if (ns_vbase != 0U) {
523 uint32_t* dump_sym_addrs,
524 uint32_t* stop_sym_addr)
526 for (uint32_t d = 0U; d < args->
dump_sym_n; d++) {
528 if ((dump_sym_addrs[d] == 0U) && (ns_elf->
fd >= 0)) {
531 if (dump_sym_addrs[d] == 0U) {
532 (void)
priv_emu_io_errf(
"ra8_emulator: --dump-sym %s not found in symbol table\n",
539 if ((*stop_sym_addr == 0U) && (ns_elf->
fd >= 0)) {
542 if (*stop_sym_addr == 0U) {
543 (void)
priv_emu_io_errf(
"ra8_emulator: --stop-sym %s not found in symbol table\n",
576 (void)uc_reg_write(uc, UC_ARM_REG_SP, &sp);
577 (void)uc_reg_write(uc, UC_ARM_REG_PC, &pc);
578 (void)uc_reg_write(uc, UC_ARM_REG_XPSR, &xpsr);
579 (void)
priv_emu_io_errf(
"ra8_emulator: reset SP=0x%08X PC=0x%08X -- running "
580 "(<= %u x %u insns, %u s wall)\n",
649 bool usbh_seamed =
false;
708 const char* win_title,
709 const uint32_t* dump_sym_addrs,
710 uint32_t stop_sym_addr,
718 .vtor_base = vtor_base,
730 .stop_sym_addr = stop_sym_addr,
733 .dump_sym_addrs = dump_sym_addrs,
737 .win_title = win_title,
738 .presentation = presentation,
774 const char* win_title)
777 uint32_t stop_sym_addr = 0U;
779 if (ns_elf->
fd >= 0) {
856 uint16_t view_w = args.
view_w;
857 uint16_t view_h = args.
view_h;
869 uc_engine* uc =
nullptr;
void main(void)
Secure fallback main entry point.
Multi-channel console log store backing the board view's tabbed console.
Virtual network peer for ra8_emulator – talks TCP/IP to the firmware.
void board_net_init(bool trace)
Reset the virtual network peer to its initial state.
Composite board-view renderer: panel framebuffer + a status sidebar.
Register-accurate peripheral-model framework for the board emulator.
void board_periph_init(bool trace)
One-time reset of all peripheral-model state.
board_device_t board_periph_device(void)
Report which RA8 device the peripheral model is emulating.
void board_periph_sci_feed_rx(uint8_t channel, const uint8_t *data, uint32_t len)
Queue host->firmware bytes for a channel's receive path.
void board_periph_battery_get(uint8_t *out_soc, bool *out_charging)
Read back the emulated battery state (for the status overlay).
bool board_periph_touch_seq_push(uint16_t x, uint16_t y)
Queue one raw touch point onto the modelled GT911 injection FIFO.
void board_periph_set_usbhs_loop(bool on)
Enable the chip-internal USBHS-host self-loop model (–usbhs-loop).
uint8_t board_periph_sci_console_channel(void)
The SCI channel the EK-RA8D2 console (J-Link OB VCOM) uses.
void board_periph_sci_set_tx_sink(void(*sink)(uint8_t channel, uint8_t byte))
Wire a host sink that receives every byte the firmware transmits.
void board_periph_touch_seq_reset(void)
Clear the modelled GT911 injected-touch sequence FIFO.
void board_periph_battery_set(uint8_t soc_pct, bool charging)
Set the emulated battery state surfaced by the MAX17048 fuel gauge.
void board_periph_gpio_set_input(uint8_t port, uint8_t pin, bool level)
Drive a GPIO pin's input level from outside the firmware.
void board_periph_set_device(board_device_t device)
Select which RA8 device the peripheral model emulates.
@ k_board_device_ra8p1
Renesas RA8P1: adds the Ethos-U55 NPU.
IT8951 e-paper SPI-device model for ra8_emulator (attached to SPI_B).
Cellular AT-modem device model for ra8_emulator (attached to SCI7 UART).
SD-card-over-SPI device model for ra8_emulator (attached to SPI_B).
USBFS controller model + a virtual USB host for the board emulator.
void board_usb_feed_bulk_in(const uint8_t *data, uint32_t len)
Queue host->device bulk bytes for the CDC data OUT pipe (echo test).
void board_usb_set_external_host(bool present)
Declare (or withdraw) a real-firmware USB host driving the device.
USBHS HOST-mode controller model (self-loop peer of the USBFS device).
void board_usb_host_set_allowed(bool allowed)
Grant (or deny) the register-level loop for this firmware.
Minimal self-contained macOS window for the board emulator.
ra8_emulator command-line parsing (usage text + option decoding)
bool emu_args_parse(int argc, char **argv, emu_args_t *out)
Parse the ra8_emulator command line into out (or print usage).
Emulator text-console surfaces: UART echo, ITM/SWO echo, escapes.
uint32_t decode_escapes(const char *in, uint8_t *out, uint32_t cap)
Decode a C-style escaped –input string into a raw byte buffer.
@ k_uart_line_max
Pretty-print line buffer for the [uart] prefix.
void emu_console_install(uc_engine *uc)
Seed ITM "ready" bits and arm the stimulus-port echo hook.
void console_tx_sink(uint8_t channel, uint8_t byte)
SCI TX sink: print each transmitted byte (prefixed line + raw mirror).
Second-core (cpu1, Cortex-M33) engine: release watch, boot, stepping.
void emu_cpu1_init(const emu_elf_source_t *elf, emu_memmap_workspace_t *memory)
Create the second emulator engine for cpu1, if the image carries one.
ELF32 image services for the board emulator (load / symbols / vectors).
uint32_t elf_sym_addr(const emu_elf_source_t *elf, const char *name, uint32_t *size_out)
Resolve a function symbol's entry address from the ELF .symtab.
int load_elf(uc_engine *uc, const emu_elf_source_t *elf)
Load ELF32 PT_LOAD segments into emulated memory at their LMA.
uint32_t elf_vector_base(const emu_elf_source_t *elf)
Vector-table base of an ELF: lowest executable PT_LOAD VMA.
@ k_emu_elf_io_ok
The complete operation succeeded.
Private raw-descriptor ELF source operations.
emu_elf_io_result_t priv_emu_elf_source_open(const char *path, emu_elf_source_t *source)
Open one regular ELF source without reading or allocating its bytes.
emu_elf_io_result_t priv_emu_elf_source_close(emu_elf_source_t *source)
Close and invalidate one independently owned ELF source.
Shared Unicorn engine access utilities for the board emulator.
static void wr32(uc_engine *uc, uint64_t addr, uint32_t v)
Write a 32-bit little-endian word to emulated memory.
Cortex-M exception model constants and interfaces for ra8_emulator.
@ k_xpsr_t_bit
xPSR.T (Thumb) – must stay set.
@ k_mpu_type_seed
8 data regions (matches the M85 MPU).
@ k_mpu_type
MPU_TYPE (DREGION in bits 15:8).
void emu_exc_install_scb_nvic(uc_engine *uc)
Arm the SCB control-word and NVIC ISER/ICER write watchers.
void emu_exc_install_core(uc_engine *uc)
Arm the core exception hooks (unmapped / INTR / ICSR watch).
Bounded raw-descriptor I/O seam for the RA8 emulator.
emu_io_result_t priv_emu_io_errf(const char *format,...)
Format bounded text and write it to the injected error descriptor.
void priv_emu_io_configure(int out_fd, int err_fd, const emu_io_ops_t *ops)
Inject process output descriptors and optional raw transfer hooks.
Shared aliased-memory backing and Unicorn memory-map bindings.
emu_memmap_result_t emu_memmap_open(emu_memmap_workspace_t *workspace)
Create three independent, lazily-committed host aperture mappings.
struct emu_memmap_workspace emu_memmap_workspace_t
Independent aperture backing with at most two engine bindings.
@ k_emu_memmap_ok
Operation completed exactly.
emu_memmap_result_t emu_memmap_attach(emu_memmap_workspace_t *workspace, uc_engine *uc)
Map one Unicorn engine onto the shared aperture backing.
bool emu_memmap_detach(emu_memmap_workspace_t *workspace, uc_engine *uc)
Remove one engine binding before closing that Unicorn engine.
bool emu_memmap_close(emu_memmap_workspace_t *workspace)
Release every host aperture mapping after all engines detached.
uint64_t emu_memmap_mram_base(void)
Return the MRAM boot-vector base.
uc_err emu_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t count)
Read guest memory through the central access seam.
Sparse MMIO model of the Renesas peripheral space.
Armv8-M MPU enforcement model for ra8_emulator.
void emu_mpu_install(uc_engine *uc)
Arm the MPU register watchers (RLAR capture + CTRL edge hooks).
@ k_emu_presentation_ok
Operation completed exactly.
bool emu_presentation_close(emu_presentation_workspace_t *workspace)
Close one owned presentation descriptor and invalidate the workspace.
@ k_emu_presentation_max_scratch_bytes
Exact maximum caller scratch: source plus rotated 64x64 RGB565 tiles.
emu_presentation_result_t emu_presentation_open(const emu_presentation_spec_t *spec, void *scratch, size_t supplied_scratch_bytes, emu_presentation_workspace_t *workspace)
Create and bind one unlinked raw-fd presentation workspace.
Firmware profiler (RA8_EMU_PROFILE): sampling, hooks, reports.
void emu_prof_install(uc_engine *uc)
Arm the per-instruction profiling hook (insn mode only).
void prof_load(const emu_elf_source_t *elf)
Collect + sort FUNC symbols (RA8_EMU_PROFILE only) for PC bucketing.
The chunked emulation run loop, report and exit-code mapping.
int emu_run_and_report(const emu_run_cfg_t *cfg)
Run the firmware to a stop condition, print the report, map the exit code.
@ k_run_wall_s
Wall-clock safety bound (seconds).
@ k_run_chunk_insns
Instructions per emulation chunk.
@ k_run_max_chunks
Chunk budget.
@ k_dump_sym_max
Max –dump-sym globals per run.
Armv8.1-M instruction-emulation seams (M85 ops on Unicorn's M33).
void div0_seam_install(const emu_elf_source_t *elf)
Scan the image for UDIV/SDIV sites so the div-0 trap can arm later.
void emu_insn_seams_install(uc_engine *uc)
Arm the invalid-instruction dispatcher on the engine.
void long_shift_seam_install(uc_engine *uc, const emu_elf_source_t *elf)
Scan the loaded image and install a hook at every immediate long-shift.
void fast_sd_seam_install(uc_engine *uc, const emu_elf_source_t *elf)
Install the --fast-sd block-read hook if opted-in and the symbol exists.
Function-entry seam glue + the –trace-sym instrument.
void sym_trace_install(uc_engine *uc, const emu_elf_source_t *elf, const char *const *names, uint32_t count)
Install a --trace-sym entry hook for every requested symbol present.
TrustZone Secure/Non-Secure seams for ra8_emulator.
uint32_t emu_tz_ns_vector_base(void)
The tracked NS vector-table fallback base.
void emu_tz_install(uc_engine *uc, const emu_elf_source_t *elf)
Arm the TrustZone S->NS boot seams (SAU_TYPE seed + BLXNS hook).
void emu_tz_set_ns_vector_base(uint32_t base)
Track the NS image's actual vector base (–ns load path).
void emu_tz_patch_cmse(uc_engine *uc, const emu_elf_source_t *elf)
Patch cmse_check_address_range to BX LR (flat-domain model).
Virtual USB host-mode devices behind the ra8_usb_host_* / hmsc seams.
bool usbh_seam_install(uc_engine *uc, const emu_elf_source_t *elf)
Install the virtual USB host-mode device seam if the host stack is linked.
Board-view presentation: frames, composition, input routing, panels.
@ k_emu_sw1_pin
SW1 -> P009.
@ k_emu_sw2_pin
SW2 -> P008.
@ k_emu_sw_port
Both user switches sit on PORT0.
bool emu_low_power(void)
Whether the M33 4:1-slower low-power clock model is active.
@ k_strtol_base10
Base-10 radix for strtol parses.
bool load_panel(const char *path, board_panel_t *out)
Load a panel descriptor (name / width / height) from a TOML-ish file.
@ k_core_m33
Cortex-M33 primary: the M85-only instruction seams stay off.
@ k_core_m85
Cortex-M85 primary (default): MVE/long-shift seams armed.
board_primary_core_t emu_primary_core(void)
The primary core the firmware targets (label + seam gating).
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
ra8_board_eth_pin_t pin
Pin.
static ra8_epaper_panel_t s_panel
Single-instance panel context.
Display descriptor loaded from a flat key=value panel file.
Every value the ra8_emulator CLI parse produces for the setup phase.
uint32_t stop_sym_thresh
–stop-sym stop threshold.
int click_x
–click column (-1 = unset).
const char * elf_path
Firmware ELF path (argv[1]).
const char * touch_seq_str
–touch-seq raw-point FIFO string.
int click_y
–click row (-1 = unset).
const char * stop_sym_name
–stop-sym watch global (NULL = off).
uint32_t trace_sym_n
Count of –trace-sym entries.
uint16_t view_w
Panel width in pixels.
uint32_t dump_sym_n
Count of –dump-sym entries.
const char * usb_in_str
–usb-in CDC bulk OUT string.
int battery_soc
–battery pct (-1 = model default).
bool usbhs_loop
–usbhs-loop chip-internal self-loop.
bool want_view
–view live window.
const char * panel_path
–panel descriptor path (NULL = none).
const char * trace_sym_names[k_trace_sym_max]
–trace-sym functions to log.
int button_press
–button: 1=SW1, 2=SW2, 0=none.
bool battery_opt
Any battery flag given.
const char * ns_elf_path
–ns second (NS) image path.
bool want_trace
–trace transition logging.
const char * save_sd_path
–save-sd dump path (NULL = off).
int reboot_count
–reboot N warm reboots.
uint16_t view_h
Panel height in pixels.
const char * dump_sym_names[k_dump_sym_max]
–dump-sym globals to read.
bool battery_charging
–charge given.
const char * record_dir
–record directory (NULL = off).
board_device_t emu_device
–device selected part (RA8D2 default).
bool size_set
–size given (wins over –panel).
const char * keys_str
–keys window-key path string.
const char * ppm_path
–ppm output path (NULL = off).
bool want_click
–click armed with valid coordinates.
uint32_t record_secs
–record-secs bound (0 = unbounded).
uint32_t rotate_deg
–rotate display rotation (0 default).
const char * input_str
–input console RX string.
Exact result for source open and bounded view acquisition.
emu_elf_io_status_t status
Semantic completion status.
One independently owned immutable raw-descriptor ELF source.
int fd
Owned regular-file descriptor, or -1 when closed.
uint64_t length
Stat-derived parsing bound.
Exact requirements and operation outcome.
int os_error
Captured errno for host mapping.
uint64_t logical_backing_bytes
Sum of the three aperture lengths.
emu_memmap_status_t status
Semantic completion status.
Exact result of a requirements or workspace operation.
size_t required_scratch_bytes
Exact caller scratch.
emu_presentation_status_t status
Semantic result.
size_t required_surface_bytes
Exact raw-fd length.
int os_error
Captured errno for I/O.
size_t supplied_scratch_bytes
Caller capacity.
Inputs controlling exact presentation requirements.
One independent owned surface plus non-owning bounded scratch.
Everything setup hands the run loop: engine, image, CLI products.
static RA8_INTERNAL void internal_main_bringup_peripherals(const emu_args_t *args)
Bring up the peripheral models and apply pre-boot input state.
static RA8_INTERNAL int internal_main_load_images(uc_engine *uc, const emu_args_t *args, emu_memmap_workspace_t *memory, emu_presentation_workspace_t *presentation, emu_elf_source_t *elf, emu_elf_source_t *ns_elf)
Load the primary and optional non-secure images into the engine.
static RA8_INTERNAL int internal_main_open_engine(uc_engine **uc_out, emu_memmap_workspace_t *memory)
Open the Unicorn engine, set the memory map, seed hardwired SCS regs.
static RA8_INTERNAL uint32_t internal_main_reset_vector(uc_engine *uc)
Read the reset vector, set the initial CPU registers, print the banner.
static RA8_INTERNAL bool internal_main_open_presentation(const emu_args_t *args, uint16_t view_w, uint16_t view_h, emu_presentation_workspace_t *workspace)
Create the exact fd-backed surface before engine/output mutation.
static RA8_INTERNAL emu_run_cfg_t internal_main_build_run_cfg(const emu_args_t *args, uc_engine *uc, emu_elf_source_t *elf, uint32_t pc, uint32_t vtor_base, uint16_t view_w, uint16_t view_h, const char *win_title, const uint32_t *dump_sym_addrs, uint32_t stop_sym_addr, emu_presentation_workspace_t *presentation, emu_memmap_workspace_t *memory)
Build the run configuration handed to emu_run_and_report().
static RA8_INTERNAL bool internal_main_open_memory(emu_memmap_workspace_t *memory)
Open the shared aliased-memory backing before engine mutation.
static RA8_INTERNAL int internal_main_run_loaded(const emu_args_t *args, emu_memmap_workspace_t *memory, emu_presentation_workspace_t *presentation, uc_engine *uc, emu_elf_source_t *elf, emu_elf_source_t *ns_elf, uint16_t view_w, uint16_t view_h, const char *win_title)
Resolve loaded firmware state, install seams, and run the emulator.
static uint8_t s_main_presentation_scratch[k_emu_presentation_max_scratch_bytes]
Explicit bounded presentation scratch owned by the process root.
static RA8_INTERNAL const char * internal_main_apply_panel(const emu_args_t *args, uint16_t *view_w, uint16_t *view_h)
Apply a –panel descriptor to the window size and title.
static RA8_INTERNAL void internal_main_install_core_seams(uc_engine *uc, const emu_elf_source_t *elf)
Install the core execution, exception, console, TrustZone + MPU seams.
static RA8_INTERNAL void internal_main_apply_button_battery(const emu_args_t *args)
Apply –button and –battery / –charge before the firmware boots.
static RA8_INTERNAL void internal_main_install_run_seams(uc_engine *uc, const emu_elf_source_t *elf, const emu_args_t *args, emu_memmap_workspace_t *memory)
Install the USB, symbol-trace, ISA-emulation and profiler seams.
static RA8_INTERNAL int internal_main_load_ns(uc_engine *uc, const char *ns_elf_path, emu_elf_source_t *elf, emu_elf_source_t *ns_out)
Read + load the optional –ns second (Non-Secure) image.
static RA8_INTERNAL int internal_main_load_primary(uc_engine *uc, const char *elf_path, emu_elf_source_t *elf_out)
Read + load the primary firmware ELF and print the load banner.
static RA8_INTERNAL void internal_main_arm_touch_seq(const char *touch_seq_str)
Arm the modelled GT911 injection FIFO from a –touch-seq string.
static RA8_INTERNAL void internal_main_feed_inputs(const emu_args_t *args)
Queue the –input / –keys / –usb-in injected byte streams.
static RA8_INTERNAL void internal_main_resolve_symbols(const emu_elf_source_t *elf, const emu_elf_source_t *ns_elf, const emu_args_t *args, uint32_t *dump_sym_addrs, uint32_t *stop_sym_addr)
Resolve the –dump-sym globals and the –stop-sym watch address.