ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
emu_idle.c
Go to the documentation of this file.
1
22
23#include "emu_exc.h"
24#include "emu_run.h"
25
53RA8_INTERNAL static bool
54internal_idle_back_edge(uc_engine* uc, uint32_t at, uint16_t hw, uint32_t aligned, bool* done)
55{
56 *done = false;
57 if ((hw & (uint16_t)k_op_bn_mask) != (uint16_t)k_op_bn_base) {
58 return false; /* not an unconditional b.n -- still inside the loop body */
59 }
60 *done = true;
61 /* Unconditional b.n: target = at + 4 + sign_extend(imm11) * 2. */
62 const uint32_t imm11 = (uint32_t)(hw & (uint16_t)k_op_bn_imm);
63 const int32_t off = (int32_t)(imm11 << (uint32_t)k_bn_imm_sext_shl) >> (int32_t)k_bn_imm_sext_shr;
64 if (off >= 0) {
65 return false; /* forward branch -- not a spin-in-place back-edge */
66 }
67 const uint32_t target = at + (uint32_t)k_thumb2_insn_bytes + (uint32_t)off;
68 if ((target > aligned) || ((aligned - target) > (uint32_t)k_idle_loop_max)) {
69 return false; /* back-edge does not bracket pc in a tight loop */
70 }
71 /* pc is enclosed by [target, at]: require a wait (cpsie/wfi) in the body. */
72 for (uint32_t k = target; k <= at; k += (uint32_t)k_thumb_hw_bytes) {
73 uint16_t bhw = 0U;
74 if (emu_mem_read(uc, (uint64_t)k, &bhw, sizeof(bhw)) != UC_ERR_OK) {
75 return false;
76 }
77 if ((bhw == (uint16_t)k_op_cpsie_i) || (bhw == (uint16_t)k_op_wfi)) {
78 return true;
79 }
80 }
81 return false; /* tight loop but no wait signature -- a busy loop, not idle */
82}
83
120bool idle_spin_at(uc_engine* uc, uint32_t pc)
121{
122 const uint32_t aligned = pc & ~1U;
123 uint16_t hw0 = 0U;
124 if (emu_mem_read(uc, (uint64_t)aligned, &hw0, sizeof(hw0)) != UC_ERR_OK) {
125 return false;
126 }
127 /* Case 1: the core is literally on a halt instruction. */
128 if ((hw0 == (uint16_t)k_op_branch_self) || (hw0 == (uint16_t)k_op_wfi)) {
129 return true;
130 }
131
132 /* Case 2: scan forward for the loop's unconditional backward back-edge. */
133 for (uint32_t j = 0U; j < (uint32_t)k_idle_scan_fwd; j++) {
134 const uint32_t at = aligned + (j * (uint32_t)k_thumb_hw_bytes);
135 uint16_t hw = 0U;
136 if (emu_mem_read(uc, (uint64_t)at, &hw, sizeof(hw)) != UC_ERR_OK) {
137 return false;
138 }
139 bool done = false;
140 const bool verdict = internal_idle_back_edge(uc, at, hw, aligned, &done);
141 if (done) {
142 return verdict;
143 }
144 }
145 return false;
146}
Cortex-M exception model constants and interfaces for ra8_emulator.
@ k_thumb2_insn_bytes
32-bit Thumb-2 instruction width.
Definition emu_exc.h:112
@ k_thumb_hw_bytes
Bytes per Thumb halfword.
Definition emu_exc.h:123
bool idle_spin_at(uc_engine *uc, uint32_t pc)
True if pc sits in a wait-for-interrupt spin (the core is idle).
Definition emu_idle.c:120
static RA8_INTERNAL bool internal_idle_back_edge(uc_engine *uc, uint32_t at, uint16_t hw, uint32_t aligned, bool *done)
Does the halfword at at close a tight idle loop around aligned?
Definition emu_idle.c:54
uc_err emu_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t count)
Read guest memory through the central access seam.
The chunked emulation run loop, report and exit-code mapping.
@ k_op_wfi
Thumb wfi (wait-for-interrupt).
Definition emu_run.h:53
@ k_idle_loop_max
Largest idle loop (bytes) that may hold PC.
Definition emu_run.h:61
@ k_idle_scan_fwd
Halfwords scanned ahead for a loop edge.
Definition emu_run.h:60
@ k_bn_imm_sext_shl
Shift imm11 bit10 up to bit31 (sign bit).
Definition emu_run.h:58
@ k_bn_imm_sext_shr
Arith >> sign-extends and scales imm by 2.
Definition emu_run.h:59
@ k_op_bn_mask
Mask selecting a Thumb T2 b.n opcode.
Definition emu_run.h:55
@ k_op_branch_self
Thumb "b ." (branch-to-self idle loop).
Definition emu_run.h:52
@ k_op_bn_base
Thumb T2 unconditional b.n base value.
Definition emu_run.h:56
@ k_op_cpsie_i
Thumb cpsie i (re-enable IRQ in a poll).
Definition emu_run.h:54
@ k_op_bn_imm
Thumb T2 b.n imm11 field mask.
Definition emu_run.h:57
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).