ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
board_periph_glcdc.c
Go to the documentation of this file.
1
43
44#include <stdint.h>
45#include <stdio.h>
46
47#include "board_periph.h"
48#include "board_periph_block.h"
50
52typedef enum : uint64_t {
53 k_glcdc_base = 0x40342000ULL,
54 k_glcdc_span = 0x1500ULL,
56
65typedef enum : uint64_t {
66 k_glcdc_off_bg_en = 0x1000ULL,
67
72 k_glcdc_off_gr1_fmt = 0x111CULL,
73
78 k_glcdc_off_gr2_fmt = 0x121CULL,
80
92
104
106typedef enum : uint8_t {
111
113typedef enum : uint32_t {
114 k_glcdc_dtcm_base = 0x20000000U,
115 k_glcdc_dtcm_end = 0x20010000U,
116 k_glcdc_sram_base = 0x22000000U,
117 k_glcdc_sram_end = 0x22200000U,
118 k_glcdc_sdram_base = 0x68000000U,
119 k_glcdc_sdram_end = 0x6C000000U,
121
123typedef enum : uint32_t {
124 k_glcdc_fnv_offset = 2166136261U,
125 k_glcdc_fnv_prime = 16777619U,
127
129typedef enum : uint32_t {
134
136typedef struct {
137 uint32_t saddr;
138 uint32_t flm3;
139 uint32_t flm5;
140 uint32_t fmt;
141 bool flmrd;
143
145typedef struct {
148 bool bg_on;
149 uc_engine* uc;
151
153
165RA8_INTERNAL static uint32_t internal_glcdc_bpp_for_format(uint8_t fmt)
166{
167 switch (fmt) {
168 case (uint8_t)k_glcdc_fmt_argb8888:
169 case (uint8_t)k_glcdc_fmt_rgb888:
170 return (uint32_t)k_glcdc_bpp_32;
171 case (uint8_t)k_glcdc_fmt_rgb565:
172 case (uint8_t)k_glcdc_fmt_argb1555:
173 case (uint8_t)k_glcdc_fmt_argb4444:
174 return (uint32_t)k_glcdc_bpp_16;
175 default:
176 return (uint32_t)k_glcdc_bpp_8; /* CLUT8 / CLUT4 / CLUT1. */
177 }
178}
179
191RA8_INTERNAL static bool internal_glcdc_addr_is_ram(uint32_t addr)
192{
193 const bool in_dtcm = (addr >= (uint32_t)k_glcdc_dtcm_base) && (addr < (uint32_t)k_glcdc_dtcm_end);
194 const bool in_sram = (addr >= (uint32_t)k_glcdc_sram_base) && (addr < (uint32_t)k_glcdc_sram_end);
195 const bool in_sdram =
196 (addr >= (uint32_t)k_glcdc_sdram_base) && (addr < (uint32_t)k_glcdc_sdram_end);
197 return in_dtcm || in_sram || in_sdram;
198}
199
224RA8_INTERNAL static bool
226{
227 if (!layer->flmrd || !internal_glcdc_addr_is_ram(layer->saddr)) {
228 return false;
229 }
230 const uint32_t stride =
231 (layer->flm3 >> (uint32_t)k_glcdc_stride_shift) & (uint32_t)k_glcdc_stride_mask;
232 const uint32_t lnnum =
233 (layer->flm5 >> (uint32_t)k_glcdc_lnnum_shift) & (uint32_t)k_glcdc_lnnum_mask;
234 const uint8_t fmt =
235 (uint8_t)((layer->fmt >> (uint32_t)k_glcdc_fmt_shift) & (uint32_t)k_glcdc_fmt_mask);
236 const uint32_t bpp = internal_glcdc_bpp_for_format(fmt);
237 const uint32_t height = lnnum + 1U;
238 const uint32_t width = stride / bpp;
239 if ((stride == 0U) || (width == 0U) || (width > (uint32_t)k_glcdc_max_dim) ||
240 (height > (uint32_t)k_glcdc_max_dim)) {
241 return false;
242 }
243 out->base = layer->saddr;
244 out->width = width;
245 out->height = height;
246 out->stride = stride;
247 out->format = fmt;
248 out->layer = num;
249 out->enabled = s_glcdc.bg_on;
250 return true;
251}
252
254{
255 if (out == nullptr) {
256 return false;
257 }
258 /* GR1 is the upper layer the e-reader and glcdc_render draw into; prefer it,
259 * then fall back to GR2 when only the lower layer is fetching. */
260 if (internal_glcdc_layer_decode(&s_glcdc.gr1, 1U, out)) {
261 return true;
262 }
263 return internal_glcdc_layer_decode(&s_glcdc.gr2, 2U, out);
264}
265
276RA8_INTERNAL static void internal_glcdc_snoop(uint64_t off, uint32_t value)
277{
278 switch (off) {
279 /* HUM Ch 63 "BG_EN" p 3759 */ /* background-plane operation enable. */
280 case (uint64_t)k_glcdc_off_bg_en:
281 s_glcdc.bg_on = ((value & (uint32_t)k_glcdc_bg_en_bit) != 0U);
282 break;
283
284 /* HUM Ch 63 "GR1_FLM2.BASE" p 3744 */ /* layer-1 framebuffer base address. */
285 case (uint64_t)k_glcdc_off_gr1_saddr:
286 s_glcdc.gr1.saddr = value;
287 break;
288 /* HUM Ch 63 "GR1_FLM3.LNOFF" p 3744 */ /* layer-1 line stride (bytes). */
289 case (uint64_t)k_glcdc_off_gr1_flm3:
290 s_glcdc.gr1.flm3 = value;
291 break;
292 /* HUM Ch 63 "GR1_FLM5.LNNUM" p 3744 */ /* layer-1 line count minus one. */
293 case (uint64_t)k_glcdc_off_gr1_line:
294 s_glcdc.gr1.flm5 = value;
295 break;
296 /* HUM Ch 63 "GR1_FLM6.FORMAT" p 3744 */ /* layer-1 pixel format code. */
297 case (uint64_t)k_glcdc_off_gr1_fmt:
298 s_glcdc.gr1.fmt = value;
299 break;
300 /* HUM Ch 63 "GR1_FLMRD.RENB" p 3744 */ /* layer-1 framebuffer read enable. */
301 case (uint64_t)k_glcdc_off_gr1_flmrd:
302 s_glcdc.gr1.flmrd = ((value & (uint32_t)k_glcdc_flmrd_renb_bit) != 0U);
303 break;
304
305 /* HUM Ch 63 "GR2_FLM2.BASE" p 3744 */ /* layer-2 framebuffer base address. */
306 case (uint64_t)k_glcdc_off_gr2_saddr:
307 s_glcdc.gr2.saddr = value;
308 break;
309 /* HUM Ch 63 "GR2_FLM3.LNOFF" p 3744 */ /* layer-2 line stride (bytes). */
310 case (uint64_t)k_glcdc_off_gr2_flm3:
311 s_glcdc.gr2.flm3 = value;
312 break;
313 /* HUM Ch 63 "GR2_FLM5.LNNUM" p 3744 */ /* layer-2 line count minus one. */
314 case (uint64_t)k_glcdc_off_gr2_line:
315 s_glcdc.gr2.flm5 = value;
316 break;
317 /* HUM Ch 63 "GR2_FLM6.FORMAT" p 3744 */ /* layer-2 pixel format code. */
318 case (uint64_t)k_glcdc_off_gr2_fmt:
319 s_glcdc.gr2.fmt = value;
320 break;
321 /* HUM Ch 63 "GR2_FLMRD.RENB" p 3744 */ /* layer-2 framebuffer read enable. */
322 case (uint64_t)k_glcdc_off_gr2_flmrd:
323 s_glcdc.gr2.flmrd = ((value & (uint32_t)k_glcdc_flmrd_renb_bit) != 0U);
324 break;
325
326 default:
327 break; /* Other GLCDC registers: shadowed by the caller's sparse model. */
328 }
329}
330
343RA8_INTERNAL static void
344internal_glcdc_write(uc_engine* uc, uint64_t addr, unsigned size, uint64_t value)
345{
346 (void)size;
347 s_glcdc.uc = uc; /* stash for the report's framebuffer read */
348 internal_glcdc_snoop(addr - (uint64_t)k_glcdc_base, (uint32_t)value);
349}
350
364RA8_INTERNAL static uint64_t internal_glcdc_read(uc_engine* uc, uint64_t addr, unsigned size)
365{
366 (void)uc;
367 (void)addr;
368 (void)size;
369 return 0U;
370}
371
381RA8_INTERNAL static void internal_glcdc_tick(uc_engine* uc)
382{
383 s_glcdc.uc = uc;
384}
385
395{
397}
398
412 uint32_t* out_crc)
413{
414 if (s_glcdc.uc == nullptr) {
415 return false;
416 }
417 const uint32_t bpp = internal_glcdc_bpp_for_format(fb->format);
418 const uint64_t line_bytes = (uint64_t)fb->width * (uint64_t)bpp;
419 const uint64_t total = line_bytes * (uint64_t)fb->height;
420 if ((total == 0U) || (total > (uint64_t)k_glcdc_max_fb_bytes)) {
421 return false;
422 }
423 uint32_t hsh = (uint32_t)k_glcdc_fnv_offset;
424 uint8_t buf[k_glcdc_read_chunk];
425 /* Hash the visible pixels row by row (skipping any inter-line stride padding)
426 * so the witness matches a contiguous width*bpp*height framebuffer hash. */
427 for (uint32_t row = 0U; row < fb->height; ++row) {
428 const uint64_t row_base = (uint64_t)fb->base + ((uint64_t)row * (uint64_t)fb->stride);
429 uint64_t done = 0U;
430 while (done < line_bytes) {
431 uint64_t want = line_bytes - done;
432 if (want > (uint64_t)k_glcdc_read_chunk) {
433 want = (uint64_t)k_glcdc_read_chunk;
434 }
435 if (emu_mem_read(s_glcdc.uc, row_base + done, buf, (size_t)want) != UC_ERR_OK) {
436 return false;
437 }
438 for (uint64_t i = 0U; i < want; ++i) {
439 hsh = (hsh ^ (uint32_t)buf[i]) * (uint32_t)k_glcdc_fnv_prime;
440 }
441 done += want;
442 }
443 }
444 *out_crc = hsh;
445 return true;
446}
447
449RA8_INTERNAL static const char* internal_glcdc_format_name(uint8_t fmt)
450{
451 switch (fmt) {
452 case (uint8_t)k_glcdc_fmt_argb8888:
453 return "argb8888";
454 case (uint8_t)k_glcdc_fmt_rgb888:
455 return "rgb888";
456 case (uint8_t)k_glcdc_fmt_rgb565:
457 return "rgb565";
458 case (uint8_t)k_glcdc_fmt_argb1555:
459 return "argb1555";
460 case (uint8_t)k_glcdc_fmt_argb4444:
461 return "argb4444";
462 default:
463 return "clut";
464 }
465}
466
476{
477 board_glcdc_fb_t fb = {};
479 return; /* No graphics layer programmed: stay quiet. */
480 }
481 uint32_t crc = 0U;
482 const bool hashed = internal_glcdc_hash_framebuffer(&fb, &crc);
483 const char* enab = fb.enabled ? "scanning" : "idle";
484 if (hashed) {
485 (void)priv_emu_io_errf(" GLCDC : layer%u fb=0x%08X %ux%u %s stride=%u crc=%08X (%s)\n",
486 (unsigned)fb.layer,
487 fb.base,
488 fb.width,
489 fb.height,
491 fb.stride,
492 crc,
493 enab);
494 } else {
495 (void)priv_emu_io_errf(" GLCDC : layer%u fb=0x%08X %ux%u %s stride=%u (%s)\n",
496 (unsigned)fb.layer,
497 fb.base,
498 fb.width,
499 fb.height,
501 fb.stride,
502 enab);
503 }
504}
505
507typedef enum : uint32_t {
510
513 .base = (uint64_t)k_glcdc_base,
514 .span = (uint64_t)k_glcdc_span,
515 .order = (uint32_t)k_glcdc_block_order,
516 .read = internal_glcdc_read,
518 .tick = internal_glcdc_tick,
519 .reset = internal_glcdc_reset,
520 .report = internal_glcdc_report,
521 .name = "GLCDC",
522 .observe = true,
523};
524
526[[gnu::constructor]] RA8_INTERNAL static void internal_glcdc_block_register(void)
527{
529}
Register-accurate peripheral-model framework for the board emulator.
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.
static RA8_INTERNAL bool internal_glcdc_addr_is_ram(uint32_t addr)
True iff addr is inside an emulated RAM window a framebuffer uses.
static const board_periph_block_t s_k_glcdc_block
GLCDC block descriptor: observe-only snoop over the register window.
static RA8_INTERNAL void internal_glcdc_tick(uc_engine *uc)
Stash the engine each chunk so the report can read framebuffer RAM.
static glcdc_state_t s_glcdc
glcdc_fnv_t
FNV-1a-32 constants (match glcdc_render's framebuffer hash).
@ k_glcdc_fnv_prime
FNV-1a-32 prime.
@ k_glcdc_fnv_offset
FNV-1a-32 offset basis.
glcdc_fmt_t
FLM6.FORMAT codes (ra8_glcdc_pixel_fmt_t; HUM Ch 63 Table 63.11).
@ k_glcdc_fmt_clut1
1-bit CLUT.
@ k_glcdc_fmt_argb1555
16-bit ARGB1555.
@ k_glcdc_fmt_argb8888
32-bit ARGB.
@ k_glcdc_fmt_rgb565
16-bit RGB565.
@ k_glcdc_fmt_clut4
4-bit CLUT.
@ k_glcdc_fmt_argb4444
16-bit ARGB4444.
@ k_glcdc_fmt_rgb888
24-bit RGB.
@ k_glcdc_fmt_clut8
8-bit CLUT.
glcdc_bound_t
Bounds for the report-time framebuffer read (NASA Rule 2).
@ k_glcdc_read_chunk
uc_mem_read batch size, bytes.
@ k_glcdc_max_fb_bytes
8 MiB cap on a hashed framebuffer.
@ k_glcdc_max_dim
Sanity cap on decoded width/height.
static RA8_INTERNAL void internal_glcdc_snoop(uint64_t off, uint32_t value)
Snoop one register write into the matching layer / BG shadow field.
glcdc_order_t
Per-tick / report order slot for the GLCDC block (after DRW).
@ k_glcdc_block_order
After DRW (160), before SRAM-ECC (176).
static RA8_INTERNAL void internal_glcdc_report(void)
End-of-run GLCDC section: the active framebuffer + its content hash.
bool board_periph_glcdc_get_framebuffer(board_glcdc_fb_t *out)
Report the active GLCDC graphics-layer framebuffer, if one is programmed.
static RA8_INTERNAL const char * internal_glcdc_format_name(uint8_t fmt)
Human label for an FLM6.FORMAT code.
static RA8_INTERNAL uint64_t internal_glcdc_read(uc_engine *uc, uint64_t addr, unsigned size)
Read stub: an observe block never owns reads (the sparse model does).
static RA8_INTERNAL uint32_t internal_glcdc_bpp_for_format(uint8_t fmt)
Bytes per pixel for an FLM6.FORMAT code (HUM Ch 63 Table 63.11).
static RA8_INTERNAL bool internal_glcdc_layer_decode(const glcdc_layer_t *layer, uint8_t num, board_glcdc_fb_t *out)
Decode a layer's snooped registers into a framebuffer descriptor.
static RA8_INTERNAL void internal_glcdc_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value)
MMIO write snoop inside the GLCDC window (observe-only, never owns).
glcdc_field_t
GLCDC register field shifts / masks the decode applies (HUM Ch 63).
@ k_glcdc_fmt_mask
FORMAT field width (3 bits).
@ k_glcdc_fmt_shift
FLM6.FORMAT[30:28].
@ k_glcdc_bg_en_bit
BG_EN.EN: background operation on.
@ k_glcdc_stride_mask
FLM3.LNOFF is 16 bits.
@ k_glcdc_stride_shift
FLM3.LNOFF lives in bits [31:16].
@ k_glcdc_lnnum_shift
FLM5.LNNUM lives in bits [26:16].
@ k_glcdc_flmrd_renb_bit
FLMRD.RENB: framebuffer read enable.
@ k_glcdc_lnnum_mask
FLM5.LNNUM is 11 bits.
static RA8_INTERNAL void internal_glcdc_reset(void)
Clear the GLCDC model on reset / process start.
glcdc_ram_window_t
Emulated RAM windows a GLCDC framebuffer may legally live in.
@ k_glcdc_dtcm_base
Data TCM start.
@ k_glcdc_sdram_end
External SDRAM end.
@ k_glcdc_sram_base
On-chip SRAM start.
@ k_glcdc_sram_end
On-chip SRAM end.
@ k_glcdc_sdram_base
External SDRAM start.
@ k_glcdc_dtcm_end
Data TCM end.
static RA8_INTERNAL bool internal_glcdc_hash_framebuffer(const board_glcdc_fb_t *fb, uint32_t *out_crc)
FNV-1a-32 over the active framebuffer, read out of emulated RAM.
glcdc_bpp_t
Bytes-per-pixel per FLM6.FORMAT code (CLUT modes round up to 1).
@ k_glcdc_bpp_16
RGB565 / ARGB1555 / ARGB4444.
@ k_glcdc_bpp_32
ARGB8888 / RGB888 fetch width.
@ k_glcdc_bpp_8
CLUT8 / CLUT4 / CLUT1 (rounded).
glcdc_off_t
GLCDC register byte offsets this model snoops (ra8_glcdc_regs.h).
@ k_glcdc_off_gr1_line
GR[0].FLM5: LNNUM (lines - 1).
@ k_glcdc_off_gr2_flmrd
GR[1].FLMRD.RENB.
@ k_glcdc_off_gr1_saddr
GR[0].FLM2.BASE: framebuffer addr.
@ k_glcdc_off_gr1_flmrd
GR[0].FLMRD.RENB: framebuffer read.
@ k_glcdc_off_gr2_fmt
GR[1].FLM6.FORMAT.
@ k_glcdc_off_gr1_fmt
GR[0].FLM6.FORMAT: pixel format.
@ k_glcdc_off_bg_en
BG.EN.EN: output stage enable.
@ k_glcdc_off_gr2_flm3
GR[1].FLM3.LNOFF.
@ k_glcdc_off_gr2_saddr
GR[1].FLM2.BASE.
@ k_glcdc_off_gr1_flm3
GR[0].FLM3.LNOFF: line stride bytes.
@ k_glcdc_off_gr2_line
GR[1].FLM5.
glcdc_geom_t
GLCDC register-window geometry (ra8_glcdc_regs.h).
@ k_glcdc_base
GLCDC block base (HUM Ch 63).
@ k_glcdc_span
Covers CLUTs..SYSCNT_PANEL_CLK 0x1450.
static RA8_INTERNAL void internal_glcdc_block_register(void)
Register the GLCDC block before main (host constructor).
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_read(uc_engine *uc, uint64_t address, void *bytes, size_t count)
Read guest memory through the central access seam.
-proof
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Active GLCDC graphics-layer framebuffer descriptor.
uint32_t width
Width in pixels (line stride / bytes-per-pixel).
uint32_t stride
Line stride in bytes (GRn FLM3.LNOFF[31:16]).
uint32_t base
Framebuffer base address (GRn FLM2.BASE).
uint8_t format
Pixel format code (GRn FLM6.FORMAT[30:28]).
uint32_t height
Height in pixels (GRn FLM5.LNNUM + 1).
bool enabled
True when the layer is fetching (FLMRD set + BG EN).
uint8_t layer
Source layer: 1 = GR1 (upper), 2 = GR2 (lower).
A modelled peripheral block's self-description for the core registry.
One graphics layer's snooped descriptor registers.
uint32_t flm3
FLM3.LNOFF (stride in bits [31:16]).
uint32_t flm5
FLM5 (LNNUM lines-1 in bits [26:16]).
uint32_t fmt
FLM6.FORMAT (code in bits [30:28]).
bool flmrd
FLMRD.RENB: layer is fetching pixels.
uint32_t saddr
FLM2.BASE framebuffer base address.
The modelled GLCDC: snooped graphics-layer + background state.
uc_engine * uc
Engine handle stashed for the report.
glcdc_layer_t gr2
Graphics layer 2 (lower).
glcdc_layer_t gr1
Graphics layer 1 (upper).
bool bg_on
BG_EN.EN: output stage enabled.