VxKernel 0.6.0-22 : Add SDL2 support (fake board) (WIP)

@add
<> src/driver/mpu/x86/sdl2
  | [sdl2] move SDL2 initialisation
  | [timer] add fake timer driver

@update
<> src/driver/mpu/x86/sdl2
  | [window] remove SDL2 initialisation

@fix
<> include/vhex/defs
  | [call] fix 64bits support
<> src/timer
  | [fps] fix negative margin
  | [fps] fix named fields
<> src/driver/mpu/sh/sh7305/tmu
  | [fps] fix elapsed time calculation
  | [fps] fix syncronisation waiting
  | [profiling] fix hardware time search
  | [profiling] fix safety guard for all primitives
  | [profiling] fix tmu_prof_quit()
  | [tmu] fix power symbols
  | [tmu] fix power primitives
<> src/display
  | [dtext] fix text register invalid write
This commit is contained in:
Yann MAGNIN 2022-08-25 13:03:55 +02:00
parent 2a107ad5b9
commit 9e1ed3cf58
10 changed files with 371 additions and 52 deletions

View File

@ -15,6 +15,8 @@ typedef union {
unsigned int u;
int32_t i32;
uint32_t u32;
uintptr_t up32;
intptr_t ip32;
/* 32-bit floating-point */
float f;
@ -85,11 +87,11 @@ typedef struct vhex_call vhex_call_t;
/* vhex_call(): Perform an indirect call */
static VINLINE int vhex_call(vhex_call_t callback)
{
return ((int(*)(int r4, int r5, int r6, int r7))callback.function)(
callback.args[0].i,
callback.args[1].i,
callback.args[2].i,
callback.args[3].i
return ((int(*)(uintptr_t, uintptr_t, uintptr_t, uintptr_t))callback.function)(
callback.args[0].up32,
callback.args[1].up32,
callback.args[2].up32,
callback.args[3].up32
);
}

View File

@ -8,9 +8,9 @@ struct timer_fps {
int fps;
int fps_real;
uint32_t render;
uint32_t margin;
int32_t margin;
uint32_t objectif;
uint32_t keyframe;
uint32_t anchor;
};
typedef struct timer_fps fps_t;

View File

@ -15,7 +15,7 @@ typedef struct timer_prof
{
uint32_t rec;
uint32_t elapsed;
uint32_t anchor;
} VPACKED(4) timer_prof_t;
#endif /* __VHEX_TIMER_TYPES__ */

View File

@ -81,7 +81,7 @@ static char *dtext_info_register(char const * const str)
}
}
len = strlen(str);
len = strlen(str) + 1;
if (len >= dtext_info.pool.text[dtext_info.pool.idx].size) {
dtext_info.pool.text[dtext_info.pool.idx].size = len;
dtext_info.pool.text[dtext_info.pool.idx].raw = reallocarray(

View File

@ -1,5 +1,6 @@
#include <vhex/timer/fps.h>
#include <vhex/driver/mpu/sh/sh7305/tmu.h>
#include <vhex/driver/mpu/sh/sh7305/cpg.h>
#include <vhex/driver/cpu.h>
#include <string.h>
@ -13,35 +14,35 @@ extern uint32_t *tmu_prof_tcnt;
/* sh7305_tmu_fps_init() : initialize fps object */
void sh7305_tmu_fps_init(fps_t *fps)
{
cpu_atomic_start();
sh7305_tmu_prof_init(NULL);
memset(fps, 0x00, sizeof(fps_t));
fps->keyframe = *tmu_prof_tcnt;
cpu_atomic_end();
}
/* sh7305_tmu_fps_sync() : compute frame statistic and wait whanted FPS */
void sh7305_tmu_fps_sync(fps_t *fps, int fps_target)
{
struct cpg_clock_frequency cpg_freq;
uint32_t snap;
snap = *tmu_prof_tcnt;
//TODO: proper freq calculation
cpg_clock_freq(&cpg_freq);
snap = (uint32_t)(((uint64_t)*tmu_prof_tcnt * 4 * 1000000) / cpg_freq.Pphi_f);
fps->objectif = 1000000 / fps_target;
fps->render = fps->keyframe - snap;
fps->render = fps->anchor - snap;
fps->margin = fps->objectif - fps->render;
fps->fps_real = 1000000 / fps->render;
fps->fps = fps->fps_real;
if (fps->margin <= 0)
if (fps->margin > 0)
fps->fps = fps_target;
while (1) {
if (*tmu_prof_tcnt - fps->keyframe >= fps->objectif)
if (*tmu_prof_tcnt - fps->anchor >= fps->objectif)
break;
}
fps->keyframe = *tmu_prof_tcnt;
fps->anchor = snap;
}
/* sh7305_fps_quit() : uninit the fps object */

View File

@ -23,7 +23,7 @@ int sh7305_tmu_prof_init(timer_prof_t *prof)
if (tmu_prof_tcnt == NULL) {
tmu_prof_timer = -1;
for(int t = 0; t < 2; t++)
for(int t = 0; t < 3; t++)
{
if (!available(t))
continue;
@ -38,52 +38,73 @@ int sh7305_tmu_prof_init(timer_prof_t *prof)
SH7305_TMU.TMU[t].TCR.CKEG = 0;
SH7305_TMU.TSTR |= 1 << t;
break;
}
if (tmu_prof_timer < 0) {
cpu_atomic_end();
return (-1);
return -1;
}
}
if (prof != NULL) {
prof->rec = 0;
prof->elapsed = 0;
prof->anchor = *tmu_prof_tcnt;
}
tmu_prof_counter += 1;
cpu_atomic_end();
return (0);
return 0;
}
/* sh7305_tmu_prof_enter(): Start counting time for a function */
void sh7305_tmu_prof_enter(timer_prof_t *prof)
{
if (prof == NULL)
return;
prof->anchor = 0;
if (tmu_prof_tcnt != NULL)
prof->elapsed += *tmu_prof_tcnt;
prof->anchor = *tmu_prof_tcnt;
}
/* sh7305_tmu_prof_enter_rec(): Start counting time for a recursive function */
void sh7305_tmu_prof_enter_rec(timer_prof_t *prof)
{
if (!prof->rec++ && tmu_prof_tcnt != NULL)
prof->elapsed += *tmu_prof_tcnt;
if (prof == NULL)
return;
if (prof->rec == 0)
sh7305_tmu_prof_enter(prof);
prof->rec += 1;
}
/* sh7305_tmu_prof_leave_rec(): Start counting time for a recursive function */
void sh7305_tmu_prof_leave_rec(timer_prof_t *prof)
{
if (!--prof->rec && tmu_prof_tcnt != NULL)
prof->elapsed -= *tmu_prof_tcnt;
if (prof == NULL)
return;
if (prof->rec <= 0) {
prof->rec = 0;
return;
}
prof->rec -= 1;
if (prof->rec == 0)
sh7305_tmu_prof_leave(prof);
}
/* sh7305_tmu_prof_leave(): Stop counting time for a function */
void sh7305_tmu_prof_leave(timer_prof_t *prof)
{
if (tmu_prof_tcnt != NULL)
prof->elapsed -= *tmu_prof_tcnt;
if (prof == NULL)
return;
if (tmu_prof_tcnt == NULL)
return;
uint32_t snapshot = *tmu_prof_tcnt;
prof->elapsed += prof->anchor - snapshot;
prof->anchor = snapshot;
}
@ -103,10 +124,11 @@ int sh7305_tmu_prof_quit(timer_prof_t *prof)
cpu_atomic_start();
if (--tmu_prof_counter <= 0) {
if(tmu_prof_timer >= 0)
if(tmu_prof_timer == 0)
sh7305_tmu_stop(tmu_prof_timer);
tmu_prof_timer = -1;
tmu_prof_tcnt = NULL;
tmu_prof_counter = 0;
}
cpu_atomic_end();
}

