ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
emu_cpu1.c
Go to the documentation of this file.
1
14
15#include "emu_cpu1.h"
16
17#include <stdio.h>
18#include <string.h>
19
20#include "emu_console.h"
21#include "emu_elf.h"
22#include "emu_engine.h"
24#include "emu_memmap.h"
25#include "emu_mmio.h"
26
39typedef enum : uint64_t {
40 k_cpu1_initvtor_addr = 0x4000F044UL,
41 k_cpu1_actcsr_addr = 0x4000F064UL,
42 k_cpu1_mram_base = 0x020C0000UL,
43 k_cpu1_mram_end = 0x02100000UL,
45
53
54static uc_engine* s_cpu1_uc;
55static bool s_cpu1_active;
56static bool s_cpu1_release_req;
57static uint32_t s_cpu1_initvtor;
58static uint32_t s_cpu1_pc;
59
60static uc_engine* s_cpu1_uc;
61static bool s_cpu1_active;
62static bool s_cpu1_release_req;
63static uint32_t s_cpu1_initvtor;
64static uint32_t s_cpu1_pc;
65
68void emu_cpu1_notify_mmio_write(uint64_t mmio_abs, uint64_t value)
69{
70 if (mmio_abs == (uint64_t)k_cpu1_initvtor_addr) {
71 s_cpu1_initvtor = (uint32_t)value;
72 } else if (mmio_abs == (uint64_t)k_cpu1_actcsr_addr) {
73 /* HUM Ch 2.9.1.9 "CPU1ACTCSR" p 130 -- a write is honored only with
74 * KEY=0xA5 in bits [15:8]; the firmware writes 0xA501 (KEY | ACTREQ).
75 * Model the key gate so a keyless ACTREQ does not release cpu1. */
76 const uint32_t key =
77 ((uint32_t)value >> (uint32_t)k_cpu1_actcsr_key_shift) & (uint32_t)k_cpu1_actcsr_key_mask;
78 if ((key == (uint32_t)k_cpu1_actcsr_key) &&
79 (((uint32_t)value & (uint32_t)k_cpu1_actcsr_actreq) != 0U)) {
80 s_cpu1_release_req = true;
81 }
82 }
83}
84
102RA8_INTERNAL static bool internal_cpu1_segment(const elf_exec_segment_t* segment, void* opaque)
103{
104 bool* const present = (bool*)opaque;
105 *present =
106 (segment->paddr >= (uint32_t)k_cpu1_mram_base) && (segment->paddr < (uint32_t)k_cpu1_mram_end);
107 return !*present;
108}
109
125{
126 bool present = false;
128 return present;
129}
130
159{
160 if (!internal_cpu1_image_present(elf)) {
161 return nullptr; /* single-core firmware -- no second engine. */
162 }
163 uc_engine* c1 = nullptr;
164 if (uc_open(UC_ARCH_ARM, (uc_mode)(UC_MODE_THUMB | UC_MODE_MCLASS), &c1) != UC_ERR_OK) {
165 return nullptr;
166 }
167 (void)uc_ctl_set_cpu_model(c1, UC_CPU_ARM_CORTEX_M33);
168 if ((emu_memmap_attach(memory, c1).status != k_emu_memmap_ok) || (load_elf(c1, elf) != 0)) {
169 (void)emu_memmap_detach(memory, c1);
170 (void)uc_close(c1);
171 return nullptr;
172 }
173 (void)priv_emu_io_errf(" cpu1 engine : Cortex-M33, shared SRAM + peripherals (dual-core)\n");
174 return c1;
175}
176
179{
181}
182
184{
185 if (s_cpu1_uc != nullptr) {
186 (void)emu_memmap_detach(memory, s_cpu1_uc);
187 (void)uc_close(s_cpu1_uc);
188 s_cpu1_uc = nullptr;
189 }
190 s_cpu1_active = false;
191 s_cpu1_release_req = false;
192}
193
197{
198 if (s_cpu1_uc == nullptr) {
199 return;
200 }
202 s_cpu1_release_req = false;
203 const uint32_t cpu1_sp = rd32(s_cpu1_uc, (uint64_t)s_cpu1_initvtor);
204 s_cpu1_pc = rd32(s_cpu1_uc, (uint64_t)s_cpu1_initvtor + 4U);
205 (void)uc_reg_write(s_cpu1_uc, UC_ARM_REG_SP, &cpu1_sp);
206 s_cpu1_active = true;
207 }
208 if (s_cpu1_active) {
209 const uc_err e1 =
210 uc_emu_start(s_cpu1_uc, (uint64_t)s_cpu1_pc | 1U, 0, 0, (size_t)k_cpu1_chunk_insns);
211 (void)uc_reg_read(s_cpu1_uc, UC_ARM_REG_PC, &s_cpu1_pc);
212 if (e1 != UC_ERR_OK) {
213 s_cpu1_active = false; /* cpu1 hit a fault -- halt it, cpu0 continues */
214 }
215 }
216}
Emulator text-console surfaces: UART echo, ITM/SWO echo, escapes.
dual_core_addr_t
CPU_CTRL registers + activation bit for the second core (cpu1).
Definition emu_cpu1.c:39
@ k_cpu1_actcsr_addr
CPU_CTRL.CPU1ACTCSR (16-bit).
Definition emu_cpu1.c:41
@ k_cpu1_mram_base
MRAM_CPU1: cpu1 image base.
Definition emu_cpu1.c:42
@ k_cpu1_mram_end
MRAM_CPU1 end (256 KiB).
Definition emu_cpu1.c:43
@ k_cpu1_initvtor_addr
CPU_CTRL.CPU1INITVTOR (32-bit).
Definition emu_cpu1.c:40
static uc_engine * internal_cpu1_engine_init(const emu_elf_source_t *elf, emu_memmap_workspace_t *memory)
Create the second emulator engine for cpu1 (Cortex-M33), if present.
Definition emu_cpu1.c:157
dual_core_bits_t
Definition emu_cpu1.c:46
@ k_cpu1_actcsr_key
KEY[15:8] required to honor a write.
Definition emu_cpu1.c:48
@ k_cpu1_actcsr_actreq
CPU1ACTCSR.ACTREQ -> release cpu1.
Definition emu_cpu1.c:47
@ k_cpu1_actcsr_key_mask
KEY byte mask after the shift.
Definition emu_cpu1.c:50
@ k_cpu1_actcsr_key_shift
KEY byte position (bits [15:8]).
Definition emu_cpu1.c:49
@ k_cpu1_chunk_insns
cpu1 instructions per interleave.
Definition emu_cpu1.c:51
void emu_cpu1_close(emu_memmap_workspace_t *memory)
Detach and close the optional cpu1 engine.
Definition emu_cpu1.c:183
static bool s_cpu1_release_req
CPU1ACTCSR.ACTREQ observed.
Definition emu_cpu1.c:56
static bool s_cpu1_active
cpu1 released and stepping.
Definition emu_cpu1.c:55
static bool internal_cpu1_segment(const elf_exec_segment_t *segment, void *opaque)
True if elf carries a PT_LOAD segment in the cpu1 MRAM window.
Definition emu_cpu1.c:102
void emu_cpu1_init(const emu_elf_source_t *elf, emu_memmap_workspace_t *memory)
Implementation of emu_cpu1_init() – detect + build the engine.
Definition emu_cpu1.c:178
static uint32_t s_cpu1_initvtor
Captured CPU1INITVTOR value.
Definition emu_cpu1.c:57
static uint32_t s_cpu1_pc
cpu1 run PC across interleaves.
Definition emu_cpu1.c:58
static bool internal_cpu1_image_present(const emu_elf_source_t *elf)
Detect a PT_LOAD segment in the cpu1 MRAM window.
Definition emu_cpu1.c:124
static uc_engine * s_cpu1_uc
2nd engine for cpu1 (NULL if N/A).
Definition emu_cpu1.c:54
void emu_cpu1_step(void)
Implementation of emu_cpu1_step() – release boot + one interleave.
Definition emu_cpu1.c:196
void emu_cpu1_notify_mmio_write(uint64_t mmio_abs, uint64_t value)
Implementation of emu_cpu1_notify_mmio_write() – release capture.
Definition emu_cpu1.c:68
Second-core (cpu1, Cortex-M33) engine: release watch, boot, stepping.
ELF32 image services for the board emulator (load / symbols / vectors).
uint32_t elf_foreach_load_segment(const emu_elf_source_t *elf, elf_exec_segment_fn fn, void *ctx)
Walk every non-empty, bounds-checked PT_LOAD segment.
Definition emu_elf.c:172
int load_elf(uc_engine *uc, const emu_elf_source_t *elf)
Load ELF32 PT_LOAD segments into emulated memory at their LMA.
Definition emu_elf.c:248
Shared Unicorn engine access utilities for the board emulator.
static uint32_t rd32(uc_engine *uc, uint64_t addr)
Read a 32-bit little-endian word from emulated memory.
Definition emu_engine.h:67
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.
Shared aliased-memory backing and Unicorn memory-map bindings.
struct emu_memmap_workspace emu_memmap_workspace_t
Independent aperture backing with at most two engine bindings.
@ k_emu_memmap_ok
Operation completed exactly.
Definition emu_memmap.h:63
emu_memmap_result_t emu_memmap_attach(emu_memmap_workspace_t *workspace, uc_engine *uc)
Map one Unicorn engine onto the shared aperture backing.
Definition emu_memmap.c:463
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
Sparse MMIO model of the Renesas peripheral space.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
One executable PT_LOAD segment, already bounds-checked against the image.
Definition emu_elf.h:238
uint32_t paddr
Segment physical load address.
Definition emu_elf.h:242
One independently owned immutable raw-descriptor ELF source.
Definition emu_elf.h:91