ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
board_periph_bkup.c
Go to the documentation of this file.
1
60
61#include <stdint.h>
62#include <stdio.h>
63
64#include "board_periph_block.h"
67
69typedef enum : uint64_t {
70 k_bkup_base = 0x4001EC40UL,
71 k_bkup_span = 0x180UL,
76
78typedef enum : uint8_t {
82
84typedef enum : uint32_t {
87
96
98typedef struct {
99 uint8_t vbtber;
100 uint32_t writes;
101 uint32_t dropped_prc1;
102 uint32_t dropped_vbae;
104
106
116{
117 s_bkup = (bkup_ctrl_t){};
118 /* HUM Ch 12.2.6 p 504 "Value after reset": VBAE = 1, so the access-enable
119 * bit is already armed out of reset (confirmed by a J-Link read of a live
120 * board). Modelling it as 0 would make a forgotten VBAE arm look fatal in
121 * the emulator when on silicon it is harmless. */
122 s_bkup.vbtber = (uint8_t)k_bkup_vbtber_reset;
123 /* s_bkup_vbtbkr is intentionally NOT cleared: it is the reset-retained
124 * domain that the survival demo depends on across a --reboot. */
125}
126
140RA8_INTERNAL static uint64_t internal_bkup_read(uc_engine* uc, uint64_t addr, unsigned size)
141{
142 (void)uc;
143 const uint64_t off = addr - (uint64_t)k_bkup_base;
144 if (off == (uint64_t)k_bkup_off_vbtber) {
145 return s_bkup.vbtber;
146 }
147 if (off >= (uint64_t)k_bkup_off_vbtbkr0) {
148 const uint64_t idx = off - (uint64_t)k_bkup_off_vbtbkr0;
149 uint64_t v = 0U;
150 for (unsigned i = 0U; (i < size) && ((idx + (uint64_t)i) < (uint64_t)k_bkup_reg_count); ++i) {
151 v |= (uint64_t)s_bkup_vbtbkr[idx + (uint64_t)i] << (8U * i);
152 }
153 return v;
154 }
155 return 0U;
156}
157
170RA8_INTERNAL static void
171internal_bkup_write(uc_engine* uc, uint64_t addr, unsigned size, uint64_t value)
172{
173 (void)uc;
174 const uint64_t off = addr - (uint64_t)k_bkup_base;
175 /* HUM Ch 13.1 Table 13.1 p 521 lists VBTBER and VBTBKRn (with the rest of
176 * the VBATT file) under PRC1. Every write below is discarded while that
177 * group is locked, with no fault and no flag -- the #131 silicon behaviour.
178 * Nested-if (not &&) keeps each decision single-condition. */
180 if (off >= (uint64_t)k_bkup_off_vbtbkr0) {
181 s_bkup.dropped_prc1++;
182 }
183 return;
184 }
185 if (off == (uint64_t)k_bkup_off_vbtber) {
186 s_bkup.vbtber = (uint8_t)value;
187 return;
188 }
189 if (off >= (uint64_t)k_bkup_off_vbtbkr0) {
190 /* HUM Ch 12.2.6 "VBTBER : VBATT Backup Enable Register" p 504: "You must
191 * write 1 to VBAE before accessing VBTBKR." Drop the write while VBAE = 0
192 * so a cleared-VBAE bug surfaces here (rw=BAD) exactly as on silicon. */
193 if ((s_bkup.vbtber & (uint8_t)k_bkup_vbtber_mask_vbae) == 0U) {
194 s_bkup.dropped_vbae++;
195 return;
196 }
197 const uint64_t idx = off - (uint64_t)k_bkup_off_vbtbkr0;
198 for (unsigned i = 0U; (i < size) && ((idx + (uint64_t)i) < (uint64_t)k_bkup_reg_count); ++i) {
199 s_bkup_vbtbkr[idx + (uint64_t)i] = (uint8_t)(value >> (8U * i));
200 }
201 s_bkup.writes++;
202 }
203}
204
214{
215 if (s_bkup.dropped_prc1 != 0U) {
216 /* Loud: firmware wrote VBTBKRn without unlocking PRCR.PRC1 (#131). */
217 (void)priv_emu_io_errf(
218 " VBATT-BKUP : VBTBKRn writes=%u dropped=%u (PRCR.PRC1 locked: unlock 0xA502)\n",
219 s_bkup.writes,
220 s_bkup.dropped_prc1);
221 return;
222 }
223 if (s_bkup.dropped_vbae != 0U) {
224 /* Loud: firmware touched VBTBKRn after clearing VBTBER.VBAE. */
225 (void)priv_emu_io_errf(
226 " VBATT-BKUP : VBTBKRn writes=%u dropped=%u (VBAE=0: enable VBTBER.VBAE)\n",
227 s_bkup.writes,
228 s_bkup.dropped_vbae);
229 return;
230 }
231 if (s_bkup.writes == 0U) {
232 return; /* Untouched: stay quiet. */
233 }
234 (void)priv_emu_io_errf(" VBATT-BKUP : VBTBKRn writes=%u (domain retained)\n", s_bkup.writes);
235}
236
239 .base = (uint64_t)k_bkup_base,
240 .span = (uint64_t)k_bkup_span,
241 .order = (uint32_t)k_bkup_block_order,
242 .read = internal_bkup_read,
244 .tick = nullptr,
245 .reset = internal_bkup_reset,
246 .report = internal_bkup_report,
247 .name = "VBATT-BKUP",
248};
249
251[[gnu::constructor]] RA8_INTERNAL static void internal_bkup_block_register(void)
252{
254}
static uint8_t s_bkup_vbtbkr[k_bkup_reg_count]
Retained VBTBKRn bytes – the battery-backed domain.
static void internal_bkup_reset(void)
Reset only the VBATT control state; the backup bytes are retained.
static uint64_t internal_bkup_read(uc_engine *uc, uint64_t addr, unsigned size)
MMIO read inside the VBATT backup window (width-aware).
bkup_order_t
Per-tick order slot for the VBATT-backup block (relative order).
@ k_bkup_block_order
After the LVD block; report order.
static void internal_bkup_block_register(void)
Register the VBATT-backup block before main (host constructor).
static void internal_bkup_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value)
MMIO write inside the VBATT backup window (width-aware).
static bkup_ctrl_t s_bkup
bkup_vbtber_mask_t
VBTBER field masks (HUM Ch 12.2.6 p 504).
@ k_bkup_vbtber_mask_vbae
VBAE @ bit 3: 1 = enable VBTBKRn access.
@ k_bkup_vbtber_reset
"Value after reset" row: VBAE = 1.
bkup_geom_t
VBATT backup window geometry (ra8_bkup_regs.h).
@ k_bkup_off_vbtber
VBTBER access-enable (at base).
@ k_bkup_off_vbtbkr0
VBTBKR0 (0x4001ED00 - 0x4001EC40).
@ k_bkup_base
VBTBER .
@ k_bkup_span
Covers VBTBER (0x00) .
@ k_bkup_reg_count
128 byte-wide VBTBKRn slots.
static const board_periph_block_t s_k_bkup_block
VBATT-backup block descriptor (self-registered with the core).
static void internal_bkup_report(void)
End-of-run VBATT-backup section: writes accepted / dropped this run.
Decentralized peripheral-block registry for the board emulator core.
void board_periph_register_block(const board_periph_block_t *block)
Register a peripheral block's descriptor with the core registry.
Module-private PRCR unlock state shared with the protected blocks.
bool priv_board_prcr_group_unlocked(uint16_t group_mask)
Report whether every bit in group_mask is currently unlocked.
@ k_board_prcr_grp1_lpm
PRC1: low-power modes + VBATT backup.
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.
-proof
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
VBATT control state (cleared by a reset; data is not).
uint8_t vbtber
VBTBER access-enable shadow (VBAE @ bit 3).
uint32_t dropped_prc1
VBTBKRn writes dropped: PRCR.PRC1 locked.
uint32_t writes
VBTBKRn writes accepted (report).
uint32_t dropped_vbae
VBTBKRn writes dropped: VBTBER.VBAE = 0.
A modelled peripheral block's self-description for the core registry.