View File

@ -120,6 +120,7 @@ static int control(tid_t id, int state)
}
/* available(): Check if a timer is available (UNIE cleared, not running) */
//TODO: proper exposure
int available(int id)
{
if (id < 0 || id >= 9)
@ -491,19 +492,19 @@ static void __tmu_hrestore(struct tmu_ctx *s)
// alimentation to check. If one of them is powered, return that the whole
// driver is powered. The __tmu_hsave() and __tmu_hresotre() will handle the
// power management
static bool __dma_hpowered(void)
static bool __tmu_hpowered(void)
{
return (SH7305_POWER.MSTPCR0.TMU == 0 || SH7305_POWER.MSTPCR2.ETMU == 0);
}
static int __dma_hpoweron(void)
static int __tmu_hpoweron(void)
{
SH7305_POWER.MSTPCR0.TMU = 0;
SH7305_POWER.MSTPCR2.ETMU = 0;
return 0;
}
static int __dma_hpoweroff(void)
static int __tmu_hpoweroff(void)
{
SH7305_POWER.MSTPCR0.TMU = 1;
SH7305_POWER.MSTPCR2.ETMU = 1;
@ -514,6 +515,9 @@ static int __dma_hpoweroff(void)
struct vhex_driver drv_tmu = {
.name = "TMU",
.hpowered = (void*)&__tmu_hpowered,
.hpoweron = (void*)&__tmu_hpoweron,
.hpoweroff = (void*)&__tmu_hpoweroff,
.hsave = (void*)&__tmu_hsave,
.hrestore = (void*)&__tmu_hrestore,
.configure = (void*)&__tmu_configure,

View File

@ -0,0 +1,31 @@
#include <SDL2/SDL.h>
/* Literal error message printed to stderr, evaluates to 1 for a combined
return/exit() call */
#define err(fmt, ...) ({ \
fprintf(stderr, "error: " fmt "\n", ##__VA_ARGS__); \
1; \
})
SDL_Window *__sdl_window = NULL;
__attribute__((constructor))
static int __sdl2_init(void)
{
if(SDL_WasInit(SDL_INIT_VIDEO | SDL_INIT_TIMER))
return 0;
int rc = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
if(rc < 0)
return err("Cannot initialize SDL: %s\n", SDL_GetError());
}
__attribute__((destructor))
void __sdl_quit(void)
{
if(__sdl_window != NULL) {
SDL_DestroyWindow(__sdl_window);
__sdl_window = NULL;
}
}

View File

@ -0,0 +1,278 @@
#include <vhex/driver.h>
#include <vhex/timer/interface.h>
#include <SDL2/SDL.h>
//---
// Internal
//---
/* internal timer cache */
static struct {
bool used;
vhex_call_t call;
uint32_t delay;
SDL_TimerID id;
} timer_cache[9];
static uint32_t __sdl_tmu_nexus(uint32_t interval, int id)
{
(void)interval;
if (timer_cache[id].call.function != NULL) {
vhex_call(timer_cache[id].call);
}
return timer_cache[id].delay;
}
//---
// Public timer API
// FIXME : atomic operation
//---
/* sdl_tmu_reserve() : reserve a timer */
tid_t sdl_tmu_reserve(uint64_t delay)
{
for (int i = 0; i < 9; ++i) {
if (timer_cache[i].used == true)
continue;
timer_cache[i].used = true;
timer_cache[i].call = VHEX_CALL_NULL;
timer_cache[i].delay = delay / 1000;
timer_cache[i].id = 0;
return i;
}
return -1;
}
/* sdl_tmu_configure() : configure timer */
tid_t sdl_tmu_configure(uint64_t delay, vhex_call_t call)
{
tid_t id;
id = sdl_tmu_reserve(delay);
if (id < 0)
return id;
memcpy(&timer_cache[id].call, &call, sizeof(vhex_call_t));
return id;
}
/* sdl_tmu_start() - start a configured timer */
int sdl_tmu_start(tid_t id)
{
if (id < 0 || id >= 9) return -1;
if (timer_cache[id].id != 0) return -2;
timer_cache[id].id = SDL_AddTimer(
timer_cache[id].delay,
(void*)&__sdl_tmu_nexus,
(void*)(uintptr_t)id
);
}
/* sdl_tmu_reload() - change a timer's delay constant for next interrupts */
int sdl_tmu_reload(tid_t id, uint64_t delay)
{
if (id < 0 || id >= 9)
return -1;
timer_cache[id].delay = delay / 1000;
return 0;
}
/* sdl_tmu_pause() - stop a running timer */
int sdl_tmu_pause(tid_t id)
{
if (id < 0 || id >= 9)
return -1;
SDL_RemoveTimer(timer_cache[id].id);
timer_cache[id].id = 0;
return 0;
}
/* sdl_tmu_stop() - stop and free a timer */
int sdl_tmu_stop(tid_t id)
{
if (id < 0 || id >= 9)
return -1;
SDL_RemoveTimer(timer_cache[id].id);
timer_cache[id].id = 0;
timer_cache[id].used = false;
return 0;
}
//---
// Profiling API
//---
/* sdl_tmu_prof_make() : initialise a new profiling timer */
int sdl_tmu_prof_init(timer_prof_t *prof)
{
prof->anchor = SDL_GetTicks();
prof->elapsed = 0;
prof->rec = 0;
}
/* sdl_tmu_prof_enter(): Start counting time for a function */
void sdl_tmu_prof_enter(timer_prof_t *prof)
{
if (prof == NULL)
return;
prof->anchor = SDL_GetTicks();
}
/* sdl_tmu_prof_enter_rec(): Start counting time for a recursive function */
void sdl_tmu_prof_enter_rec(timer_prof_t *prof)
{
if (prof == NULL)
return;
if (prof->rec == 0)
sdl_tmu_prof_enter(prof);
prof->rec += 1;
}
/* sdl_tmu_prof_leave(): Stop counting time for a function */
void sdl_tmu_prof_leave(timer_prof_t *prof)
{
if (prof == NULL)
return;
uint32_t snapshot = SDL_GetTicks();
prof->elapsed += snapshot - prof->anchor;
prof->anchor = snapshot;
}
/* sdl_tmu_prof_leave_rec(): Start counting time for a recursive function */
void sdl_tmu_prof_leave_rec(timer_prof_t *prof)
{
if (prof == NULL)
return;
if (prof->rec <= 0) {
prof->rec = 0;
return;
}
prof->rec -= 1;
if (prof->rec == 0)
sdl_tmu_prof_leave(prof);
}
/* sdl_prof_time(): Time spent in a given context, in microseconds */
uint32_t sdl_tmu_prof_time(timer_prof_t *prof)
{
if (prof == NULL)
return 0;
return prof->elapsed * 1000;
}
/* sdl_tmu_prof_quit() : uninit the profoling object */
int sdl_tmu_prof_quit(timer_prof_t *prof)
{
(void)prof;
return 0;
}
//---
// FPS primitives
//---
/* sh7305_tmu_fps_init() : initialize fps object */
void sdl_tmu_fps_init(fps_t *fps)
{
memset(fps, 0x00, sizeof(fps_t));
fps->anchor = SDL_GetTicks();
}
/* sdl_tmu_fps_sync() : compute frame statistic and wait whanted FPS */
void sdl_tmu_fps_sync(fps_t *fps, int fps_target)
{
uint32_t snapshot;
snapshot = SDL_GetTicks();
fps->objectif = 1000 / fps_target;
fps->render = snapshot - fps->anchor;
fps->margin = fps->objectif - fps->render;
fps->fps_real = 1000 / fps->render;
fps->fps = fps->fps_real;
if (fps->margin > 0)
fps->fps = fps_target;
while (1) {
if (SDL_GetTicks() - fps->anchor >= fps->objectif)
break;
}
fps->anchor = SDL_GetTicks();
}
/* sdl_fps_quit() : uninit the fps object */
void sdl_tmu_fps_quit(fps_t *fps)
{
(void)fps;
}
//---
// fake driver specification
//---
static void __tmu_configure(void)
{
for (int i = 0; i < 9; ++i) {
timer_cache[i].used = false;
timer_cache[i].id = 0;
}
}
static void __tmu_hsave(void)
{
// Nothing to do, this is a fake driver
;
}
static void __tmu_hrestore(void)
{
// Nothing to do, this is a fake driver
;
}
struct vhex_driver drv_tmu = {
.name = "SDL2 Timer",
.hsave = (void*)&__tmu_hsave,
.hrestore = (void*)&__tmu_hrestore,
.configure = (void*)&__tmu_configure,
.state_size = 4,
.flags = {
.TIMER = 1,
.SHARED = 0,
.UNUSED = 0
},
.module_data = &(struct timer_drv_interface){
/* timer API */
.timer_reserve = &sdl_tmu_reserve,
.timer_configure = &sdl_tmu_configure,
.timer_start = &sdl_tmu_start,
.timer_pause = &sdl_tmu_pause,
.timer_stop = &sdl_tmu_stop,
.timer_wait = NULL,
.timer_spinwait = NULL,
.timer_reload = &sdl_tmu_reload,
/* profiling API */
.timer_prof_init = &sdl_tmu_prof_init,
.timer_prof_enter = &sdl_tmu_prof_enter,
.timer_prof_enter_rec = &sdl_tmu_prof_enter_rec,
.timer_prof_leave_rec = &sdl_tmu_prof_leave_rec,
.timer_prof_leave = &sdl_tmu_prof_leave,
.timer_prof_time = &sdl_tmu_prof_time,
.timer_prof_quit = &sdl_tmu_prof_quit,
/* fps API */
.timer_fps_init = &sdl_tmu_fps_init,
.timer_fps_sync = &sdl_tmu_fps_sync,
.timer_fps_quit = &sdl_tmu_fps_quit,
}
};
VHEX_DECLARE_DRIVER(03, drv_tmu);

View File

@ -3,23 +3,9 @@
#include <vhex/display/interface.h>
#include <vhex/driver.h>
/* Literal error message printed to stderr, evaluates to 1 for a combined
return/exit() call */
#define err(fmt, ...) ({ \
fprintf(stderr, "error: " fmt "\n", ##__VA_ARGS__); \
1; \
})
static SDL_Window *__sdl_window = NULL;
extern SDL_Window *__sdl_window;
__attribute__((destructor))
void quit(void)
{
if(__sdl_window != NULL) {
SDL_DestroyWindow(__sdl_window);
__sdl_window = NULL;
}
}
//---
// Driver primitives
@ -86,11 +72,6 @@ int sdl_frame_end(dsurface_t *surface)
static int __sdl_configure(void)
{
if(!SDL_WasInit(SDL_INIT_VIDEO)) {
int rc = SDL_Init(SDL_INIT_VIDEO);
if(rc < 0)
return err("Cannot initialize SDL: %s\n", SDL_GetError());
}
__sdl_window = SDL_CreateWindow(
"vxKernel",