ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
board_periph_rtc.c
Go to the documentation of this file.
1
44
45#include <stdint.h>
46#include <stdio.h>
47
48#include "board_periph_block.h"
50
52typedef enum : uint32_t {
53 k_bcd_base = 10U,
55 k_nibble_mask = 0x0FU,
56 k_year_mod = 100U,
57 k_year_base = 2000U,
58} rtc_lit_t;
59
71typedef enum : uint32_t {
74
76typedef enum : uint64_t {
77 k_rtc_base = 0x40202000UL,
78 k_rtc_span = 0x80UL,
80
103
105typedef enum : uint8_t {
111} rtc_bit_t;
112
122
124typedef enum : uint8_t {
126} rtc_r64_t;
127
138typedef enum : uint16_t {
142
144typedef struct {
145 uint8_t reg[k_rtc_span];
146 uint8_t sec;
147 uint8_t min;
148 uint8_t hour;
149 uint8_t day;
150 uint8_t mon;
151 uint16_t year;
152 uint8_t r64;
153 uint32_t tick_frac;
154 uint32_t alarms;
155 uint32_t periodics;
157
159
160/* =============================================================================
161 * BCD helpers + the binary <-> BCD calendar reflection.
162 * =============================================================================
163 */
164
176RA8_INTERNAL static uint8_t internal_rtc_bin_to_bcd(uint8_t bin)
177{
178 return (uint8_t)(((uint8_t)(bin / (uint8_t)k_bcd_base) << (uint8_t)k_bcd_shift) |
179 (uint8_t)(bin % (uint8_t)k_bcd_base));
180}
181
193RA8_INTERNAL static uint8_t internal_rtc_bcd_to_bin(uint8_t bcd)
194{
195 return (uint8_t)(((uint8_t)((bcd >> (uint8_t)k_bcd_shift) & (uint8_t)k_nibble_mask) *
196 (uint8_t)k_bcd_base) +
197 (uint8_t)(bcd & (uint8_t)k_nibble_mask));
198}
199
209{
210 s_rtc.reg[(uint64_t)k_rtc_off_r64cnt] = (uint8_t)(s_rtc.r64 & (uint8_t)k_rtc_r64_mask);
216 s_rtc.reg[(uint64_t)k_rtc_off_ryrcnt] =
217 internal_rtc_bin_to_bcd((uint8_t)(s_rtc.year % (uint32_t)k_year_mod));
218}
219
229{
235 s_rtc.year = (uint16_t)internal_rtc_bcd_to_bin(s_rtc.reg[(uint64_t)k_rtc_off_ryrcnt]);
236}
237
238/* =============================================================================
239 * MMIO read / write.
240 * =============================================================================
241 */
242
256RA8_INTERNAL static uint64_t internal_rtc_read(uc_engine* uc, uint64_t addr, unsigned size)
257{
258 (void)uc;
259 const uint64_t off = addr - (uint64_t)k_rtc_base;
260 uint64_t v = 0U;
261 for (unsigned i = 0U; i < size; i++) {
262 const uint64_t b = off + (uint64_t)i;
263 if (b < (uint64_t)k_rtc_span) {
264 v |= (uint64_t)s_rtc.reg[b] << (8U * i);
265 }
266 }
267 return v;
268}
269
282{
283 return (off == (uint64_t)k_rtc_off_rseccnt) || (off == (uint64_t)k_rtc_off_rmincnt) ||
284 (off == (uint64_t)k_rtc_off_rhrcnt) || (off == (uint64_t)k_rtc_off_rdaycnt) ||
285 (off == (uint64_t)k_rtc_off_rmoncnt) || (off == (uint64_t)k_rtc_off_ryrcnt);
286}
287
300RA8_INTERNAL static void
301internal_rtc_write(uc_engine* uc, uint64_t addr, unsigned size, uint64_t value)
302{
303 (void)uc;
304 const uint64_t off = addr - (uint64_t)k_rtc_base;
305 bool touched_cal = false;
306 for (unsigned i = 0U; i < size; i++) {
307 const uint64_t b = off + (uint64_t)i;
308 if (b >= (uint64_t)k_rtc_span) {
309 continue;
310 }
311 s_rtc.reg[b] = (uint8_t)(value >> (8U * i));
313 touched_cal = true;
314 }
315 }
316 /* A calendar-count write (ra8_rtc_set, performed with START cleared) reseeds
317 * the running time mirror so the clock continues from the new value. */
318 if (touched_cal) {
320 }
321}
322
323/* =============================================================================
324 * Per-tick time advance + alarm / periodic event raising.
325 * =============================================================================
326 */
327
337{
338 s_rtc.sec++;
339 if (s_rtc.sec < (uint8_t)k_rtc_secs_per_min) {
340 return;
341 }
342 s_rtc.sec = 0U;
343 s_rtc.min++;
344 if (s_rtc.min < (uint8_t)k_rtc_mins_per_hour) {
345 return;
346 }
347 s_rtc.min = 0U;
348 s_rtc.hour++;
349 if (s_rtc.hour < (uint8_t)k_rtc_hours_per_day) {
350 return;
351 }
352 s_rtc.hour = 0U;
353 s_rtc.day++;
354 if (s_rtc.day <= (uint8_t)k_rtc_days_per_mon) {
355 return;
356 }
357 s_rtc.day = 1U;
358 s_rtc.mon++;
359 if (s_rtc.mon <= (uint8_t)k_rtc_mons_per_year) {
360 return;
361 }
362 s_rtc.mon = 1U;
363 s_rtc.year++;
364}
365
377{
378 const uint8_t sar = s_rtc.reg[(uint64_t)k_rtc_off_rsecar];
379 const uint8_t mar = s_rtc.reg[(uint64_t)k_rtc_off_rminar];
380 const uint8_t har = s_rtc.reg[(uint64_t)k_rtc_off_rhrar];
381 /* Alarm is meaningful only if at least one field has its ENB bit set. */
382 if (((sar | mar | har) & (uint8_t)k_rtc_alarm_enb) == 0U) {
383 return false;
384 }
385 const bool sec_ok =
386 ((sar & (uint8_t)k_rtc_alarm_enb) == 0U) ||
387 (internal_rtc_bcd_to_bin((uint8_t)(sar & (uint8_t)k_rtc_alarm_val)) == s_rtc.sec);
388 const bool min_ok =
389 ((mar & (uint8_t)k_rtc_alarm_enb) == 0U) ||
390 (internal_rtc_bcd_to_bin((uint8_t)(mar & (uint8_t)k_rtc_alarm_val)) == s_rtc.min);
391 const bool hr_ok =
392 ((har & (uint8_t)k_rtc_alarm_enb) == 0U) ||
393 (internal_rtc_bcd_to_bin((uint8_t)(har & (uint8_t)k_rtc_alarm_val)) == s_rtc.hour);
394 return sec_ok && min_ok && hr_ok;
395}
396
406RA8_INTERNAL static void internal_rtc_raise_events(uc_engine* uc)
407{
408 const uint8_t rcr1 = s_rtc.reg[(uint64_t)k_rtc_off_rcr1];
410 s_rtc.alarms++;
411 if ((rcr1 & (uint8_t)k_rtc_rcr1_aie) != 0U) {
413 }
414 if (board_periph_trace()) {
415 (void)priv_emu_io_errf(" RTC : alarm match %02u:%02u:%02u\n",
416 s_rtc.hour,
417 s_rtc.min,
418 s_rtc.sec);
419 }
420 }
421 if ((rcr1 & (uint8_t)k_rtc_rcr1_pie) != 0U) {
422 s_rtc.periodics++;
424 }
425}
426
436RA8_INTERNAL static void internal_rtc_tick(uc_engine* uc)
437{
438 if ((s_rtc.reg[(uint64_t)k_rtc_off_rcr2] & (uint8_t)k_rtc_rcr2_start) == 0U) {
439 return; /* stopped: time holds */
440 }
441 s_rtc.r64 = (uint8_t)(s_rtc.r64 + 1U);
442 s_rtc.tick_frac++;
443 if (s_rtc.tick_frac < (uint32_t)k_rtc_ticks_per_sec) {
445 return;
446 }
447 s_rtc.tick_frac = 0U;
451}
452
453/* =============================================================================
454 * Reset / report.
455 * =============================================================================
456 */
457
467{
468 s_rtc = (rtc_state_t){};
469}
470
480{
481 if ((s_rtc.alarms == 0U) && (s_rtc.periodics == 0U)) {
482 return;
483 }
484 (void)priv_emu_io_errf(" RTC : %04u-%02u-%02u %02u:%02u:%02u alarms=%u periodics=%u\n",
485 (unsigned)((uint32_t)k_year_base + s_rtc.year),
486 s_rtc.mon,
487 s_rtc.day,
488 s_rtc.hour,
489 s_rtc.min,
490 s_rtc.sec,
491 s_rtc.alarms,
492 s_rtc.periodics);
493}
494
497 .base = (uint64_t)k_rtc_base,
498 .span = (uint64_t)k_rtc_span,
499 .order = (uint32_t)k_rtc_block_order,
500 .read = internal_rtc_read,
502 .tick = internal_rtc_tick,
503 .reset = internal_rtc_reset,
504 .report = internal_rtc_report,
505 .name = "RTC",
506};
507
509[[gnu::constructor]] RA8_INTERNAL static void internal_board_periph_rtc_register(void)
510{
512}
Decentralized peripheral-block registry for the board emulator core.
void board_periph_icu_raise_event(uc_engine *uc, uint16_t event)
Raise a peripheral ELC event through the core's ICU -> NVIC path.
void board_periph_register_block(const board_periph_block_t *block)
Register a peripheral block's descriptor with the core registry.
bool board_periph_trace(void)
Whether –trace is active (blocks log transitions when true).
static const board_periph_block_t s_k_rtc_block
RTC register window + the calendar tick / reset / report.
rtc_bit_t
RCR1 / RCR2 bit masks (ra8_rtc_regs.h, ra8_rtc.h).
@ k_rtc_rcr1_pie
RCR1.PIE periodic interrupt enable.
@ k_rtc_rcr1_aie
RCR1.AIE alarm interrupt enable.
@ k_rtc_rcr2_start
RCR2.START 0=stop, 1=run.
@ k_rtc_alarm_val
RxxAR lower BCD match value.
@ k_rtc_alarm_enb
RxxAR bit7 alarm-field enable.
static RA8_INTERNAL bool internal_rtc_is_calendar_off(uint64_t off)
True iff offset off is a calendar-count register (BCD value).
rtc_calendar_t
Calendar moduli + the modelled time:tick ratio.
@ k_rtc_mons_per_year
Rtc mons per year.
@ k_rtc_mins_per_hour
Rtc mins per hour.
@ k_rtc_secs_per_min
Rtc secs per minimum.
@ k_rtc_days_per_mon
Conservative roll-over (model only).
@ k_rtc_ticks_per_sec
Emulation chunks per modelled second.
@ k_rtc_hours_per_day
Rtc hours per day.
static RA8_INTERNAL void internal_rtc_advance_one_second(void)
Advance the binary time mirror by one modelled second.
static RA8_INTERNAL void internal_rtc_reset(void)
Clear the RTC register shadow and the time mirror.
static RA8_INTERNAL void internal_rtc_report(void)
Print the RTC's final time and its alarm / periodic event totals.
rtc_r64_t
64 Hz counter range (R64CNT is 6 bits).
@ k_rtc_r64_mask
R64CNT counts 0..63.
rtc_off_t
RTC register byte offsets (subset the driver touches).
@ k_rtc_off_ryrcnt
Year counter (BCD, 16-bit).
@ k_rtc_off_rseccnt
Second counter (BCD).
@ k_rtc_off_ryraren
Year alarm enable.
@ k_rtc_off_rwkcnt
Day-of-week counter.
@ k_rtc_off_ryrar
Year alarm.
@ k_rtc_off_rmincnt
Minute counter (BCD).
@ k_rtc_off_rminar
Minute alarm (BCD + ENB).
@ k_rtc_off_rcr4
Control 4 (count source / mode).
@ k_rtc_off_rhrcnt
Hour counter (BCD).
@ k_rtc_off_rmoncnt
Month counter (BCD).
@ k_rtc_off_rsecar
Second alarm (BCD + ENB).
@ k_rtc_off_rwkar
Day-of-week alarm.
@ k_rtc_off_r64cnt
64 Hz counter (read-only).
@ k_rtc_off_rhrar
Hour alarm (BCD + ENB).
@ k_rtc_off_rdayar
Day alarm.
@ k_rtc_off_rcr1
Control 1 (AIE/CIE/PIE, PES).
@ k_rtc_off_rmonar
Month alarm.
@ k_rtc_off_rcr2
Control 2 (START/RESET/HR24/...).
@ k_rtc_off_rdaycnt
Day counter (BCD).
rtc_lit_t
BCD packing + calendar constants for the RTC model.
@ k_bcd_shift
Tens nibble shift.
@ k_year_base
Calendar epoch base year.
@ k_bcd_base
Decimal radix for BCD packing.
@ k_year_mod
Two-digit year wrap.
static RA8_INTERNAL void internal_rtc_raise_events(uc_engine *uc)
Raise alarm / periodic ELC events for one elapsed modelled second.
static RA8_INTERNAL void internal_rtc_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value)
Write size bytes little-endian into the RTC shadow at off.
static RA8_INTERNAL void internal_board_periph_rtc_register(void)
Self-register the RTC window before main runs (decentralized).
rtc_event_t
RTC alarm / periodic ELC events the model emits (FSP ra8d2 bsp_elc).
@ k_rtc_event_alarm
RTC_ALM alarm-match event.
@ k_rtc_event_periodic
RTC_PRD periodic event.
static RA8_INTERNAL uint8_t internal_rtc_bin_to_bcd(uint8_t bin)
Binary 0..99 -> packed BCD.
static RA8_INTERNAL void internal_rtc_latch_calendar(void)
Load the binary time mirror from a freshly written BCD calendar.
static RA8_INTERNAL uint8_t internal_rtc_bcd_to_bin(uint8_t bcd)
Packed BCD -> binary 0..99.
static RA8_INTERNAL void internal_rtc_tick(uc_engine *uc)
Advance the RTC each chunk while running; raise its events.
static RA8_INTERNAL void internal_rtc_publish_calendar(void)
Refresh the BCD calendar shadow registers from the binary mirror.
static rtc_state_t s_rtc
static RA8_INTERNAL bool internal_rtc_alarm_matches(void)
True iff the running time matches the armed (ENB) alarm fields.
rtc_geom_t
RTC register window geometry (ra8_rtc_regs.h).
@ k_rtc_base
RTC block base.
@ k_rtc_span
FSP R_RTC_Type size.
static RA8_INTERNAL uint64_t internal_rtc_read(uc_engine *uc, uint64_t addr, unsigned size)
Read size bytes little-endian from the RTC shadow at off.
rtc_order_t
Per-tick order slot for the RTC block.
@ k_rtc_block_order
RTC tick / reset / report order slot.
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).
@ k_nibble_mask
Nibble mask.
A modelled peripheral block's self-description for the core registry.
The modelled RTC: a control-register shadow + a binary time mirror.
uint32_t tick_frac
Ticks accumulated toward the next second.
uint16_t year
Binary year mirror (2000-based BCD low).
uint8_t reg[k_rtc_span]
Faithful register shadow (BCD on reads).
uint8_t day
Binary day mirror.
uint8_t hour
Binary hour mirror.
uint8_t min
Binary minute mirror.
uint32_t periodics
Periodic events raised (report).
uint32_t alarms
Alarm events raised (report).
uint8_t sec
Binary second mirror.
uint8_t mon
Binary month mirror.
uint8_t r64
64 Hz sub-second counter.