|
pico9918-core 1.3.0
TMS9918A / F18A video display processor emulation in C99
|
the live harness's desktop backend More...
#include "impl/pico9918_priv.h"#include "gpu/gpu.h"#include "pico9918.h"#include "pico9918_frame.h"#include <stddef.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <pthread.h>#include <time.h>
Include dependency graph for shim.c:Go to the source code of this file.
Data Structures | |
| struct | thread_t |
Macros | |
| #define | H_VIRTUAL_PIXELS 640 |
| #define | V_DISPLAY_LINES 480 |
| #define | FRAME_RATE_HZ 60.0f |
| #define | CORE_TEMP_C 30.0f |
| #define | FRAMES_AT_START 1000 |
| #define | CAPTURE_BYTES (512 * 512) |
| #define | RENDER_LOCK() pthread_mutex_lock(&renderLock) |
| #define | RENDER_UNLOCK() pthread_mutex_unlock(&renderLock) |
| #define | THREAD_BODY(name) static void* name(void* unused) |
| #define | THREAD_DONE return NULL |
Typedefs | |
| typedef void *(* | thread_body_t) (void *) |
Functions | |
| void | liveDesktopCaptureRow (uint16_t y, uint16_t height, uint16_t width_, const uint8_t *indices) |
| static void | renderFrameUnlocked (void) |
| static void | renderFrame (void) |
| static size_t | buildView (void) |
| static int | threadStart (thread_t *t, thread_body_t body) |
| static void | threadJoin (thread_t *t) |
| THREAD_BODY (gpuBody) | |
| THREAD_BODY (rasterBody) | |
| static void | gpuReap (void) |
| static void | gpuStart (uint16_t addr) |
| static uint8_t * | base (void) |
| static void | reply (const char *text) |
| static int | readExactly (void *into, size_t n) |
| static void | writeExactly (const void *from, size_t n) |
| int | main (void) |
Variables | |
| static PICO9918_PIXEL_T | pixels [1024] |
| static uint8_t | capture [CAPTURE_BYTES] |
| static uint32_t | rows = 0 |
| static uint32_t | width = 0 |
| static uint32_t | missed = 0 |
| static int | vPixelScale = 1 |
| static int | vVirtualPixels = V_DISPLAY_LINES |
| static uint32_t | triggerLine = V_DISPLAY_LINES |
| static int | viewScale = 2 |
| static pthread_mutex_t | renderLock = PTHREAD_MUTEX_INITIALIZER |
| static uint8_t | view [32+512 *480 *3] |
| static volatile int | gpuBusy = 0 |
| static thread_t | gpuThread |
| static thread_t | rasterThread |
the live harness's desktop backend
Project: pico9918
Copyright (c) 2026 Troy Schrapel
This code is licensed under the MIT license
https://github.com/visrealm/pico9918
test/live/ drives a board over SWD: it writes the scene into the instance's memory, waits, and reads back the rows the renderer produced. Every one of those three is memory access plus a render, and none of them is device-specific - so this speaks the same three operations over a pipe against an in-process library.
What that buys is the correctness half of the suite without a board: 111 scenes and their frozen references, on a desktop and in CI. What it cannot buy is the other half. The device measures microseconds and which lines did not fit, and neither has any meaning here. There is no timing hook in this build at all - see liveDesktopOps.h - so the numbers cannot be produced by accident.
THE ROWS ARE THE SAME ARTIFACT, and structurally rather than by agreement: the capture arrives through PICO9918_LINE_CAPTURE, the hook the firmware's own harness uses, at the same call site inside pico9918_frame_scanline, from the same pointer. This file renders through the frame path the firmware renders through; it does not reimplement it.
Protocol: one command a line on stdin, a reply a line on stdout, and payloads as raw bytes rather than hex - a full VRAM write is 16 KB and a capture 240 KB.
* off field offsets, one "name value" a line, then "end" * palette the library's default palette, 64 little-endian uint16 * w <hexaddr> <len> write <len> raw bytes that follow, instance-relative * r <hexaddr> <len> read: "data <len>" then <len> raw bytes * frames <n> render n frames, discarding them * capture render one frame: "capture <rows> <width>" then the rows * gpu <hexaddr> start a GPU program at <hexaddr> on its own thread, with * the raster running under it for as long as it does * gpupoll "gpu running", or "gpu done <microseconds>" * gpustop clear the GPU's run flag, which stops it where it is * quit *
Addresses are instance-relative, so the harness needs no notion of where the instance lives - which is also what keeps the two backends' address arithmetic identical.
Definition in file shim.c.
| void liveDesktopCaptureRow | ( | uint16_t | y, |
| uint16_t | height, | ||
| uint16_t | width_, | ||
| const uint8_t * | indices | ||
| ) |
|
static |
|
static |
|
static |