diff --git a/include/vhex/defs/call.h b/include/vhex/defs/call.h index 50e0d54..6c22c2f 100644 --- a/include/vhex/defs/call.h +++ b/include/vhex/defs/call.h @@ -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 ); } diff --git a/include/vhex/timer/fps.h b/include/vhex/timer/fps.h index 6e8a0bb..48a3f99 100644 --- a/include/vhex/timer/fps.h +++ b/include/vhex/timer/fps.h @@ -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; diff --git a/include/vhex/timer/types.h b/include/vhex/timer/types.h index 0a8dacb..28a692c 100644 --- a/include/vhex/timer/types.h +++ b/include/vhex/timer/types.h @@ -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__ */ diff --git a/src/display/text/render/dtext.c b/src/display/text/render/dtext.c index eb4781b..cfa16fb 100644 --- a/src/display/text/render/dtext.c +++ b/src/display/text/render/dtext.c @@ -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( diff --git a/src/driver/mpu/sh/sh7305/tmu/fps.c b/src/driver/mpu/sh/sh7305/tmu/fps.c index 5bf6295..cbdbba9 100644 --- a/src/driver/mpu/sh/sh7305/tmu/fps.c +++ b/src/driver/mpu/sh/sh7305/tmu/fps.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -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 */ diff --git a/src/driver/mpu/sh/sh7305/tmu/profiling.c b/src/driver/mpu/sh/sh7305/tmu/profiling.c index f8f1951..0e0f3fe 100644 --- a/src/driver/mpu/sh/sh7305/tmu/profiling.c +++ b/src/driver/mpu/sh/sh7305/tmu/profiling.c @@ -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(); } diff --git a/src/driver/mpu/sh/sh7305/tmu/tmu.c b/src/driver/mpu/sh/sh7305/tmu/tmu.c index c43ce1c..72ead5b 100644 --- a/src/driver/mpu/sh/sh7305/tmu/tmu.c +++ b/src/driver/mpu/sh/sh7305/tmu/tmu.c @@ -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, diff --git a/src/driver/mpu/x86/sdl2/sdl2.c b/src/driver/mpu/x86/sdl2/sdl2.c new file mode 100644 index 0000000..9a708d4 --- /dev/null +++ b/src/driver/mpu/x86/sdl2/sdl2.c @@ -0,0 +1,31 @@ +#include + +/* 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; + } +} diff --git a/src/driver/mpu/x86/sdl2/timer.c b/src/driver/mpu/x86/sdl2/timer.c new file mode 100644 index 0000000..87faabc --- /dev/null +++ b/src/driver/mpu/x86/sdl2/timer.c @@ -0,0 +1,278 @@ +#include +#include + +#include + +//--- +// 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); diff --git a/src/driver/mpu/x86/sdl2/window.c b/src/driver/mpu/x86/sdl2/window.c index 625d67c..18e5bc2 100644 --- a/src/driver/mpu/x86/sdl2/window.c +++ b/src/driver/mpu/x86/sdl2/window.c @@ -3,23 +3,9 @@ #include #include -/* 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",