ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
board_periph_mram.c
Go to the documentation of this file.
1
59
60#include <stdint.h>
61#include <stdio.h>
62#include <string.h>
63
64#include "board_periph_block.h"
66
77typedef enum : uint64_t {
78 k_mram_reg_base = 0x4013E000UL,
79 k_mram_reg_span = 0x00000100UL,
80 k_mram_off_msaddr = 0x0030UL,
81 k_mram_off_mstatr = 0x0080UL,
82 k_mram_off_mentryr = 0x0084UL,
84
86typedef enum : uint64_t {
87 k_maci_base = 0x40120000UL,
88 k_maci_span = 0x00000010UL,
90
103typedef enum : uint64_t {
104 k_mrpgm_base = 0x4013F000UL,
105 k_mrpgm_span = 0x00000100UL,
106 k_mrpgm_words = 0x00000100UL / 4UL,
107 k_mrpgm_off_mrcps = 0x0010UL,
109
111typedef enum : uint8_t {
114
116typedef enum : uint32_t {
118 k_mram_mstatr_mrdy = 0x00008000U,
119 k_mram_mstatr_ilglerr = 0x00004000U,
120 k_mram_mstatr_ilgcom = 0x00800000U,
122
124typedef enum : uint32_t {
125 k_mram_off_mastat = 0x0010UL,
129
152typedef enum : uint32_t {
153 k_mram_pgm_lo = 0x02E07600UL,
154 k_mram_pgm_hi = 0x02E179F0UL,
156
158typedef enum : uint32_t {
163} maci_cmd_t;
164
166typedef enum : uint8_t {
171
173typedef enum : uint32_t {
174 k_mram_reg_words = (uint32_t)(k_mram_reg_span / 4UL),
179} mram_lit_t;
180
182typedef struct {
185 uint32_t msaddr;
187 uint32_t payload_len;
188 uint8_t maci_state;
189 uint8_t pe_active;
190 uint32_t programs;
191 uint32_t rejected;
193
195
209RA8_INTERNAL static uint64_t internal_mram_reg_read(uc_engine* uc, uint64_t addr, unsigned size)
210{
211 (void)uc;
212 (void)size;
213 const uint64_t off = addr - (uint64_t)k_mram_reg_base;
214 if (off == (uint64_t)k_mram_off_mentryr) {
215 return (s_mram.pe_active != 0U) ? (uint64_t)k_mram_mentryr_pe_bit : 0U;
216 }
217 if (off == (uint64_t)k_mram_off_mstatr) {
218 return (uint64_t)k_mram_mstatr_mrdy; /* command complete, no error bits */
219 }
220 if ((off / 4U) >= (uint64_t)k_mram_reg_words) {
221 return 0U;
222 }
223 return s_mram.regs[off / 4U];
224}
225
238RA8_INTERNAL static void
239internal_mram_reg_write(uc_engine* uc, uint64_t addr, unsigned size, uint64_t value)
240{
241 (void)uc;
242 (void)size;
243 const uint64_t off = addr - (uint64_t)k_mram_reg_base;
244 if (off == (uint64_t)k_mram_off_mentryr) {
245 s_mram.pe_active = (((uint32_t)value & (uint32_t)k_mram_mentryr_pe_bit) != 0U) ? 1U : 0U;
246 }
247 if (off == (uint64_t)k_mram_off_msaddr) {
248 s_mram.msaddr = (uint32_t)value;
249 }
250 if ((off / 4U) < (uint64_t)k_mram_reg_words) {
251 s_mram.regs[off / 4U] = (uint32_t)value;
252 }
253}
254
269{
270 s_mram.regs[(uint32_t)k_mram_off_mstatr / 4U] |=
271 (uint32_t)k_mram_mstatr_ilgcom | (uint32_t)k_mram_mstatr_ilglerr;
272 s_mram.regs[(uint32_t)k_mram_off_mastat / 4U] |=
273 (uint32_t)k_mram_mastat_cmdlk | (uint32_t)k_mram_mastat_mreae;
274 s_mram.rejected++;
275}
276
286RA8_INTERNAL static void internal_maci_commit(uc_engine* uc)
287{
288 if (s_mram.payload_len == 0U) {
289 return;
290 }
291 /* HUM Ch 59.7.4.5 Table 59.15 p 3592: the Program command only accepts the
292 * option-setting / OTP addresses in [k_mram_pgm_lo, k_mram_pgm_hi]. Anything
293 * else -- notably the 0x2700_0000 "extra-MRAM data area" that exists in no
294 * RA8D2 memory map -- is an illegal command on silicon. This model used to
295 * write it straight through to mapped RAM, which let ra8_io_mram_demo round
296 * trip in the emulator while the bench returned Error=516 (#170). Reject it
297 * here so the emulator reports the bench result. */
298 if (s_mram.msaddr < (uint32_t)k_mram_pgm_lo) {
300 return;
301 }
302 if (s_mram.msaddr > (uint32_t)k_mram_pgm_hi) {
304 return;
305 }
306 (void)emu_mem_write(uc, (uint64_t)s_mram.msaddr, s_mram.payload, (size_t)s_mram.payload_len);
307 s_mram.programs++;
308}
309
322RA8_INTERNAL static void
323internal_maci_write(uc_engine* uc, uint64_t addr, unsigned size, uint64_t value)
324{
325 (void)addr;
326 if (size == 2U) {
327 if (s_mram.maci_state == (uint8_t)k_maci_collect) {
328 if ((s_mram.payload_len + 2U) <= (uint32_t)k_mram_payload_max) {
329 s_mram.payload[s_mram.payload_len] = (uint8_t)(value & (uint64_t)k_mram_byte_mask);
330 s_mram.payload[s_mram.payload_len + 1U] =
331 (uint8_t)((value >> (uint64_t)k_mram_hi_shift) & (uint64_t)k_mram_byte_mask);
332 s_mram.payload_len += 2U;
333 }
334 }
335 return;
336 }
337 const uint32_t byte = (uint32_t)value & (uint32_t)k_mram_byte_mask;
338 /* Either opener (Program 0xE8 or Config-Set 0x40) starts a command; kept as
339 * two single-condition checks so the model carries no compound decision. */
340 if (byte == (uint32_t)k_maci_cmd_program) {
341 s_mram.maci_state = (uint8_t)k_maci_opener1;
342 return;
343 }
344 if (byte == (uint32_t)k_maci_cmd_config_set) {
345 s_mram.maci_state = (uint8_t)k_maci_opener1;
346 return;
347 }
348 if ((byte == (uint32_t)k_maci_cmd_word_n) && (s_mram.maci_state == (uint8_t)k_maci_opener1)) {
349 s_mram.maci_state = (uint8_t)k_maci_collect;
350 s_mram.payload_len = 0U;
351 return;
352 }
353 if ((byte == (uint32_t)k_maci_cmd_final) && (s_mram.maci_state == (uint8_t)k_maci_collect)) {
355 s_mram.maci_state = (uint8_t)k_maci_idle;
356 return;
357 }
358 s_mram.maci_state = (uint8_t)k_maci_idle; /* forced-stop / status-clear / unknown */
359}
360
374RA8_INTERNAL static uint64_t internal_maci_read(uc_engine* uc, uint64_t addr, unsigned size)
375{
376 (void)uc;
377 (void)addr;
378 (void)size;
379 return 0U;
380}
381
395RA8_INTERNAL static uint64_t internal_mrpgm_read(uc_engine* uc, uint64_t addr, unsigned size)
396{
397 (void)uc;
398 (void)size;
399 const uint64_t off = addr - (uint64_t)k_mrpgm_base;
400 if (off == (uint64_t)k_mrpgm_off_mrcps) {
401 return (uint64_t)k_mrcps_ready; /* always idle-and-ready: no MACI sequencing here. */
402 }
403 if ((off / 4U) >= (uint64_t)k_mrpgm_words) {
404 return 0U;
405 }
406 return s_mram.pgm_regs[off / 4U]; /* MRCPC0/1 / MRCFLR read back their written value. */
407}
408
421RA8_INTERNAL static void
422internal_mrpgm_write(uc_engine* uc, uint64_t addr, unsigned size, uint64_t value)
423{
424 (void)uc;
425 (void)size;
426 const uint64_t off = addr - (uint64_t)k_mrpgm_base;
427 /* MRCPC0/1 (program gate), MRCFLR (flush), MRCPS (W1C error clear): the mapped
428 * MRAM window already accepts the direct STR programming, so these only need
429 * to shadow so a gate read-back sees the key that was written. */
430 if ((off / 4U) < (uint64_t)k_mrpgm_words) {
431 s_mram.pgm_regs[off / 4U] = (uint32_t)value;
432 }
433}
434
444{
445 (void)memset(&s_mram, 0, sizeof(s_mram));
446}
447
457{
458 if (s_mram.rejected != 0U) {
459 /* Loud: a Program aimed outside HUM Table 59.15's option-setting window
460 * is an illegal command on silicon (command-locked, MSTATR.ILGCOMERR). */
461 (void)priv_emu_io_errf(" Extra-MRAM : %u MACI program commands, %u REJECTED "
462 "(MSADDR outside HUM Table 59.15 option-setting window)\n",
463 s_mram.programs,
464 s_mram.rejected);
465 return;
466 }
467 if (s_mram.programs == 0U) {
468 return;
469 }
470 (void)priv_emu_io_errf(" Extra-MRAM : %u MACI program commands\n", s_mram.programs);
471}
472
475 .base = (uint32_t)k_mram_reg_base,
476 .span = (uint32_t)k_mram_reg_span,
477 .order = (uint32_t)k_mram_block_order,
480 .tick = nullptr,
481 .reset = internal_mram_reset,
482 .report = internal_mram_report,
483 .name = "MRAM",
484};
485
488 .base = (uint32_t)k_maci_base,
489 .span = (uint32_t)k_maci_span,
490 .order = (uint32_t)k_mram_block_order,
491 .read = internal_maci_read,
493 .tick = nullptr,
494 .reset = nullptr,
495 .report = nullptr,
496 .name = "MACI",
497};
498
501 .base = (uint32_t)k_mrpgm_base,
502 .span = (uint32_t)k_mrpgm_span,
503 .order = (uint32_t)k_mram_block_order,
504 .read = internal_mrpgm_read,
506 .tick = nullptr,
507 .reset = nullptr,
508 .report = nullptr,
509 .name = "MRAM-pgm",
510};
511
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.
mram_pgm_window_t
Legal MSADDR window for the MACI Program command (HUM Table 59.15).
@ k_mram_pgm_lo
First legal Program MSADDR.
@ k_mram_pgm_hi
Last legal Program MSADDR.
static RA8_INTERNAL void internal_mram_block_register(void)
Register the MRAM + MACI blocks before main (host constructor).
static mram_state_t s_mram
mram_reg_map_t
MRMS program-mode register sub-window (ra8_flash_regs.h).
@ k_mram_off_mentryr
MENTRYR : program-mode entry.
@ k_mram_reg_base
MRMS program-mode sub-window base.
@ k_mram_reg_span
Covers MSADDR / MSTATR / MENTRYR.
@ k_mram_off_mstatr
MSTATR : extra-MRAM status.
@ k_mram_off_msaddr
MSADDR : MACI start address.
maci_state_t
MACI collection state.
@ k_maci_collect
Opener complete, collecting words.
@ k_maci_idle
No command in progress.
@ k_maci_opener1
Saw an opener (0xE8/0x40), expecting N.
static const board_periph_block_t s_k_mrpgm_block
Code-MRAM program-control block descriptor (self-registered).
mram_lit_t
Sizing + report-order constants.
@ k_mram_byte_mask
One byte.
@ k_mram_hi_shift
High-byte shift.
@ k_mram_payload_max
Max config-set bytes.
@ k_mram_block_order
Report order slot.
@ k_mram_reg_words
Shadow words.
static RA8_INTERNAL void internal_mram_report(void)
End-of-run MRAM section: MACI program-command count (only if used).
static const board_periph_block_t s_k_mram_reg_block
MRMS controller-register block descriptor (self-registered).
mrpgm_status_t
MRCPS ready snapshot: address buffer empty, not busy, not full, no errors.
@ k_mrcps_ready
ABUFEMP set; PRGBSYC / ABUFFULL / error bits clear.
maci_map_t
MACI command-issuing area window (ra8_flash_regs.h).
@ k_maci_base
MACI command-issuing area base.
@ k_maci_span
One command port (byte+halfword).
static RA8_INTERNAL uint64_t internal_mram_reg_read(uc_engine *uc, uint64_t addr, unsigned size)
MMIO read inside the MRMS controller window.
mram_status_t
Register bit values the driver polls / writes.
@ k_mram_mstatr_mrdy
MSTATR.MRDY (command complete).
@ k_mram_mstatr_ilgcom
MSTATR.ILGCOMERR (illegal cmd).
@ k_mram_mstatr_ilglerr
MSTATR.ILGLERR (illegal).
@ k_mram_mentryr_pe_bit
MENTRYR.MENTRY status bit.
mram_mastat_t
MASTAT bits latched when the sequencer rejects a command.
@ k_mram_mastat_cmdlk
Command-locked state latched.
@ k_mram_off_mastat
MASTAT : extra-MRAM access status.
@ k_mram_mastat_mreae
Extra MRAM access error.
static const board_periph_block_t s_k_maci_block
MACI command-area block descriptor (self-registered).
static RA8_INTERNAL uint64_t internal_mrpgm_read(uc_engine *uc, uint64_t addr, unsigned size)
MMIO read inside the code-MRAM program-control window (MRCPS ready).
maci_cmd_t
MACI command opcodes the extra-MRAM program / config-set stream uses.
@ k_maci_cmd_word_n
N halfword count written after the opener.
@ k_maci_cmd_config_set
Config-Set opener: OFS area (HUM 59.7.4.8).
@ k_maci_cmd_final
Trailer byte that starts command processing.
@ k_maci_cmd_program
Program opener: extra-MRAM data (HUM 59.7.4.5).
static RA8_INTERNAL uint64_t internal_maci_read(uc_engine *uc, uint64_t addr, unsigned size)
MMIO read inside the MACI command area (driver never reads it).
static RA8_INTERNAL void internal_maci_commit(uc_engine *uc)
Commit the collected command payload to the mapped MRAM region.
static RA8_INTERNAL void internal_mram_reg_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value)
MMIO write inside the MRMS controller window (latch MSADDR / P-E mode).
static RA8_INTERNAL void internal_mram_reset(void)
Reset the MRAM model: clear the shadow + collection state.
static RA8_INTERNAL void internal_mrpgm_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value)
MMIO write inside the code-MRAM program-control window (shadow the gate).
mrpgm_map_t
Code-MRAM program-control sub-window (R_MRMS 0x3000 page).
@ k_mrpgm_off_mrcps
MRCPS : Code MRAM Program Status.
@ k_mrpgm_base
0x4013C000 + 0x3000 code-MRAM P/E page.
@ k_mrpgm_words
Shadow word count.
@ k_mrpgm_span
Covers MRCPC0/1 / MRCPS / MRCFLR.
static RA8_INTERNAL void internal_maci_reject(void)
Latch the command-locked state the sequencer enters on rejection.
static RA8_INTERNAL void internal_maci_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value)
MMIO write inside the MACI command-issuing area (the command stream).
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.
uc_err emu_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t count)
Write guest memory through the central access seam.
-proof
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
A modelled peripheral block's self-description for the core registry.
MRAM model state: register shadow + MACI collection + counters.
uint32_t payload_len
Bytes collected this command.
uint32_t programs
Config-set program commands.
uint8_t maci_state
maci_state_t collection state.
uint8_t payload[k_mram_payload_max]
Collected config-set bytes.
uint8_t pe_active
1 => program/erase mode entered.
uint32_t msaddr
Latched MACI target address.
uint32_t regs[k_mram_reg_words]
0x4013E000 window shadow.
uint32_t rejected
Programs refused: MSADDR illegal.
uint32_t pgm_regs[k_mrpgm_words]
0x4013F000 code-MRAM P/E shadow.