ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
emu_view_surface.c
Go to the documentation of this file.
1
12
13#include <stddef.h>
14#include <stdint.h>
15
17#include "emu_memmap.h"
18#include "emu_mmio.h"
19#include "emu_view.h"
22
24typedef enum : uint64_t {
25 k_surface_gr1_saddr = 0x4034310CUL,
26 k_surface_gr1_flm3 = 0x40343110UL,
27 k_surface_gr1_flm5 = 0x40343118UL,
28 k_surface_gr1_fmt = 0x4034311CUL,
30
53
55typedef struct {
56 uint32_t address;
57 uint32_t stride;
58 uint16_t width;
59 uint16_t height;
60 bool active;
62
74RA8_INTERNAL static uint16_t internal_rgb888_to_565(uint32_t rgb)
75{
76 const uint32_t red = (rgb >> k_surface_rgb_r_shift) & k_surface_byte_mask;
77 const uint32_t green = (rgb >> k_surface_rgb_g_shift) & k_surface_byte_mask;
78 const uint32_t blue = rgb & k_surface_byte_mask;
79 return (uint16_t)(((red & k_surface_r_keep) << k_surface_r_pos) |
80 ((green & k_surface_g_keep) << k_surface_g_pos) | (blue >> k_surface_b_drop));
81}
82
94RA8_INTERNAL static bool internal_address_is_ram(uint32_t address)
95{
96 return (((address >= (uint32_t)k_dtcm_base) && (address < (uint32_t)k_dtcm_end)) ||
97 ((address >= (uint32_t)k_sram_base) && (address < (uint32_t)k_sram_end)) ||
98 ((address >= (uint32_t)k_sdram_base) && (address < (uint32_t)k_sdram_end)));
99}
100
113RA8_INTERNAL static surface_layer_t internal_layer(uint16_t panel_width, uint16_t panel_height)
114{
115 const uint32_t address = mmio_peek((uint64_t)k_surface_gr1_saddr);
116 const uint32_t format =
118 const uint32_t stride =
120 const uint32_t lines =
122 const bool active = internal_address_is_ram(address) && (format == k_surface_fmt_rgb565) &&
123 (stride >= sizeof(uint16_t));
124 const uint32_t source_width = stride / sizeof(uint16_t);
125 return (surface_layer_t){
126 .address = address,
127 .stride = stride,
128 .width = (uint16_t)((source_width < panel_width) ? source_width : panel_width),
129 .height = (uint16_t)((lines < panel_height) ? lines : panel_height),
130 .active = active,
131 };
132}
133
135typedef struct {
136 uint16_t x;
137 uint16_t y;
138 uint16_t width;
139 uint16_t height;
141
156RA8_INTERNAL static bool internal_read_tile(uc_engine* uc,
157 const surface_layer_t* layer,
158 const surface_tile_t* tile,
159 uint16_t* source)
160{
161 for (uint16_t row = 0U; row < tile->height; row++) {
162 if (emu_mem_read(uc,
163 (uint64_t)layer->address + ((uint64_t)(tile->y + row) * layer->stride) +
164 ((uint64_t)tile->x * sizeof(uint16_t)),
165 &source[(size_t)row * tile->width],
166 (size_t)tile->width * sizeof(uint16_t)) != UC_ERR_OK) {
167 return false;
168 }
169 }
170 return true;
171}
172
186RA8_INTERNAL static bool internal_write_layer(uc_engine* uc,
187 emu_presentation_workspace_t* presentation,
188 const surface_layer_t* layer)
189{
190 if (!layer->active) {
191 return true;
192 }
193 /* The borrowed scratch holds a run of RGB565 pixels, and
194 * emu_presentation_open() rejects any scratch not aligned to alignof(uint16_t). */
195 uint16_t* const source = presentation->scratch;
196 for (uint16_t y0 = 0U; y0 < layer->height;) {
197 const uint16_t height = ((uint32_t)layer->height - y0 < k_emu_presentation_tile_px)
198 ? (uint16_t)(layer->height - y0)
199 : (uint16_t)k_emu_presentation_tile_px;
200 for (uint16_t x0 = 0U; x0 < layer->width;) {
201 const uint16_t width = ((uint32_t)layer->width - x0 < k_emu_presentation_tile_px)
202 ? (uint16_t)(layer->width - x0)
203 : (uint16_t)k_emu_presentation_tile_px;
204 const surface_tile_t tile = {.x = x0, .y = y0, .width = width, .height = height};
205 if (!internal_read_tile(uc, layer, &tile, source)) {
206 return false;
207 }
208 if (!priv_emu_view_tile_write(presentation, source, x0, y0, width, height)) {
209 return false;
210 }
211 x0 = (uint16_t)(x0 + width);
212 }
213 y0 = (uint16_t)(y0 + height);
214 }
215 return true;
216}
217
219 emu_presentation_workspace_t* presentation,
220 const board_status_t* status)
221{
222 if ((uc == nullptr) || (presentation == nullptr) || (presentation->fd < 0)) {
223 return false;
224 }
225 const uint16_t background =
227 if (!emu_presentation_fill(presentation,
228 0U,
229 0U,
230 presentation->composite_width,
231 presentation->composite_height,
232 0U) ||
233 !emu_presentation_fill(presentation,
234 0U,
235 0U,
236 presentation->display_width,
237 presentation->display_height,
238 background)) {
239 return false;
240 }
241 const surface_layer_t layer =
242 internal_layer(presentation->panel_width, presentation->panel_height);
243 if (!internal_write_layer(uc, presentation, &layer)) {
244 return false;
245 }
246 board_overlay_surface_t overlay = {.context = presentation,
247 .fill = emu_presentation_fill,
248 .width = presentation->composite_width,
249 .height = presentation->composite_height,
250 .ok = true};
251 return board_overlay_draw_sidebar(&overlay, presentation->display_width, status);
252}
253
267 const emu_presentation_workspace_t* presentation)
268{
269 enum : size_t {
270 k_pixels_per_chunk = 128U,
271 };
272 uint16_t pixels[k_pixels_per_chunk];
273 uint8_t rgb[k_pixels_per_chunk * 3U];
274 const size_t total_pixels = presentation->surface_bytes / sizeof(uint16_t);
275 for (size_t base = 0U; base < total_pixels; base += k_pixels_per_chunk) {
276 const size_t count =
277 ((total_pixels - base) < k_pixels_per_chunk) ? (total_pixels - base) : k_pixels_per_chunk;
278 if (!emu_presentation_read(presentation,
279 base * sizeof(uint16_t),
280 pixels,
281 count * sizeof(uint16_t))) {
282 return false;
283 }
284 for (size_t index = 0U; index < count; index++) {
285 const uint16_t pixel = pixels[index];
286 const uint32_t red = (pixel >> k_surface_r565_shift) & k_surface_5bit;
287 const uint32_t green = (pixel >> k_surface_g565_shift) & k_surface_6bit;
288 const uint32_t blue = pixel & k_surface_5bit;
289 rgb[(index * 3U) + 0U] = (uint8_t)((red << 3U) | (red >> 2U));
290 rgb[(index * 3U) + 1U] = (uint8_t)((green << 2U) | (green >> 4U));
291 rgb[(index * 3U) + 2U] = (uint8_t)((blue << 3U) | (blue >> 2U));
292 }
293 if (priv_emu_io_write_exact(fd, rgb, count * 3U).status != k_emu_io_ok) {
294 return false;
295 }
296 }
297 return true;
298}
299
300int write_ppm(const char* path, const emu_presentation_workspace_t* presentation)
301{
302 if ((path == nullptr) || (presentation == nullptr) || (presentation->fd < 0)) {
303 return -1;
304 }
305 emu_io_txn_t transaction = {.fd = -1};
306 if (priv_emu_io_txn_begin(path, &transaction).status != k_emu_io_ok) {
307 return -1;
308 }
309 const bool ok = (priv_emu_io_filef(transaction.fd,
310 "P6\n%u %u\n255\n",
311 (unsigned int)presentation->composite_width,
312 (unsigned int)presentation->composite_height)
313 .status == k_emu_io_ok) &&
314 internal_write_ppm_pixels(transaction.fd, presentation);
315 if (!ok || (priv_emu_io_txn_commit(&transaction).status != k_emu_io_ok)) {
316 priv_emu_io_txn_abort(&transaction);
317 return -1;
318 }
319 return 0;
320}
bool board_overlay_draw_sidebar(board_overlay_surface_t *surface, uint16_t panel_w, const board_status_t *st)
Draw the status sidebar through a bounded rectangle sink.
Bounded raw-descriptor I/O seam for the RA8 emulator.
@ k_emu_io_ok
The complete operation succeeded.
emu_io_result_t priv_emu_io_write_exact(int fd, const void *buf, size_t count)
Write exactly count sequential bytes or report fault progress.
emu_io_result_t priv_emu_io_filef(int fd, const char *format,...)
Format bounded text and write it to an explicit raw descriptor.
void priv_emu_io_txn_abort(emu_io_txn_t *txn)
Close and unlink an active sibling transaction without publication.
emu_io_result_t priv_emu_io_txn_commit(emu_io_txn_t *txn)
Sync, close, and atomically rename an active sibling transaction.
emu_io_result_t priv_emu_io_txn_begin(const char *path, emu_io_txn_t *txn)
Create a sibling temporary output for failure-atomic publication.
Shared aliased-memory backing and Unicorn memory-map bindings.
@ k_sdram_base
External SDRAM start.
Definition emu_memmap.h:46
@ k_sram_end
CPU0 SRAM end used by framebuffer checks.
Definition emu_memmap.h:44
@ k_dtcm_base
Data TCM start.
Definition emu_memmap.h:38
@ k_sram_base
On-chip SRAM start.
Definition emu_memmap.h:42
@ k_dtcm_end
Data TCM end.
Definition emu_memmap.h:40
@ k_sdram_end
External SDRAM end.
Definition emu_memmap.h:48
uc_err emu_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t count)
Read guest memory through the central access seam.
Sparse MMIO model of the Renesas peripheral space.
uint32_t mmio_peek(uint64_t addr)
Side-effect-free read of the last value written to a peripheral reg.
Definition emu_mmio.c:177
@ k_glcdc_bg_bgc
GLCDC BG.BGC background colour.
Definition emu_mmio.h:57
bool emu_presentation_read(const emu_presentation_workspace_t *workspace, size_t offset, void *bytes, size_t count)
Read exact RGB565 bytes at a checked surface offset.
@ k_emu_presentation_tile_px
Square rotation tile side.
bool emu_presentation_fill(void *context, uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color)
Fill a checked RGB565 rectangle in a raw-fd surface.
Board-view presentation: frames, composition, input routing, panels.
surface_color_t
GLCDC field and RGB conversion constants.
@ k_surface_b_drop
Packed blue truncation.
@ k_surface_rgb_g_shift
RGB888 green shift.
@ k_surface_g_keep
RGB565 green high bits.
@ k_surface_6bit
Six-bit channel mask.
@ k_surface_g565_shift
RGB565 green field shift.
@ k_surface_rgb_mask
Live background color mask.
@ k_surface_g_pos
Packed green position.
@ k_surface_fmt_rgb565
GLCDC RGB565 format code.
@ k_surface_r_keep
RGB565 red high bits.
@ k_surface_high_shift
Stride/count high-half shift.
@ k_surface_r_pos
Packed red position.
@ k_surface_fmt_shift
FORMAT[30:28] shift.
@ k_surface_stride_mask
FLM3 stride mask.
@ k_surface_r565_shift
RGB565 red field shift.
@ k_surface_byte_mask
One RGB888 component.
@ k_surface_5bit
Five-bit channel mask.
@ k_surface_lnnum_mask
FLM5 line count mask.
@ k_surface_fmt_mask
FORMAT mask.
@ k_surface_rgb_r_shift
RGB888 red shift.
static bool internal_address_is_ram(uint32_t address)
True when a source base lies in one emulated RAM region.
static uint16_t internal_rgb888_to_565(uint32_t rgb)
Pack a live 0x00RRGGBB background into RGB565.
surface_glcdc_reg_t
GLCDC layer registers decoded by the streamed renderer.
@ k_surface_gr1_fmt
GR[0].FLM6 pixel format.
@ k_surface_gr1_flm5
GR[0].FLM5 line count.
@ k_surface_gr1_flm3
GR[0].FLM3 line stride.
@ k_surface_gr1_saddr
GR[0].FLM2 framebuffer base.
static bool internal_read_tile(uc_engine *uc, const surface_layer_t *layer, const surface_tile_t *tile, uint16_t *source)
Read one bounded tile of the live layer into the scratch pixels.
static bool internal_write_layer(uc_engine *uc, emu_presentation_workspace_t *presentation, const surface_layer_t *layer)
Read, rotate, and write every active GLCDC tile.
int write_ppm(const char *path, const emu_presentation_workspace_t *presentation)
Write an RGB565 frame to a binary PPM (P6) for headless inspection.
static bool internal_write_ppm_pixels(int fd, const emu_presentation_workspace_t *presentation)
Convert and emit one bounded RGB565 chunk as PPM RGB bytes.
static surface_layer_t internal_layer(uint16_t panel_width, uint16_t panel_height)
Decode and clip the current GLCDC layer without guest-facing reads.
bool priv_emu_view_surface_build(uc_engine *uc, emu_presentation_workspace_t *presentation, const board_status_t *status)
Build one exact fd-backed composite from live engine and status state.
Internal streamed panel/composite builder seam.
Internal bounded RGB565 tile rotation/writer.
bool priv_emu_view_tile_write(emu_presentation_workspace_t *presentation, const uint16_t *source, uint16_t source_x, uint16_t source_y, uint16_t width, uint16_t height)
Rotate and write one native-panel tile into its exact display location.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Non-owning drawing surface used by memory and raw-fd compositors.
Live peripheral snapshot the status sidebar renders each frame.
emu_io_status_t status
Semantic completion status.
Sibling temporary file used for failure-atomic publication.
int fd
Owned temporary descriptor, or -1 when inactive.
One independent owned surface plus non-owning bounded scratch.
uint16_t panel_height
Native panel height.
uint16_t composite_width
Display plus sidebar width.
int fd
Owned unlinked descriptor, or -1.
uint16_t display_height
Rotation-adjusted panel height.
uint16_t composite_height
Display/sidebar maximum height.
uint16_t * scratch
Borrowed RGB565 scratch, or nullptr.
uint16_t display_width
Rotation-adjusted panel width.
size_t surface_bytes
Exact raw-fd RGB565 length.
uint16_t panel_width
Native panel width.
Live GLCDC source layer clipped to native panel geometry.
bool active
Valid RGB565 layer.
uint16_t width
Clipped source pixels.
uint32_t stride
Source row bytes.
uint32_t address
Emulated row-zero address.
uint16_t height
Clipped source rows.
One bounded source tile inside the live GLCDC layer.
uint16_t width
Tile width in source pixels.
uint16_t height
Tile height in source rows.
uint16_t y
Tile origin row in the source layer.
uint16_t x
Tile origin column in the source layer.