ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
emu_run_report.c
Go to the documentation of this file.
1
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <unistd.h>
23
24#include "board_net.h"
25#include "board_periph.h"
26#include "board_periph_sd.h"
27#include "board_view.h"
28#include "emu_console.h"
29#include "emu_cpu1.h"
31#include "emu_engine.h"
32#include "emu_exc.h"
34#include "emu_mmio.h"
35#include "emu_prof.h"
36#include "emu_run_internal.h"
37#include "emu_seams.h"
38#include "emu_view.h"
39
54typedef struct {
55 uc_err err;
56 uint32_t run_pc;
57 uint32_t chunks;
58 uint32_t max_chunks;
59 double wall_s;
61 bool timed_out;
67
83{
84 bool sd_att = false;
85 uint64_t sd_b = 0U;
86 uint8_t sd_f = 0U;
87 const char* sd_l = nullptr;
88 board_sd_info(&sd_att, &sd_b, &sd_f, &sd_l);
89 const uint64_t gib_bytes = (uint64_t)k_size_kib * (uint64_t)k_size_kib * (uint64_t)k_size_kib;
90 const uint64_t mib_bytes = (uint64_t)k_size_kib * (uint64_t)k_size_kib;
91 const bool sd_gb = (sd_b >= gib_bytes);
92 const unsigned long sd_sz =
93 sd_gb ? (unsigned long)(sd_b / gib_bytes) : (unsigned long)(sd_b / mib_bytes);
94 const char* sd_u = sd_gb ? "GB" : "MB";
95 if (sd_att && (sd_f != 0U)) {
96 (void)priv_emu_io_errf(" SD card : %lu %s FAT%u '%s' (created by --sd-new)\n",
97 sd_sz,
98 sd_u,
99 (unsigned)sd_f,
100 (sd_l != nullptr) ? sd_l : "");
101 } else if (sd_att) {
102 (void)priv_emu_io_errf(" SD card : %lu %s image attached\n", sd_sz, sd_u);
103 }
104}
105
124RA8_INTERNAL static void internal_run_print_stop_summary(uc_engine* uc, const run_stop_t* st)
125{
126 (void)priv_emu_io_errf("\nra8_emulator: stopped -- %s%s%s%s%s%s\n",
127 uc_strerror(st->err),
128 st->timed_out ? " (wall-clock budget reached)" : "",
129 st->idle_stopped ? " (idle steady-state)" : "",
130 st->usb_stopped ? " (USB enumerated)" : "",
131 st->stop_sym_hit ? " (--stop-sym threshold reached)" : "",
132 st->prof_stopped ? " (profile: boot complete)" : "");
133 (void)priv_emu_io_errf(" final PC : 0x%08X\n", st->run_pc);
134 if (emu_exc_bkpt_hit()) {
135 (void)priv_emu_io_errf(" => firmware executed a BKPT @ 0x%08X (deliberate trap: "
136 "Default_Handler / failed assert / fault give-up)\n",
138 }
139 (void)priv_emu_io_errf(" chunks run : %u SysTick ticks: %u\n",
140 st->chunks,
142 if (emu_mve_emulated_count() > 0U) {
143 (void)priv_emu_io_errf(" MVE (Helium) : %llu instruction(s) emulated "
144 "(M85 vector ops the M33 "
145 "core lacks)\n",
146 (unsigned long long)emu_mve_emulated_count());
147 }
148 if (emu_lob_emulated_count() > 0U) {
149 (void)priv_emu_io_errf(" LOB (loop) : %llu DLS/LE instruction(s) "
150 "emulated (M85 hardware-loop "
151 "ops)\n",
152 (unsigned long long)emu_lob_emulated_count());
153 }
154 prof_report();
155 (void)priv_emu_io_errf(" exceptions : %u PendSV %u SVCall (real Cortex-M entry/return)\n",
158 (void)priv_emu_io_errf(" touch clicks : %u drained via ra8_touch -> I3C -> GT911\n",
160 /* Emit any console bytes still buffered without a trailing newline. */
162 /* Peripheral-model observability: LED transitions, timer totals, IRQ counts,
163 * SCI byte totals. */
169}
170
187{
188 if (st->timed_out && !st->idle_stopped && !st->usb_stopped && !st->stop_sym_hit &&
189 !st->prof_stopped && !emu_exc_bkpt_hit()) {
190 /* The wall-clock guard fired (clock() is CPU-time, so a heavily-loaded host
191 * burns the budget faster). This is a TRUNCATED run, NOT a completed one --
192 * say so plainly, and do NOT print the "EXECUTED to the run budget" line a
193 * full-budget run prints. Conflating the two let a load-correlated
194 * truncation masquerade as success, dropping a deterministic banner without
195 * failing the gate (#168). A caller that wants the run bounded by a
196 * deterministic event (not by CPU-time) should pass RA8_EMU_STOP_ON /
197 * RA8_EMU_MAX_CHUNKS. */
198 (void)priv_emu_io_errf(" => ra8_emulator TRUNCATED by the wall-clock guard at chunk %u of %u "
199 "(%.0fs CPU-time elapsed); this is NOT a full-budget run (host "
200 "overloaded -- see #168).\n",
201 st->chunks,
202 st->max_chunks,
203 st->wall_s);
204 } else if (((st->err == UC_ERR_OK) || st->idle_stopped || st->usb_stopped || st->stop_sym_hit ||
205 st->prof_stopped) &&
206 !emu_exc_bkpt_hit()) {
207 if (st->idle_stopped) {
208 (void)priv_emu_io_errf(" => firmware EXECUTED to the run budget (idle steady-state: no "
209 "observable change for %u chunks, stopped at chunk %u).\n",
211 st->chunks);
212 } else if (st->usb_stopped) {
213 (void)priv_emu_io_errf(" => firmware EXECUTED to the run budget (USB enumerated: device "
214 "CONFIGURED, stopped at chunk %u).\n",
215 st->chunks);
216 } else {
217 (void)priv_emu_io_errf(" => firmware EXECUTED to the run budget (no "
218 "invalid opcode / fault).\n");
219 }
220 }
221}
222
239RA8_INTERNAL static void internal_run_print_dump_syms(uc_engine* uc, const emu_run_cfg_t* cfg)
240{
241 /* --dump-sym: read each resolved global from Unicorn memory and print its
242 * 32-bit value (and the address), so a test can probe firmware state (e.g. an
243 * init-step or mismatch counter) after the run without a debugger. */
244 for (uint32_t d = 0U; d < cfg->dump_sym_n; d++) {
245 if (cfg->dump_sym_addrs[d] == 0U) {
246 (void)priv_emu_io_errf(" dump-sym : %s = <unresolved>\n", cfg->dump_sym_names[d]);
247 continue;
248 }
249 uint32_t v = 0U;
250 if (emu_mem_read(uc, (uint64_t)cfg->dump_sym_addrs[d], &v, sizeof(v)) == UC_ERR_OK) {
251 (void)priv_emu_io_errf(" dump-sym : %s @0x%08X = %u (0x%08X)\n",
252 cfg->dump_sym_names[d],
253 cfg->dump_sym_addrs[d],
254 v,
255 v);
256 } else {
257 (void)priv_emu_io_errf(" dump-sym : %s @0x%08X = <unreadable>\n",
258 cfg->dump_sym_names[d],
259 cfg->dump_sym_addrs[d]);
260 }
261 }
262}
263
265{
266 emu_view_mark_stopped(st->run_pc); /* final / held frame shows "parked". */
267 const run_stop_t stop = {
268 .err = st->err,
269 .run_pc = st->run_pc,
270 .chunks = st->chunks,
271 .max_chunks = st->guards.max_chunks,
272 .wall_s = st->guards.wall_s,
273 .idle_stop_chunks = st->guards.idle_stop_chunks,
274 .timed_out = st->timed_out,
275 .idle_stopped = st->idle_stopped,
276 .usb_stopped = st->usb_stopped,
277 .stop_sym_hit = st->stop_sym_hit,
278 .prof_stopped = st->prof_stopped,
279 };
283}
284
286{
287 const emu_run_cfg_t* cfg = st->cfg;
288 if ((cfg->ppm_path != nullptr) && (st->presentation->fd >= 0)) {
289 const bool built = build_composite(cfg->uc, st->presentation, cfg->win_title);
290 if (built && (write_ppm(cfg->ppm_path, st->presentation) == 0)) {
291 (void)priv_emu_io_errf(" wrote %s (%ux%u)\n",
292 cfg->ppm_path,
293 (unsigned)st->comp_w,
294 (unsigned)st->comp_h);
295 } else {
296 (void)priv_emu_io_errf(" could not write %s\n", cfg->ppm_path);
297 }
298 }
299 if (cfg->record_dir != nullptr) {
300 (void)priv_emu_io_errf(" recorded %u frame(s) to %s (%ux%u, ~%u fps)\n",
301 st->rec_frames,
302 cfg->record_dir,
303 (unsigned)st->comp_w,
304 (unsigned)st->comp_h,
305 (unsigned)k_record_fps);
306 }
307}
308
310{
311 const emu_run_cfg_t* cfg = st->cfg;
312 if (st->view == nullptr) {
313 return;
314 }
315 if (!st->closed) { /* run ended on its own -- keep the last frame up until
316 closed */
317 if (build_composite(cfg->uc, st->presentation, cfg->win_title)) {
319 }
320 (void)priv_emu_io_errf("ra8_emulator: run ended; close the window to exit\n");
321 while (!board_view_pump(st->view)) {
322 (void)usleep((useconds_t)k_view_idle_us);
323 }
324 }
326}
327
329{
330 const emu_run_cfg_t* cfg = st->cfg;
331 if (cfg->save_sd_path != nullptr) {
332 (void)board_sd_save(cfg->save_sd_path);
333 }
335 (void)priv_emu_elf_source_close(cfg->elf); /* warm reboot source lifetime ends here. */
337 (void)emu_memmap_detach(cfg->memory, cfg->uc);
338 (void)uc_close(cfg->uc);
339 (void)emu_memmap_close(cfg->memory);
340
341 emu_exit_t exit_code = k_emu_exit_ok;
342 if (emu_exc_bkpt_hit()) {
343 exit_code = k_emu_exit_bkpt;
344 } else if (st->err != UC_ERR_OK) {
345 exit_code = k_emu_exit_fault;
346 } else if (st->timed_out) {
347 exit_code = k_emu_exit_timeout;
348 }
349 return (int)exit_code;
350}
Virtual network peer for ra8_emulator – talks TCP/IP to the firmware.
void board_net_report(void)
Print the end-of-run network summary (link / ARP / ping / TCP).
Definition board_net.c:829
Register-accurate peripheral-model framework for the board emulator.
uint8_t board_periph_sci_console_channel(void)
The SCI channel the EK-RA8D2 console (J-Link OB VCOM) uses.
void board_periph_report(uc_engine *uc)
Print the peripheral-model section of the end-of-run summary.
uint32_t board_periph_touch_reported(void)
Count of touch contacts the firmware has drained from the GT911 model.
SD-card-over-SPI device model for ra8_emulator (attached to SPI_B).
bool board_sd_save(const char *path)
Transactionally publish the current SD-card image to a file.
void board_sd_info(bool *attached, uint64_t *bytes, uint8_t *fat_bits, const char **label)
Read back the attached card's summary (for the status view / report).
Minimal self-contained macOS window for the board emulator.
bool board_view_pump(board_view_t *view)
Drain pending UI events; report whether the window was closed.
void board_view_present(board_view_t *view, emu_presentation_workspace_t *presentation)
Snapshot an RGB565 fd surface and request a redraw.
void board_view_close(board_view_t *view)
Close the window and release its resources.
Emulator text-console surfaces: UART echo, ITM/SWO echo, escapes.
void console_flush_line(uint8_t channel)
Flush the pending [uart] line to injected output sink with its channel prefix.
Second-core (cpu1, Cortex-M33) engine: release watch, boot, stepping.
void emu_cpu1_close(emu_memmap_workspace_t *memory)
Detach and close the optional cpu1 engine.
Definition emu_cpu1.c:183
Private raw-descriptor ELF source operations.
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.
Cortex-M exception model constants and interfaces for ra8_emulator.
bool emu_exc_bkpt_hit(void)
Whether the firmware executed a BKPT (deliberate trap / give-up).
Definition emu_exc.c:955
uint32_t emu_exc_pendsv_takes(void)
PendSV exceptions taken this run (report + idle signature).
Definition emu_exc.c:973
uint32_t emu_exc_bkpt_pc(void)
PC of the BKPT that halted the run.
Definition emu_exc.c:961
uint32_t emu_exc_svc_takes(void)
SVCall exceptions taken this run (report + idle signature).
Definition emu_exc.c:979
uint32_t emu_exc_systick_fires(void)
SysTick exceptions taken this run (report telemetry).
Definition emu_exc.c:967
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.
bool emu_memmap_detach(emu_memmap_workspace_t *workspace, uc_engine *uc)
Remove one engine binding before closing that Unicorn engine.
Definition emu_memmap.c:486
bool emu_memmap_close(emu_memmap_workspace_t *workspace)
Release every host aperture mapping after all engines detached.
Definition emu_memmap.c:500
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.
void emu_mmio_print_counts(void)
Print the run-end MMIO counters line to injected error sink.
Definition emu_mmio.c:234
void emu_mmio_print_bgc_and_table(void)
Print the BG_BGC witness and the per-address MMIO table to injected error sink.
Definition emu_mmio.c:243
bool emu_presentation_close(emu_presentation_workspace_t *workspace)
Close one owned presentation descriptor and invalidate the workspace.
Firmware profiler (RA8_EMU_PROFILE): sampling, hooks, reports.
void prof_report(void)
Print the top hot functions (by wall time or instruction count).
Definition emu_prof.c:892
emu_exit_t
Process exit codes for the #67 run-every-example matrix.
Definition emu_run.h:76
@ k_emu_exit_ok
Clean run-to-budget (no fault/BKPT/timeout).
Definition emu_run.h:77
@ k_emu_exit_bkpt
Firmware executed a BKPT (assert/give-up).
Definition emu_run.h:79
@ k_emu_exit_timeout
Wall-clock budget reached before a clean stop.
Definition emu_run.h:80
@ k_emu_exit_fault
Emulation fault / invalid access ended it.
Definition emu_run.h:78
@ k_size_kib
One kibibyte (k suffix multiplier).
Definition emu_run.h:104
Shared run-loop state + cross-TU run helpers (ra8_emulator internal).
static RA8_INTERNAL void internal_run_print_dump_syms(uc_engine *uc, const emu_run_cfg_t *cfg)
Print each –dump-sym probe's value from emulated memory.
void priv_run_report(const run_loop_t *st)
Print the run-end report (stop summary, verdict, –dump-sym probes).
static RA8_INTERNAL void internal_run_print_stop_summary(uc_engine *uc, const run_stop_t *st)
Print the stop banner, telemetry counters and peripheral summaries.
static RA8_INTERNAL void internal_run_print_sd_summary(void)
Print the attached microSD summary line of the run report.
void priv_run_write_outputs(const run_loop_t *st)
Write the –ppm snapshot and the –record summary line.
static RA8_INTERNAL void internal_run_print_verdict(const run_stop_t *st)
Print the run verdict: TRUNCATED warning or EXECUTED-to-budget.
int priv_run_cleanup(const run_loop_t *st)
Save the SD image, close owned descriptors + engine, map the exit code.
void priv_run_hold_view(const run_loop_t *st)
Hold the live window on the final frame until the user closes it.
Armv8.1-M instruction-emulation seams (M85 ops on Unicorn's M33).
uint64_t emu_mve_emulated_count(void)
Count of MVE instructions emulated this run (run-end telemetry).
uint64_t emu_lob_emulated_count(void)
Count of LOB (DLS/LE) instructions emulated this run (telemetry).
Board-view presentation: frames, composition, input routing, panels.
void emu_view_mark_stopped(uint32_t pc)
Mark the run ended: the held frame shows "parked" at pc.
Definition emu_view.c:591
@ k_record_fps
Recorded frames per emulated second.
Definition emu_view.h:58
@ k_view_idle_us
~60 Hz idle pump after the run ends.
Definition emu_view.h:47
int write_ppm(const char *path, const emu_presentation_workspace_t *presentation)
Write an RGB565 frame to a binary PPM (P6) for headless inspection.
bool build_composite(uc_engine *uc, emu_presentation_workspace_t *presentation, const char *app_name)
Stream the panel and status sidebar into a raw-fd surface.
Definition emu_view.c:371
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
int fd
Owned unlinked descriptor, or -1.
Everything setup hands the run loop: engine, image, CLI products.
Definition emu_run.h:122
const char * record_dir
–record directory (NULL when unused).
Definition emu_run.h:133
const char * win_title
Window / sidebar caption.
Definition emu_run.h:145
emu_elf_source_t * elf
Open caller-owned firmware source.
Definition emu_run.h:124
const char * ppm_path
–ppm output path (NULL when unused).
Definition emu_run.h:132
uc_engine * uc
The prepared cpu0 engine.
Definition emu_run.h:123
const uint32_t * dump_sym_addrs
–dump-sym resolved addresses.
Definition emu_run.h:141
const char * save_sd_path
–save-sd dump path (NULL when unused).
Definition emu_run.h:137
emu_memmap_workspace_t * memory
Authoritative aliased-memory backing.
Definition emu_run.h:147
const char *const * dump_sym_names
–dump-sym names (argv-backed).
Definition emu_run.h:140
uint32_t dump_sym_n
Count of –dump-sym entries.
Definition emu_run.h:142
emu_presentation_workspace_t * presentation
Owned streamed frame surface.
Definition emu_run.h:146
uint32_t max_chunks
Outer-chunk budget.
Definition emu_run.h:166
uint32_t idle_stop_chunks
Idle steady-state stop (0 = off).
Definition emu_run.h:169
double wall_s
CPU-time guard bound, seconds.
Definition emu_run.h:167
The whole run's mutable state, threaded through the phase helpers.
bool timed_out
Wall-clock guard fired.
emu_presentation_workspace_t * presentation
Owned raw-fd presentation surface.
bool usb_stopped
USB / banner early stop fired.
uint16_t comp_h
Composite (panel + sidebar) height.
bool closed
Live window was closed.
board_view_t * view
Live window (NULL when headless).
run_guards_t guards
Env-tunable budgets + stop conditions.
uint32_t rec_frames
–record frames written.
bool prof_stopped
Profiler stop fired.
const emu_run_cfg_t * cfg
Setup products (engine, image, CLI knobs).
uint32_t run_pc
Current resume PC.
uint16_t comp_w
Composite (panel + sidebar) width.
bool idle_stopped
Idle steady-state stop fired.
bool stop_sym_hit
–stop-sym threshold reached.
uc_err err
Latest uc_emu_start status.
uint32_t chunks
Outer chunks executed so far.
How the run ended: final engine status plus every stop flag.
uc_err err
Final uc_emu_start status.
bool idle_stopped
Idle steady-state stop fired.
uint32_t chunks
Outer chunks executed.
bool usb_stopped
USB early stop (CONFIGURED / STOP_ON hit).
bool stop_sym_hit
–stop-sym threshold reached.
uint32_t max_chunks
The chunk budget in force.
uint32_t run_pc
PC where the run stopped.
bool prof_stopped
Profiler compute-idle stop fired.
bool timed_out
Wall-clock guard fired (truncated run).
double wall_s
The wall-clock bound in force (seconds).
uint32_t idle_stop_chunks
RA8_EMU_IDLE_STOP window (0 = off).