diff --git a/board/fxcg50/fxcg50.ld b/board/fxcg50/fxcg50.ld index 5c768e4..28fb00c 100644 --- a/board/fxcg50/fxcg50.ld +++ b/board/fxcg50/fxcg50.ld @@ -13,8 +13,8 @@ MEMORY { /* virtual memory, read-write segment */ userram (WX) : o = 0x00000000, l = 1M - /* On-chip IL memory */ - ilram (rwx): o = 0xe5200000, l = 4k + /* On-chip X memory */ + xram (rwx): o = 0xe5007000, l = 8k } SECTIONS @@ -157,16 +157,13 @@ SECTIONS /* On-chip memory sections: IL and Y (X is reserved) */ - . = ORIGIN(ilram); - .ilram ALIGN(4) : ALIGN(4) { - _lilram = LOADADDR(.ilram); - _rilram = . ; + . = ORIGIN(xram); + .xram ALIGN(4) : ALIGN(4) { - *(.vhex.ilram) + *(.vhex.xram) . = ALIGN(16); - } > ilram AT> userram - _silram = SIZEOF(.ilram); + } > xram AT> userram diff --git a/board/fxcg50/initialize.c b/board/fxcg50/initialize.c index dcb6e1c..758f4b7 100644 --- a/board/fxcg50/initialize.c +++ b/board/fxcg50/initialize.c @@ -10,15 +10,10 @@ #include #include - - /* Constructor and destructor arrays */ extern void (*bctors)(void), (*ectors)(void); extern void (*bdtors)(void), (*edtors)(void); -/* on-chip RAM information */ -extern uint32_t lilram, silram, rilram; /* IL memory section */ - /* User-provided main() function */ extern int main(void); @@ -33,22 +28,6 @@ static void callarray(void (**f)(void), void (**l)(void)) while(f < l) (*(*f++))(); } -/* regcpy(): Copy a memory region using symbol information - @l Source pointer (load address) - @s Size of area (should be a multiple of 16) - @r Destination pointer (relocation address) */ -static void regcpy(uint32_t * __restrict l, int32_t s, uint32_t * __restrict r) -{ - while(s > 0) - { - *r++ = *l++; - *r++ = *l++; - *r++ = *l++; - *r++ = *l++; - s -= 16; - } -} - /* initialize() : Where it all starts We are currently in a RAM location at a non-constant address due to the @@ -112,10 +91,6 @@ void initialize(void) tell us if we are running in an emulator or on a real device. */ hw_detect(); - /* move special on-chip RAM section */ - regcpy(&lilram, (uintptr_t)&silram, &rilram); - - /* Install Vhex, switch VBR, initialize drivers and modules */ kinit(); diff --git a/include/vhex/display/image/render.h b/include/vhex/display/image/render.h index e3e8902..ae4cea3 100644 --- a/include/vhex/display/image/render.h +++ b/include/vhex/display/image/render.h @@ -73,8 +73,9 @@ struct imgbox { }; /* dsubimage_render_box() : generate box information */ -extern void dsubimage_render_box( +extern int dsubimage_render_box( struct imgbox *imgbox, + dsurface_t *surface, image_t const *image, int x, int y, int left, int top, int width, int height diff --git a/include/vhex/display/stack.h b/include/vhex/display/stack.h index e5f2850..623aade 100644 --- a/include/vhex/display/stack.h +++ b/include/vhex/display/stack.h @@ -24,7 +24,7 @@ struct dstack_action { }; /* DSTACK_CALL - display indirect call */ -#define DSTACK_CALL(fct, ...) (dstack_call_t){ \ +#define DSTACK_CALL(fct, ...) (dstack_call_t*)&(dstack_call_t){ \ .routine = fct, \ .args = { __VA_ARGS__ } \ } diff --git a/include/vhex/driver.h b/include/vhex/driver.h index 0c4d153..b31557b 100644 --- a/include/vhex/driver.h +++ b/include/vhex/driver.h @@ -43,15 +43,15 @@ struct vhex_driver /* default flags for the driver */ byte_union(flags, - uint8_t :1; - uint8_t :1; - uint8_t TIMER :1; - uint8_t DISPLAY :1; + uint8_t :1; + uint8_t KEYBOARD :1; + uint8_t TIMER :1; + uint8_t DISPLAY :1; - uint8_t :1; - uint8_t :1; - uint8_t SHARED :1; - uint8_t UNUSED :1; + uint8_t :1; + uint8_t :1; + uint8_t SHARED :1; + uint8_t UNUSED :1; ); /* module related-internal data */ diff --git a/include/vhex/driver/mpu/sh/sh7305/keysc.h b/include/vhex/driver/mpu/sh/sh7305/keysc.h index 9f7f413..cb86700 100644 --- a/include/vhex/driver/mpu/sh/sh7305/keysc.h +++ b/include/vhex/driver/mpu/sh/sh7305/keysc.h @@ -73,4 +73,31 @@ struct __sh7305_keysc_s #define SH7305_KEYSC (*(volatile struct __sh7305_keysc_s *)0xa44b0000) +//--- +// Internal API +//--- + +#include + +/* sh7305_keycache_init() : initialise the keycache information */ +extern void sh7305_keycache_init(void); + +/* sh7305_keycache_add_key() : involved by the interrupt handler */ +extern void sh7305_keycache_update(key_t key, int status); + +/* sh7305_keycache_quit() : quit the keycache */ +extern void sh7305_keycache_quit(void); + +/* sh7305_keycache_keydown() : return the key status */ +extern int sh7305_keycache_keydown(key_t key); + +/* sh7305_keycache_event_wait() : wait event or timeout != 0 */ +extern void sh7305_keycache_event_wait(key_event_t *e, volatile int *timeout); + +/* sh7305_keycache_event_push() : pop event from the keycache */ +extern void sh7305_keycache_event_pop(key_event_t *event); + +/* sh7305_keycache_event_push() : push event on the keycache */ +extern void sh7305_keycache_event_push(key_event_t *event); + #endif /* __VHEX_ARCH_SH7305_KEYSC__ */ diff --git a/include/vhex/driver/mpu/sh/sh7305/tmu.h b/include/vhex/driver/mpu/sh/sh7305/tmu.h index bf4ffa6..e41348c 100644 --- a/include/vhex/driver/mpu/sh/sh7305/tmu.h +++ b/include/vhex/driver/mpu/sh/sh7305/tmu.h @@ -80,6 +80,65 @@ typedef volatile etmu_t sh7305_etmu_t[6]; #define SH7305_ETMU (*(sh7305_etmu_t *)0xa44d0030) +//--- +// internal API +//--- +#include + +/* timer */ + +/* sh7305_tmu_reserve() : reserve a timer */ +extern tid_t sh7305_tmu_reserve(uint64_t delay); + +/* sh7305_tmu_configure() : configure timer */ +extern tid_t sh7305_tmu_configure(uint64_t delay, timer_call_t call); + +/* sh7305_tmu_start() - start a configured timer */ +extern int sh7305_tmu_start(tid_t id); + +/* sh7305_tmu_reload() - change a timer's delay constant for next interrupts */ +extern int sh7305_tmu_reload(tid_t id, uint64_t delay); + +/* sh7305_tmu_pause() - stop a running timer */ +extern int sh7305_tmu_pause(tid_t id); + +/* sh7305_tmu_stop() - stop and free a timer */ +extern int sh7305_tmu_stop(tid_t id); + +/* sh7305_tmu_wait(): Wait for a timer to stop */ +extern int sh7305_tmu_wait(tid_t id); + +/* sh7305_tmu_spinwait(): Start a timer and actively wait for UNF */ +extern int sh7305_tmu_spinwait(tid_t id); + +/* sh7305_tmu_get_tcnt() : return the timer TCNT register address */ +extern volatile uint32_t *sh7305_tmu_get_tcnt(tid_t id); + +/* sh7305_tmu_set_tcor() : set the timer TCOR value */ +extern void sh7305_tmu_set_tcor(tid_t id, uint32_t value); + +/* profiling */ + +/* sh7305_tmu_prof_make() : initialise a new */ +extern int sh7305_tmu_prof_init(timer_prof_t *prof); + +/* sh7305_tmu_prof_enter(): Start counting time for a function */ +extern void sh7305_tmu_prof_enter(timer_prof_t *prof); + +/* sh7305_tmu_prof_enter_rec(): Start counting time for a recursive function */ +extern void sh7305_tmu_prof_enter_rec(timer_prof_t *prof); + +/* sh7305_tmu_prof_leave_rec(): Start counting time for a recursive function */ +extern void sh7305_tmu_prof_leave_rec(timer_prof_t *prof); + +/* sh7305_tmu_prof_leave(): Stop counting time for a function */ +extern void sh7305_tmu_prof_leave(timer_prof_t *prof); + +/* sh7305_prof_time(): Time spent in a given context, in microseconds */ +extern uint32_t sh7305_tmu_prof_time(timer_prof_t *prof); + +/* sh7305_tmu_prof_quit() : uninit the profoling object */ +extern int sh7305_tmu_prof_quit(timer_prof_t *prof); #endif /* __VHEX_MPU_SH7305_TMU__ */ diff --git a/include/vhex/keyboard.h b/include/vhex/keyboard.h index bff151c..6d64e2c 100644 --- a/include/vhex/keyboard.h +++ b/include/vhex/keyboard.h @@ -1,98 +1,5 @@ -#ifndef __KERNEL_DEVICES_KEYBOARD_H__ -# define __KERNEL_DEVICES_KEYBOARD_H__ - -#include - - - -/* key_t : Define all keycode */ -typedef enum key_e -{ - KEY_F1 = 0x41, - KEY_F2 = 0x42, - KEY_F3 = 0x43, - KEY_F4 = 0x44, - KEY_F5 = 0x45, - KEY_F6 = 0x46, - - KEY_SHIFT = 0x49, - KEY_OPTN = 0x4a, - KEY_VARS = 0x4b, - KEY_MENU = 0x4c, - KEY_LEFT = 0x4d, - KEY_UP = 0x4e, - - KEY_ALPHA = 0x31, - KEY_SQUARE = 0x32, - KEY_POWER = 0x33, - KEY_EXIT = 0x34, - KEY_DOWN = 0x35, - KEY_RIGHT = 0x36, - - KEY_XOT = 0x39, - KEY_LOG = 0x3a, - KEY_LN = 0x3b, - KEY_SIN = 0x3c, - KEY_COS = 0x3d, - KEY_TAN = 0x3e, - - KEY_FRAC = 0x21, - KEY_FD = 0x22, - KEY_LEFTP = 0x23, - KEY_RIGHTP = 0x24, - KEY_COMMA = 0x25, - KEY_ARROW = 0x26, - - KEY_7 = 0x29, - KEY_8 = 0x2a, - KEY_9 = 0x2b, - KEY_DEL = 0x2c, - - KEY_4 = 0x11, - KEY_5 = 0x12, - KEY_6 = 0x13, - KEY_MUL = 0x14, - KEY_DIV = 0x15, - - KEY_1 = 0x19, - KEY_2 = 0x1a, - KEY_3 = 0x1b, - KEY_PLUS = 0x1c, - KEY_MINUS = 0x1d, - - KEY_0 = 0x01, - KEY_DOT = 0x02, - KEY_EXP = 0x03, - KEY_NEG = 0x04, - KEY_EXE = 0x05, - - KEY_UNUSED = 0xff -} key_t; - - -//--- -// internal Key Cache module API -//--- - - -/* KEYSCODE_GEN() : generate keycode */ -#define KEYCODE_GEN(row, column) \ - (((row & 0x0f) << 4) | ((column & 0x0f) << 0)) - -/* keycache : Internal structure used by the keyboard abstraction */ -struct keycache_s -{ - uint8_t keycode; - uint8_t keyframe; - uint32_t repeated; - struct keycache_s *next; -}; - -/* keycache_clean() : remove all event which not math the key_frame */ -extern void keycache_clean(int key_frame); - -/* keycache_update() : add a new key event */ -extern void keycache_update(int row, int column, uint8_t key_frame); - - -#endif /*__KERNEL_DEVICES_KEYBOARD_H__*/ +#include +#include +#include +#include +#include diff --git a/include/vhex/keyboard/getkey.h b/include/vhex/keyboard/getkey.h new file mode 100644 index 0000000..cc5036e --- /dev/null +++ b/include/vhex/keyboard/getkey.h @@ -0,0 +1,106 @@ +#ifndef __VHEX_KEYBOARD_GETKEY__ +# define __VHEX_KEYBOARD_GETKEY__ + +#include + +//--- +// High-level functions +//--- + +/* getkey(): Wait for a key press + + This function mimics the behavior of the fxlib GetKey(). It returns a + key_event_t object where [mod=1], and where [shift] and [alpha] indicate + whether SHIFT or ALPHA was pressed before the key was hit. [event] is + KEYEV_DOWN when a new key is pressed and KEYEV_HOLD in case of repeats. + + Similarities with GetKey() include: + - Wait for a key to be pressed *after* the call (held keys don't count) + - Supports SHIFT and ALPHA modifiers + - Repeats arrows keys + - Allows return to main menu if the MENU key is pressed + - Controls backlight on models that have a back-lit screen + + getkey() is equivalent to getkey_opt(GETKEY_DEFAULT, NULL). */ +extern key_event_t getkey(void); + +/* The following are the option bits for getkey_opt(). */ +enum { + /* Enable modifiers keys */ + GETKEY_MOD_SHIFT = 0x01, + GETKEY_MOD_ALPHA = 0x02, + /* SHIFT + OPTN toggles backlight (requires GETKEY_MOD_SHIFT) */ + GETKEY_BACKLIGHT = 0x04, + /* MENU triggers a task switch and displays the main menu */ + GETKEY_MENU = 0x08, + /* Repeat arrow keys, or even all keys */ + GETKEY_REP_ARROWS = 0x10, + GETKEY_REP_ALL = 0x20, + /* Enable custom repeat profiles; see getkey_set_repeat_profile() */ + GETKEY_REP_PROFILE = 0x40, + /* Enable application shortcuts; see getkey_set_feature_function() */ + GETKEY_FEATURES = 0x80, + + /* No modifiers */ + GETKEY_NONE = 0x00, + /* Default settings of getkey() */ + GETKEY_DEFAULT = 0xdf, +}; + +/* getkey_profile_t: Custom repeat profile function + See getkey_set_repeat_profile() for details. */ +typedef int (*getkey_profile_t)(int key, int duration, int count); + +/* getkey_feature_t: Custom feature function + See getkey_set_feature_function() for details. */ +typedef bool (*getkey_feature_t)(key_event_t event); + +/* getkey_opt(): Enhanced getkey() + + This function enhances getkey() with more general features. An + or-combination of option flags (see above) must be supplied as first + argument; GETKEY_NONE stands for no option. getkey_opt() returns the same + kind of events as getkey(). + + getkey_opt() supports a generic timeout function in the form of a volatile + pointer [timeout]. If it's NULL, getkey_opt() waits indefinitely. Otherwise, + it waits until *timeout becomes non-zero. It's up to you to change the + value whenever you want to interrupt the call; using a timer with + [timer_timeout] as callback is suitable. + + Event transforms in getkey_opt() (SHIFT, ALPHA and repetitions) are handled + by changing the transform settings on the keyboard device. These settings + are restored when getkey_opt() returns, so if they are originally disabled + (which they are unless set manually) then the status of the SHIFT and ALPHA + keys is lost between calls (this has an effect it getkey_opt() is + interrupted by timeout). Therefore, in order to use modifiers across several + calls to getkey_opt(), make sure to enable the transforms on the keyboard + device. + + @options An or-combination of values from the GETKEY_* enumeration + @timeout Optional pointer to a timeout value + Returns a key event of type KEYEV_DOWN or KEYEV_HOLD with [mod=1]. */ +extern key_event_t getkey_opt(int options, volatile int *timeout); + +/* getkey_repeat(): Set repeat delays for getkey() + + This function updates the repeat delays of getkey() and getkey_opt(). The + unit of the argument is in milliseconds, but the granularity of the delay is + dependent on the keyboard scan frequency. + + In the default setting (128 Hz scans), the possible repeat delays are + approximately 8 ms, 16 ms, 23 ms, 31 ms... the provided arguments will be + rounded to the closest feasible delays to ensure that repetitions are + perfectly regular, rather than approximating the requested frequency. + + The system default is (500 ms, 125 ms). With the 128 Hz setting, this + default is reached exactly without approximation. vhex's default is (400 ms, + 40 ms) for more reactivity. + + @first Delay between key press and first repeat (no more than one hour) + @next Delay between subsequent repeats (no more than one hour) */ +extern void getkey_repeat(int first, int next); + + +#endif /* __VHEX_KEYBOARD_GETKEY__ */ + diff --git a/include/vhex/keyboard/interface.h b/include/vhex/keyboard/interface.h new file mode 100644 index 0000000..b4b1aeb --- /dev/null +++ b/include/vhex/keyboard/interface.h @@ -0,0 +1,17 @@ +#ifndef __VHEX_KEYBOARD_INTERFACE__ +# define __VHEX_KEYBOARD_INTERFACE__ + +#include + +/* keyboard_drv_interface - driver interface */ +struct keyboard_drv_interface +{ + void (*keycache_init)(void); + int (*keycache_keydown)(key_t key); + void (*keycache_event_wait)(key_event_t *event, volatile int *timeout); + void (*keycache_event_pop)(key_event_t *event); + void (*keycache_event_push)(key_event_t *event); + void (*keycache_quit)(void); +}; + +#endif /* __VHEX_KEYBOARD_INTERFACE__ */ diff --git a/include/vhex/keyboard/keycache.h b/include/vhex/keyboard/keycache.h new file mode 100644 index 0000000..2bcffeb --- /dev/null +++ b/include/vhex/keyboard/keycache.h @@ -0,0 +1,25 @@ +#ifndef __VHEX_KEYBOARD_KEYCACHE__ +# define __VHEX_KEYBOARD_KEYCACHE__ + +#include + +/* keycache_init() : initialize the keycache */ +extern void keycache_init(void); + +/* keycache_keydown() : check the current key state */ +extern int keycache_keydown(key_t key); + +/* keycache_event_wait() : wait until the next event or the timeout != 0 */ +extern void keycache_event_wait(key_event_t *event, volatile int *timeout); + +/* keycache_event_pop() : pop the first key event in the cache */ +extern void keycache_event_pop(key_event_t * event); + +/* keycache_event_push() : push a key event in the cache */ +extern void keycache_event_push(key_event_t * event); + +/* keycache_init() : uninit the keycache */ +extern void keycache_quit(void); + + +#endif /* __VHEX_KEYBOARD_KEYCACHE__ */ diff --git a/include/vhex/keyboard/keycode.h b/include/vhex/keyboard/keycode.h new file mode 100644 index 0000000..b093991 --- /dev/null +++ b/include/vhex/keyboard/keycode.h @@ -0,0 +1,75 @@ +#ifndef __VHEX_KEYBOARD_KEYCODE__ +# define __VHEX_KEYBOARD_KEYCODE__ + + +/* KEYSCODE_GEN() : generate keycode */ +#define KEYCODE_GEN(row, column) \ + (((row & 0x0f) << 4) | ((column & 0x0f) << 0)) + + +/* key_t : Define all keycode */ +typedef enum key_e +{ + KEY_F1 = 0x41, + KEY_F2 = 0x42, + KEY_F3 = 0x43, + KEY_F4 = 0x44, + KEY_F5 = 0x45, + KEY_F6 = 0x46, + + KEY_SHIFT = 0x49, + KEY_OPTN = 0x4a, + KEY_VARS = 0x4b, + KEY_MENU = 0x4c, + KEY_LEFT = 0x4d, + KEY_UP = 0x4e, + + KEY_ALPHA = 0x31, + KEY_SQUARE = 0x32, + KEY_POWER = 0x33, + KEY_EXIT = 0x34, + KEY_DOWN = 0x35, + KEY_RIGHT = 0x36, + + KEY_XOT = 0x39, + KEY_LOG = 0x3a, + KEY_LN = 0x3b, + KEY_SIN = 0x3c, + KEY_COS = 0x3d, + KEY_TAN = 0x3e, + + KEY_FRAC = 0x21, + KEY_FD = 0x22, + KEY_LEFTP = 0x23, + KEY_RIGHTP = 0x24, + KEY_COMMA = 0x25, + KEY_ARROW = 0x26, + + KEY_7 = 0x29, + KEY_8 = 0x2a, + KEY_9 = 0x2b, + KEY_DEL = 0x2c, + + KEY_4 = 0x11, + KEY_5 = 0x12, + KEY_6 = 0x13, + KEY_MUL = 0x14, + KEY_DIV = 0x15, + + KEY_1 = 0x19, + KEY_2 = 0x1a, + KEY_3 = 0x1b, + KEY_PLUS = 0x1c, + KEY_MINUS = 0x1d, + + KEY_0 = 0x01, + KEY_DOT = 0x02, + KEY_EXP = 0x03, + KEY_NEG = 0x04, + KEY_EXE = 0x05, + + KEY_UNUSED = 0xff, + KEY_NONE = 0xfe, +} key_t; + +#endif /* __VHEX_KEYBOARD_KEYCODE__ */ diff --git a/include/vhex/keyboard/keydown.h b/include/vhex/keyboard/keydown.h new file mode 100644 index 0000000..cd03bf6 --- /dev/null +++ b/include/vhex/keyboard/keydown.h @@ -0,0 +1,27 @@ +#ifndef __VHEX_KEYBOARD_KEYDOWN__ +# define __VHEX_KEYBOARD_KEYDOWN__ + +#include + +//--- +// Key state functions +//--- + +/* keydown(): Current key state + This function returns zero if the specified key is currently up (according + to the last events that have been processed) and non-zero if it is down. */ +extern int keydown(key_t key); + +/* keydown_all(): Check a set of keys for simultaneous input + Returns non-zero if all provided keys are down. The list should end with + KEY_NONE as terminator. */ +extern int keydown_all(key_t key1, ...); + +/* keydown_any(): Check a set of keys for any input + Returns nonzero if any one of the specified keys is currently pressed. The + sequence should be terminated by KEY_NONE. */ +extern int keydown_any(key_t key1, ...); + + + +#endif /* __VHEX_KEYBOARD_KEYDOWN__ */ diff --git a/include/vhex/keyboard/keyvent.h b/include/vhex/keyboard/keyvent.h new file mode 100644 index 0000000..8047912 --- /dev/null +++ b/include/vhex/keyboard/keyvent.h @@ -0,0 +1,27 @@ +#ifndef __VHEX_KEYBOARD_KEYVENT__ +# define __VHEX_KEYBOARD_KEYVENT__ + +#include + +//--- +// Event-level functions +//--- + +/* keyvent_poll(): Poll the next keyboard event + This function returns the next event from the event queue, chronologically. + If no event is available, it returns a dummy event with type=KEYEV_NONE + and time set to the current driver time. This function always returns events + with mod=0. */ +extern key_event_t keyvent_poll(void); + +/* waitevent(): Wait for the next keyboard event + This function works as pollevent() but waits if no event is available. When + timeout=NULL, it waits indefinitely. Otherwise, it waits until *timeout + becomes non-zero (by using a timer for exemple). */ +extern key_event_t keyvent_wait(volatile int *timeout); + +/* clearevents(): Clear all events waiting in the queue */ +extern void keyvent_clear(void); + + +#endif /* __VHEX_KEYBOARD_KEYVENT__ */ diff --git a/include/vhex/keyboard/time.h b/include/vhex/keyboard/time.h new file mode 100644 index 0000000..6d96972 --- /dev/null +++ b/include/vhex/keyboard/time.h @@ -0,0 +1,35 @@ +#ifndef __VHEX_KEYBOARD_TIME__ +# define __VHEX_KEYBOARD_TIME__ + +#include + +//--- +// Time frequency settings +// +// Unlike Gint, I use the KeyScan Interface for the key matrix scanning, but I +// whant to keep the notion of "time" to know the elapsed time between each key +// strokes, because this information is usefull for game which whant to analyse +// combo. +// +// So, I use a ETMU whith no interruption which refert to the "time" indicator, +// and this part of the API is usefull to change the granularity of said timer. +//--- + +/* keysc_time_frequency(): Get the current keyboard time frequency in Hertz */ +extern int keysc_time_frequency(void); + +/* keysc_scan_frequency_us(): Get keyboard time delay in microseconds */ +extern uint32_t keysc_time_frequency_us(void); + +/* keysc_set_time_frequency(): Set the keyboard scan frequency in Hertz + + The new frequency must be at least 64 for the keyboard to work reliably, and + at most 32768 for the underlying ETMU to support it. Out-of-range values are + forced to the closest valid value. + + @freq New scan frequency, in Hertz */ +extern void keysc_set_time_frequency(int freq); + + + +#endif /* __VHEX_KEYBOARD_TIME__ */ diff --git a/include/vhex/keyboard/types.h b/include/vhex/keyboard/types.h new file mode 100644 index 0000000..f6d4e89 --- /dev/null +++ b/include/vhex/keyboard/types.h @@ -0,0 +1,60 @@ +#ifndef __VHEX_KEYBOARD_TYPES__ +# define __VHEX_KEYBOARD_TYPES__ + +#include +#include + +#include + +/* key_event_t: Low-level or high-level keyboard event + + This structure represents an event that occurs on the keyboard. It is first + produced by the keyboard scanner with limited information, then possibly + enriched by getkey(). Events are produced each time the keyboard emit + interruption. + + getkey() returns enriched events with [mod=1], in whic ase [shift] and + [alpha] indicate whether the key has been modified. Only key press events + returned by getkey() have [mod=1]. Note that you can't have, e.g. + [key=KEY_SHIFT] and [mod=1] at the same time. + + The [time] attribute indicates when the event occurred. It is a snapshot of + a time counter that increases at each keyboard scan and *wraps around every + 8 minutes* (at 128 Hz). I expect this attribute to be useful to analyze + combo sequences in games. Make sure you are aware of the two nitpicks: + * Don't keep the time values for too long because of the wrap-around effect. + * 0xffff is "just before" 0x0000, not "long after". */ +typedef struct +{ + uint time :16; /* Time of event, unique over short periods */ + + uint rep_type :3; /* Repetition type */ + + uint mod :1; /* Whether modifiers are used */ + uint shift :1; /* If mod=1, whether SHIFT was pressed */ + uint alpha :1; /* If mod=1, whether ALPHA was pressed */ + + uint type :2; /* Type of key event */ + uint key :8; /* Hit key */ + +} VPACKED(4) key_event_t; + +/* Keyboard event types, as in the [type] field of key_event_t */ +enum +{ + KEYEV_NONE = 0, /* No event available (poll() only) */ + KEYEV_DOWN = 1, /* Key was pressed */ + KEYEV_UP = 2, /* Key was released */ + KEYEV_HOLD = 3, /* A key that was pressed has been held down */ +}; + +/* keyboard repetition type */ +enum +{ + KEYEV_REP_NONE = 0, + KEYEV_REP_FIRST = 1, + KEYEV_REP_NEXT = 2, +}; + + +#endif /* __VHEX_KEYBOARD_TYPES__ */ diff --git a/include/vhex/timer.h b/include/vhex/timer.h index 9a31e09..aa6136c 100644 --- a/include/vhex/timer.h +++ b/include/vhex/timer.h @@ -27,6 +27,12 @@ enum { again after the same delay) or stop the timer. */ extern tid_t timer_configure(uint64_t delay_us, timer_call_t callback); +/* timer_reserve() : reserve a timer + + The timer can be used normaly, but no callback nor interruption will occur. + This primitive is usefull if you whant to have only the timer counter */ +extern tid_t timer_reserve(uint64_t delay_us); + /* timer_start(): Start a configured timer */ extern int timer_start(tid_t timer); diff --git a/include/vhex/timer/interface.h b/include/vhex/timer/interface.h index 86d7c4b..761774a 100644 --- a/include/vhex/timer/interface.h +++ b/include/vhex/timer/interface.h @@ -8,6 +8,7 @@ struct timer_drv_interface { /* timer API */ + tid_t (*timer_reserve)(uint64_t delay_us); tid_t (*timer_configure)(uint64_t delay_us, timer_call_t callback); int (*timer_start)(tid_t timer); int (*timer_pause)(tid_t timer); diff --git a/src/drivers/mpu/sh/sh7305/keysc/handler.c b/src/drivers/mpu/sh/sh7305/keysc/handler.c index ed1964b..3dc9cec 100644 --- a/src/drivers/mpu/sh/sh7305/keysc/handler.c +++ b/src/drivers/mpu/sh/sh7305/keysc/handler.c @@ -2,16 +2,15 @@ #include #include -/* Internal indicator used by high-level function to notice when the key list - is updated */ -volatile uint8_t keylist_isUpdate = 0; + +extern void sh7305_keycache_update(key_t key, int status); /* sh7305_keysc_int_handler() : SH7305 KEYSC interrupt handler */ void sh7305_keysc_int_handler(void) { - static uint8_t keyframe = 0; int intlevel; int column; + key_t key; int row; /* Block / disable KEYSC interrupt (otherwise the module will crash) */ @@ -19,26 +18,20 @@ void sh7305_keysc_int_handler(void) intlevel = SH7305_INTC._IPRX->IPRF.KEYSC; SH7305_INTC._IPRX->IPRF.KEYSC = 0; - - /* update the keyframe */ - keyframe = keyframe + 1; - /* update the keycache */ row = 6; + key = 0x5f; while (--row >= 0) { column = 16; while (--column >= 0) { - if (SH7305_KEYSC.KIUDATA[row] & (0x8000 >> column)) - keycache_update(row, column, keyframe); + sh7305_keycache_update( + key, + SH7305_KEYSC.KIUDATA[row] & (0x8000 >> column) + ); + key -= 1; } } - /* Clean key cache (remove unpressed key) */ - keycache_clean(keyframe); - - /* Indicate that the key list has been udpated */ - keylist_isUpdate = 1; - /* Clear KEYSC interrupt, really */ SH7305_KEYSC.KIUINTREG.word = SH7305_KEYSC.KIUINTREG.word; diff --git a/src/drivers/mpu/sh/sh7305/keysc/keycache.c b/src/drivers/mpu/sh/sh7305/keysc/keycache.c new file mode 100644 index 0000000..fbd22b8 --- /dev/null +++ b/src/drivers/mpu/sh/sh7305/keysc/keycache.c @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include + +#include +#include + +struct { + key_event_t keycache[96]; + struct { + key_event_t *list; + int nb_evt_max; + int idx; + } queue; + struct { + tid_t id; + volatile uint16_t counter; + } timer; +} keyinfo; + +//--- +// kernel-level API +//--- + +static int __sh7305_keycache_keyframe(volatile uint16_t *counter) +{ + *counter += 1; + return TIMER_CONTINUE; +} + +/* sh7305_keycache_init() : initialise the keycache information */ +void sh7305_keycache_init(void) +{ + for (int i = 0; i < 96 ; ++i) { + keyinfo.keycache[i].rep_type = KEYEV_REP_NONE; + keyinfo.keycache[i].type = KEYEV_UP; + keyinfo.keycache[i].key = i; + } + + keyinfo.queue.idx = -1; + keyinfo.queue.nb_evt_max = 16; + keyinfo.queue.list = calloc( + keyinfo.queue.nb_evt_max, + sizeof(key_event_t) + ); + + keyinfo.timer.id = sh7305_tmu_configure( + 7215, + TIMER_CALL( + &__sh7305_keycache_keyframe, + (uintptr_t)&keyinfo.timer.counter + ) + ); + sh7305_tmu_start(keyinfo.timer.id); +} + +/* sh7305_keycache_update() : involved by the interrupt handler + + Note : this function SHOULD be involved with atomic context !! */ +void sh7305_keycache_update(key_t key, int status) +{ + status = (status != 0) ? KEYEV_DOWN : KEYEV_UP; + + if (keyinfo.keycache[key].type == status) + return; + + keyinfo.keycache[key].type = status; + sh7305_keycache_event_push(&keyinfo.keycache[key]); +} + +/* sh7305_keycache_quit() : quit the keycache */ +void sh7305_keycache_quit(void) +{ + sh7305_tmu_stop(keyinfo.timer.id); + free(keyinfo.queue.list); + keyinfo.queue.idx = -1; + keyinfo.queue.nb_evt_max = 0; +} + + +//--- +// driver-level API +//--- + +/* sh7305_keycache_keydown() : return the key status */ +int sh7305_keycache_keydown(key_t key) +{ + int info; + + cpu_atomic_start(); + info = keyinfo.keycache[key].type; + cpu_atomic_end(); + + return info == KEYEV_DOWN; +} + +/* sh7305_keycache_event_wait() : wait event or timeout != 0 */ +void sh7305_keycache_event_wait(key_event_t *event, volatile int *timeout) +{ + key_event_t e; + + do { + sh7305_keycache_event_pop(&e); + if (e.type != KEYEV_NONE) { + event->time = e.time; + event->type = e.type; + event->key = e.key; + return; + } + if (timeout != NULL && timeout != 0) { + event->type = KEYEV_NONE; + event->key = KEY_NONE; + return; + } + __asm__("sleep"); + } while (1); +} + +/* sh7305_keycache_event_push() : push event on the keycache */ +void sh7305_keycache_event_push(key_event_t *event) +{ + cpu_atomic_start(); + + keyinfo.queue.idx += 1; + if (keyinfo.queue.idx >= keyinfo.queue.nb_evt_max) { + keyinfo.queue.nb_evt_max += keyinfo.queue.nb_evt_max; + keyinfo.queue.list = reallocarray( + keyinfo.queue.list, + keyinfo.queue.nb_evt_max, + sizeof(key_event_t) + ); + } + + keyinfo.queue.list[keyinfo.queue.idx].time = keyinfo.timer.counter; + keyinfo.queue.list[keyinfo.queue.idx].type = event->type; + keyinfo.queue.list[keyinfo.queue.idx].key = event->key; + + cpu_atomic_end(); +} + +/* sh7305_keycache_event_push() : pop event from the keycache */ +void sh7305_keycache_event_pop(key_event_t *event) +{ + cpu_atomic_start(); + + if (keyinfo.queue.idx < 0) { + event->key = KEY_NONE; + event->type = KEYEV_NONE; + } else { + event->time = keyinfo.queue.list[0].time; + event->type = keyinfo.queue.list[0].type; + event->key = keyinfo.queue.list[0].key; + + memcpy( + &keyinfo.queue.list[0], + &keyinfo.queue.list[1], + sizeof(key_event_t) * keyinfo.queue.idx + ); + + keyinfo.queue.idx -= 1; + } + + + cpu_atomic_end(); +} diff --git a/src/drivers/mpu/sh/sh7305/keysc/keysc.c b/src/drivers/mpu/sh/sh7305/keysc/keysc.c index 9a0a054..72d22f5 100644 --- a/src/drivers/mpu/sh/sh7305/keysc/keysc.c +++ b/src/drivers/mpu/sh/sh7305/keysc/keysc.c @@ -1,5 +1,6 @@ #include #include +#include #include /* define the private KeyScan context structure */ @@ -126,6 +127,19 @@ struct vhex_driver drv_keysc = { .hsave = (void*)&__keysc_hsave, .hrestore = (void*)&__keysc_hrestore, .configure = (void*)&__keysc_configure, - .state_size = sizeof(struct keysc_ctx) + .state_size = sizeof(struct keysc_ctx), + .flags = { + .KEYBOARD = 1, + .SHARED = 0, + .UNUSED = 0, + }, + .module_data = &(struct keyboard_drv_interface){ + .keycache_init = &sh7305_keycache_init, + .keycache_keydown = &sh7305_keycache_keydown, + .keycache_event_wait = &sh7305_keycache_event_wait, + .keycache_event_pop = &sh7305_keycache_event_pop, + .keycache_event_push = &sh7305_keycache_event_push, + .keycache_quit = &sh7305_keycache_quit, + } }; VHEX_DECLARE_DRIVER(03, drv_keysc); diff --git a/src/drivers/mpu/sh/sh7305/tmu/tmu.c b/src/drivers/mpu/sh/sh7305/tmu/tmu.c index e5d99a9..7a166e2 100644 --- a/src/drivers/mpu/sh/sh7305/tmu/tmu.c +++ b/src/drivers/mpu/sh/sh7305/tmu/tmu.c @@ -35,8 +35,20 @@ struct tmu_ctx { // Internal helpers //--- -/* conf(): Configure a fixed timer */ -static int conf(tid_t id, uint32_t delay, int clock, timer_call_t call) +uint8_t tmu_status[9] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* valid() : check if the id is valid */ +static int invalid(tid_t id) +{ + if (id < 0 || id >= 9) + return -1; + return tmu_status[id] == 0; +} + +/* conf(): Reserve a fixed timer */ +static tid_t reserve(tid_t id, uint32_t delay, int clock) { if(id < 3) { /* Refuse to setup timers that are already in use */ @@ -50,8 +62,8 @@ static int conf(tid_t id, uint32_t delay, int clock, timer_call_t call) T->TCR.TPSC = clock; set(T->TCR.UNF, 0); - /* Enable interrupt and count on rising edge (SH7705) */ - T->TCR.UNIE = 1; + /* Disable interrupt and count on rising edge (SH7705) */ + T->TCR.UNIE = 0; T->TCR.CKEG = 0; } else { etmu_t *T = &ETMU[id-3]; @@ -61,21 +73,38 @@ static int conf(tid_t id, uint32_t delay, int clock, timer_call_t call) set(T->TCR.UNF, 0); set(T->TCOR, delay); set(T->TCNT, delay); + T->TCR.UNIE = 0; + } + tmu_status[id] = 1; + return id; +} + +/* conf(): Configure a fixed timer */ +static tid_t conf(tid_t id, timer_call_t call) +{ + if(id < 3) { + /* Refuse to setup timers that are already in use */ + tmu_t *T = &TMU[id]; + + /* Enable interrupt and count on rising edge (SH7705) */ + T->TCR.UNIE = 1; + T->TCR.CKEG = 0; + } else { + etmu_t *T = &ETMU[id-3]; + + /* Enable interrupt */ T->TCR.UNIE = 1; } sh7305_tmu_callbacks[id] = call; - return (id); + return id; } -/* sh7305_tmu_control() - start or stop a timer +/* control() - start or stop a timer @id Timer ID to configure @state 0 to start the timer, 1 to stop it (nothing else!) */ -static int sh7305_tmu_control(tid_t id, int state) +static int control(tid_t id, int state) { - if (id < 0 || id >= 9) - return (-1); - if(id < 3) { *TSTR = (*TSTR | (1 << id)) ^ (state << id); } else { @@ -98,8 +127,8 @@ static int available(int id) return !T->TCR.UNIE && !T->TSTR; } -/* sh7305_tmu_delay() - compute a delay constant from a duration in seconds */ -static uint32_t sh7305_tmu_delay(int id, uint64_t delay_us, int clock) +/* compute_delay() - compute a delay constant from a duration in seconds */ +static uint32_t compute_delay(int id, uint64_t delay_us, int clock) { struct cpg_clock_frequency cpg_freq; uint64_t freq; @@ -130,13 +159,11 @@ static int stop_callback(void) // Public timer-API //--- -tid_t sh7305_tmu_configure(uint64_t delay, timer_call_t call) +/* sh7305_tmu_reserve() : reserve a timer */ +tid_t sh7305_tmu_reserve(uint64_t delay) { int clock = 0; - /* Default behavior for the callback */ - if(!call.function) call = TIMER_CALL(&stop_callback); - /* Find a matching timer, starting from the slowest timers with the smallest interrupt priorities all the way up to TMU0 */ for(int id = 8; id >= 0; id--) @@ -161,30 +188,45 @@ tid_t sh7305_tmu_configure(uint64_t delay, timer_call_t call) } /* Find the delay constant for that timer and clock */ - delay = sh7305_tmu_delay(id, delay, clock); + delay = compute_delay(id, delay, clock); - return conf(id, delay, clock, call); + return reserve(id, delay, clock); } return (-1); } +/* sh7305_tmu_configure() : configure timer */ +tid_t sh7305_tmu_configure(uint64_t delay, timer_call_t call) +{ + tid_t timer = sh7305_tmu_reserve(delay); + if (timer < 0) + return -1; + + if(call.function == NULL) + call = TIMER_CALL(&stop_callback); + + return conf(timer, call); +} + /* sh7305_tmu_start() - start a configured timer */ int sh7305_tmu_start(tid_t id) { - return sh7305_tmu_control(id, 0); + return control(id, 0); } /* sh7305_tmu_reload() - change a timer's delay constant for next interrupts */ int sh7305_tmu_reload(tid_t id, uint64_t delay) { - //FIXME - if (id < 0 || id >= 9) - return (-1); + if (invalid(id)) + return -1; if(id < 3) { - TMU[id].TCOR = delay; + tmu_t *T = &TMU[id]; + T->TCOR = compute_delay(id, delay, T->TCR.TPSC); + } else { - ETMU[id-3].TCOR = delay; + etmu_t *T = &ETMU[id - 3]; + T->TCOR = compute_delay(id, delay, 0); } return (0); } @@ -192,14 +234,14 @@ int sh7305_tmu_reload(tid_t id, uint64_t delay) /* sh7305_tmu_pause() - stop a running timer */ int sh7305_tmu_pause(tid_t id) { - return sh7305_tmu_control(id, 1); + return control(id, 1); } /* sh7305_tmu_stop() - stop and free a timer */ int sh7305_tmu_stop(tid_t id) { - if (id < 0 || id >= 9) - return (-1); + if (invalid(id)) + return -1; /* Stop the timer and disable UNIE to indicate that it's free */ sh7305_tmu_pause(id); @@ -218,14 +260,14 @@ int sh7305_tmu_stop(tid_t id) set(T->TCNT, 0xffffffff); set(T->TCR.UNF, 0); } - return (0); + return 0; } /* sh7305_tmu_wait(): Wait for a timer to stop */ int sh7305_tmu_wait(tid_t id) { - if (id < 0 || id >= 9) - return (-1); + if (invalid(id) != 0) + return -1; if(id < 3) { tmu_t *T = &TMU[id]; @@ -240,8 +282,8 @@ int sh7305_tmu_wait(tid_t id) /* sh7305_tmu_spinwait(): Start a timer and actively wait for UNF */ int sh7305_tmu_spinwait(tid_t id) { - if (id < 0 || id >= 9) - return (-1); + if (invalid(id)) + return -1; if(id < 3) { tmu_t *T = &TMU[id]; @@ -254,9 +296,32 @@ int sh7305_tmu_spinwait(tid_t id) sh7305_tmu_start(id); while(!T->TCR.UNF) {} } - return (0); + return 0; } +/* sh7305_tmu_get_tcnt() : return the timer TCNT register address */ +volatile uint32_t *sh7305_tmu_get_tcnt(tid_t id) +{ + if (invalid(id)) + return NULL; + + if (id < 3) + return &TMU[id].TCNT; + return &ETMU[id - 3].TCNT; +} + +/* sh7305_tmu_set_tcor() : set the timer TCOR value */ +void sh7305_tmu_set_tcor(tid_t id, uint32_t value) +{ + if (invalid(id)) + return; + + if (id < 3) { + TMU[id].TCOR = value; + } else { + set(ETMU[id - 3].TCOR, value); + } +} //--- @@ -283,7 +348,7 @@ int sh7305_tmu_prof_init(timer_prof_t *prof) TMU[t].TCNT = 0xffffffff; TMU[t].TCR.TPSC = TIMER_Pphi_4; set(TMU[t].TCR.UNF, 0); - TMU[t].TCR.UNIE = 1; + TMU[t].TCR.UNIE = 0; TMU[t].TCR.CKEG = 0; *TSTR = *TSTR | (1 << t); @@ -337,6 +402,7 @@ uint32_t sh7305_tmu_prof_time(timer_prof_t *prof) return ((uint64_t)prof->elapsed * 4 * 1000000) / cpg_freq.Pphi_f; } +/* sh7305_tmu_prof_quit() : uninit the profoling object */ int sh7305_tmu_prof_quit(timer_prof_t *prof) { (void)prof; @@ -491,6 +557,7 @@ struct vhex_driver drv_tmu = { }, .module_data = &(struct timer_drv_interface){ /* timer API */ + .timer_reserve = &sh7305_tmu_reserve, .timer_configure = &sh7305_tmu_configure, .timer_start = &sh7305_tmu_start, .timer_pause = &sh7305_tmu_pause, diff --git a/src/drivers/screen/R61524/r61524.c b/src/drivers/screen/R61524/r61524.c index 7d07e92..3a666a2 100644 --- a/src/drivers/screen/R61524/r61524.c +++ b/src/drivers/screen/R61524/r61524.c @@ -8,7 +8,7 @@ //--- /* r61524_frame_start() - prepar the screen and reset surfaces */ -int r61524_frame_start(dsurface_t *surface) +VALIGNED(4) int r61524_frame_start(dsurface_t *surface) { /* Set the windows size */ r61524_select(horizontal_ram_start); @@ -40,7 +40,7 @@ int r61524_frame_start(dsurface_t *surface) return (0); } -int r61524_frame_frag_next(dsurface_t *surface) +VALIGNED(4) int r61524_frame_frag_next(dsurface_t *surface) { surface->y1 += 10; if (surface->y1 >= 224) { @@ -54,7 +54,7 @@ int r61524_frame_frag_next(dsurface_t *surface) return (0); } -VWEAK int r61524_frame_frag_send(dsurface_t *surface) +VALIGNED(4) VWEAK int r61524_frame_frag_send(dsurface_t *surface) { uint16_t * restrict yram = surface->vram; int size = (surface->y1 == 220) ? 1584 : 3960; @@ -65,7 +65,7 @@ VWEAK int r61524_frame_frag_send(dsurface_t *surface) return (0); } -int r61524_frame_end(dsurface_t *surface) +VALIGNED(4) int r61524_frame_end(dsurface_t *surface) { (void)surface; return (0); diff --git a/src/modules/display/dclear.c b/src/modules/display/dclear.c index 1c5bc87..f701fb2 100644 --- a/src/modules/display/dclear.c +++ b/src/modules/display/dclear.c @@ -44,7 +44,7 @@ did_t dclear(int color) color = color & 0xffff; copti = (color << 16) | (color << 0); return dstack_add_action( - &DSTACK_CALL(&dclear_dstack, copti), + DSTACK_CALL(&dclear_dstack, copti), NULL, NULL ); diff --git a/src/modules/display/draw/dcircle.c b/src/modules/display/draw/dcircle.c index 4bd7e7d..7388b18 100644 --- a/src/modules/display/draw/dcircle.c +++ b/src/modules/display/draw/dcircle.c @@ -73,7 +73,7 @@ void dcircle_filled(int x, int y, size_t radius, int mode, int color) if (mode & DCIRCLE_BOTTOM) y -= (radius >> 1) + offset; dstack_add_action( - &DSTACK_CALL(&dcircle_filled_dstack, x, y, radius, color), + DSTACK_CALL(&dcircle_filled_dstack, x, y, radius, color), NULL, NULL ); diff --git a/src/modules/display/draw/dline.c b/src/modules/display/draw/dline.c index 950e3b3..b278b8f 100644 --- a/src/modules/display/draw/dline.c +++ b/src/modules/display/draw/dline.c @@ -188,7 +188,7 @@ void dline(int x1, int y1, int x2, int y2, int color) if(y1 == y2) { dstack_add_action( - &DSTACK_CALL(&dhline_dstack, y1, x1, x2, color), + DSTACK_CALL(&dhline_dstack, y1, x1, x2, color), NULL, NULL ); @@ -197,14 +197,14 @@ void dline(int x1, int y1, int x2, int y2, int color) if(x1 == x2) { dstack_add_action( - &DSTACK_CALL(&dvline_dstack, x1, y1, y2, color), + DSTACK_CALL(&dvline_dstack, x1, y1, y2, color), NULL, NULL ); return; } dstack_add_action( - &DSTACK_CALL(&dline_dstack, x1, y1, x2, y2, color), + DSTACK_CALL(&dline_dstack, x1, y1, x2, y2, color), NULL, NULL ); @@ -214,7 +214,7 @@ void dline(int x1, int y1, int x2, int y2, int color) void dhline(int y, int x1, int x2, int color) { dstack_add_action( - &DSTACK_CALL(&dhline_dstack, y, x1, x2, color), + DSTACK_CALL(&dhline_dstack, y, x1, x2, color), NULL, NULL ); @@ -224,7 +224,7 @@ void dhline(int y, int x1, int x2, int color) void dvline(int x, int y1, int y2, int color) { dstack_add_action( - &DSTACK_CALL(&dvline_dstack, x, y1, y2, color), + DSTACK_CALL(&dvline_dstack, x, y1, y2, color), NULL, NULL ); diff --git a/src/modules/display/draw/dpixel.c b/src/modules/display/draw/dpixel.c index 4cc3076..c673ff2 100644 --- a/src/modules/display/draw/dpixel.c +++ b/src/modules/display/draw/dpixel.c @@ -52,7 +52,7 @@ void dpixel_dstack(dsurface_t *surface, uint32_t *arg) void dpixel(int x, int y, int color) { dstack_add_action( - &DSTACK_CALL(&dpixel_dstack, x, y, color), + DSTACK_CALL(&dpixel_dstack, x, y, color), NULL, NULL ); diff --git a/src/modules/display/dstack.c b/src/modules/display/dstack.c index de70f13..28c0075 100644 --- a/src/modules/display/dstack.c +++ b/src/modules/display/dstack.c @@ -184,7 +184,7 @@ void dstack_render(void) action[i].shader.table[j].routine( &surface, action[i].call.args, - action[i].shader.table[i].args + action[i].shader.table[j].args ); } } diff --git a/src/modules/display/font/render.c b/src/modules/display/font/render.c index 52b76b1..5c2ac79 100644 --- a/src/modules/display/font/render.c +++ b/src/modules/display/font/render.c @@ -96,7 +96,7 @@ void dfont_char_dstack(dsurface_t *surface, uint32_t *arg) void dfont_char(uint32_t n, int x, int y, int fg, int bg) { dstack_add_action( - &DSTACK_CALL( + DSTACK_CALL( &dfont_char_dstack, n, x, y, diff --git a/src/modules/display/image/render/dimage.c b/src/modules/display/image/render/dimage.c index 038f86c..b90d2ea 100644 --- a/src/modules/display/image/render/dimage.c +++ b/src/modules/display/image/render/dimage.c @@ -12,21 +12,6 @@ void dimage_render(dsurface_t *surface, image_t const *img, int x, int y) dsubimage_render(surface, img, x, y, 0, 0, img->width, img->height); } -//--- -// Dstack API (internal) -//--- - -/* dimage_dstack(): dstack wrapper primitive */ -static void dimage_dstack(dsurface_t *surface, uint32_t *args) -{ - dimage_render( - surface, - (image_t*)(uintptr_t)args[0], - (int)args[1], - (int)args[2] - ); -} - //--- // User-level API //--- @@ -34,12 +19,19 @@ static void dimage_dstack(dsurface_t *surface, uint32_t *args) /* dimage(): Render a full image */ did_t dimage(image_t const *image, int x, int y, int mode) { + extern void dsubimage_dstack(dsurface_t *surface, uint32_t *args); + if (mode & DIMAGE_CENTER) { x -= image->width >> 1; } if (mode & DIMAGE_RIGHT) { x -= image->width; } if (mode & DIMAGE_MIDDLE) { y -= image->height >> 1; } if (mode & DIMAGE_BOTTOM) { y -= image->height; } return dstack_add_action( - &DSTACK_CALL(&dimage_dstack, (uintptr_t)image, x, y), + DSTACK_CALL( + &dsubimage_dstack, + (uintptr_t)image, + x, y, + 0, 0, image->width, image->height + ), NULL, NULL ); diff --git a/src/modules/display/image/render/dsubimage.c b/src/modules/display/image/render/dsubimage.c index 9c39023..61df626 100644 --- a/src/modules/display/image/render/dsubimage.c +++ b/src/modules/display/image/render/dsubimage.c @@ -64,8 +64,10 @@ static void dsubimage_alpha_render(image_t const *image, struct imgbox *box) // Kernel-level API //--- -/* dsubimage_render() : draw a subimage in the surface */ -void dsubimage_render( + +/* dsubimage_render_box() : generate box information */ +int dsubimage_render_box( + struct imgbox *imgbox, dsurface_t *surface, image_t const *image, int x, int y, @@ -75,6 +77,9 @@ void dsubimage_render( int vxs; int vys; + //TODO: precalculate image information + (void)image; + /* precalculate culling information */ if (x < 0) { left -= x; @@ -89,14 +94,14 @@ void dsubimage_render( /* check error */ if (top < 0 || left < 0 || width < 0 || height < 0) - return; + return -1; /* check culling */ if (y >= surface->y2 || y + height < surface->y1 || x >= surface->x2 || x + width < surface->x1) { - return; + return -2; } /* precalculate geometry information (both image and vram) */ @@ -119,26 +124,38 @@ void dsubimage_render( vram = surface->vram; /* prepare box request */ - struct imgbox imgbox = { - .img = { - .y = { - .start = top, - .end = top + height - }, - .x = { - .start = left, - .end = left + width - } - }, - .surface = { - .vram = &vram[(surface->width * vys) + vxs], - .voff = surface->width - } - }; + imgbox->img.y.start = top; + imgbox->img.y.end = top + height; + imgbox->img.x.start = left; + imgbox->img.x.end = left + width; + imgbox->surface.vram = &vram[(surface->width * vys) + vxs], + imgbox->surface.voff = surface->width; + return 0; +} + +/* dsubimage_render() : draw a subimage in the surface */ +void dsubimage_render( + dsurface_t *surface, + image_t const *image, + int x, int y, + int left, int top, int width, int height +) { + struct imgbox imgbox; + int ret; + + ret = dsubimage_render_box( + &imgbox, + surface, + image, + x, y, + left, top, width, height + ); + if (ret != 0) + return; #if 0 static int test = 0; - if (++test >= 12) { + if (++test >= 0) { dclear(C_WHITE); dprint(0, 0, C_BLACK, "surface.x1 = %d\n" @@ -220,7 +237,7 @@ did_t dsubimage( int left, int top, int width, int height ) { return dstack_add_action( - &DSTACK_CALL( + DSTACK_CALL( &dsubimage_dstack, (uintptr_t)image, x, y, diff --git a/src/modules/display/image/shader/shadow.c b/src/modules/display/image/shader/shadow.c index 2c89444..9844f6e 100644 --- a/src/modules/display/image/shader/shadow.c +++ b/src/modules/display/image/shader/shadow.c @@ -9,33 +9,94 @@ /* dimg_shadow_default_render() : add shadow on image with no alpha */ static void dimg_shadow_default_render( - dsurface_t *surface, - image_t *img, - uint32_t *draw, - uint32_t *shader + image_t *image, + struct imgbox *box, + int xoff, + int yoff ) { - (void)surface; - (void)img; - (void)draw; - (void)shader; + (void)image; + (void)box; + (void)xoff; + (void)yoff; } /* dimg_shadow_alpha_render() : add shadow on image with no alpha */ static void dimg_shadow_alpha_render( + image_t *image, + struct imgbox *box, + int xoff, + int yoff +) { + uint16_t *vram; + uint16_t *data; + uint16_t pixel; + uint16_t alpha; + int voff; + int xcnt; + int c; + int msk; + int pxl; + + (void)xoff; + (void)yoff; + + voff = box->surface.voff; + vram = box->surface.vram; + alpha = image_alpha(image->format); + + //TODO: optimisation if xoff == 0 + //TODO: optimisation if yoff == 0 + + for (int iy = box->img.y.start; iy < box->img.y.end; ++iy) { + data = vram; + c = 0; + xcnt = 0; + for (int ix = box->img.x.start; ix < box->img.x.end; ++ix) { + pixel = image_get_pixel(image, ix, iy); + if (pixel != alpha) { + if (xcnt < 4) { + pxl = data[c]; + msk = pxl; + pxl = ((msk & 0xF81F) >> 1) & 0xF81F; + pxl |= ((msk & 0x07E0) >> 1) & 0x07E0; + data[c] = pxl; + } + } else { + xcnt = 0; + } + c += 1; + xcnt += 1; + } + vram = &vram[voff]; + } +} + + +//--- +// Dstack-level API +//--- + +#include + +/* dimage_shader_shadow() : add shadows in any image rendered */ +static void dimage_shader_shadow_dstack( dsurface_t *surface, - image_t *img, uint32_t *draw, uint32_t *shader ) { - (void)img; - (void)surface; - (void)draw; - (void)shader; - -#if 0 struct imgbox imgbox; - dsubimage_render_box( + image_t *image; + int xoff; + int yoff; + int ret; + + image = (image_t*)(uintptr_t)draw[0]; + xoff = (int)shader[0]; + yoff = (int)shader[1]; + + ret = dsubimage_render_box( &imgbox, + surface, image, (int)draw[1] + xoff, (int)draw[2] + yoff, @@ -44,31 +105,62 @@ static void dimg_shadow_alpha_render( (int)draw[5], (int)draw[6] ); + if (ret != 0) + return; + +#if 0 + static int test = 0; + if (++test >= 2) { + dclear(C_WHITE); + dprint(0, 0, C_BLACK, + "surface.x1 = %d\n" + "surface.x2 = %d\n" + "surface.y1 = %d\n" + "surface.y2 = %d\n" + "surface.width = %d\n" + "surface.height = %d\n" + "\n" + "img.y.start = %d\n" + "img.y.end = %d\n" + "img.x.start = %d\n" + "img.x.end = %d\n" + "\n" + "image.x = %d\n" + "image.y = %d\n" + "image.width = %d\n" + "image.heigt = %d\n" + "image.ptr = %p\n", + surface->x1, + surface->x2, + surface->y1, + surface->y2, + surface->width, + surface->height, + imgbox.img.y.start, + imgbox.img.y.end, + imgbox.img.x.start, + imgbox.img.x.end, + xoff, + yoff, + (int)draw[3], + (int)draw[4], + (int)draw[5], + (int)draw[6], + (image_t*)(uintptr_t)draw[0] + ); + dupdate(); + while(1) { __asm__ volatile ("sleep"); } + } else { + return; + } #endif -} - - -//--- -// Dstack-level API -//--- - -/* dimage_shader_shadow() : add shadows in any image rendered */ -static void dimage_shader_shadow_dstack( - dsurface_t *surface, - uint32_t *draw, - uint32_t *shader -) { - image_t *image; - - image = (image_t*)(uintptr_t)draw[0]; - /* send drawing request in the approriate optimized function */ if (IMAGE_IS_ALPHA(image->format)) { - dimg_shadow_alpha_render(surface, image, draw, shader); + dimg_shadow_alpha_render(image, &imgbox, xoff, yoff); return; } - dimg_shadow_default_render(surface, image, draw, shader); + dimg_shadow_default_render(image, &imgbox, xoff, yoff); } //--- diff --git a/src/modules/display/text/render.c b/src/modules/display/text/render.c index de283fc..0ce4c0e 100644 --- a/src/modules/display/text/render.c +++ b/src/modules/display/text/render.c @@ -181,7 +181,7 @@ did_t dtext_opt( /* request draw call */ return dstack_add_action( - &DSTACK_CALL( + DSTACK_CALL( &dtext_dstack, x, y, x + width, y + height, fg, bg, diff --git a/src/modules/keyboard/getkey.c b/src/modules/keyboard/getkey.c new file mode 100644 index 0000000..3d351fd --- /dev/null +++ b/src/modules/keyboard/getkey.c @@ -0,0 +1,35 @@ +#if 0 +//FIXME : driver-specific +//FIXME : redirect custom mode for getkey_opt +#include +#include + +/* getkey(): Wait for a key press */ +key_event_t getkey(void) +{ + return getkey_opt(GETKEY_DEFAULT, NULL); +} + +/* getkey_opt(): Enhanced getkey() */ +key_event_t getkey_opt(int options, volatile int *timeout) +{ + key_event_t e; + + while (1) + { + keycache_event_pop(&e); + if(e.type == KEYEV_NONE) { + keycache_event_wait(timeout); + continue; + } + + (void)options; + //TODO: handle modifier + //TODO: handle repeat + //TODO: handle feature + //TODO: handle timeout + + return e; + } +} +#endif diff --git a/src/modules/keyboard/keycache.c b/src/modules/keyboard/keycache.c index 550ae07..26b29d3 100644 --- a/src/modules/keyboard/keycache.c +++ b/src/modules/keyboard/keycache.c @@ -1,104 +1,80 @@ #include +#include #include +#include +#include + +#include +#include + /* Internal cache, used like chained list. @note: The KEYSC have 6 key data 16-bits registers this is why we used 6 * 16 = 96 cache slots. */ -struct keycache_s keycache[96]; -struct keycache_s *keylist; +struct { + struct keyboard_drv_interface driver; +} keyboard_info; + //--- -// Private functions -//--- - -/* keycache_alloc() : Try to alloc a new keycache node */ -static struct keycache_s *keycache_alloc(int keycode, int keyframe) -{ - void *node; - - cpu_atomic_start(); - - node = NULL; - for (int i = 0; i < 96 ; ++i) { - if (keycache[i].keycode == KEY_UNUSED) { - keycache[i].keycode = keycode; - keycache[i].keyframe = keyframe; - keycache[i].repeated = 0; - node = &keycache[i]; - break; - } - } - - cpu_atomic_end(); - return (node); -} - -//--- -// Secret entries +// Module init //--- /* keycache_init() : keycache constructor */ void keycache_init(void) { - for (int i = 0; i < 96 ; ++i) { - keycache[i].keycode = KEY_UNUSED; - keycache[i].next = NULL; + struct vhex_driver *driver = vhex_driver_table(); + for (int i = 0; i < vhex_driver_count(); ++i) { + if (driver[i].flags.KEYBOARD) { + memcpy( + &keyboard_info.driver, + driver[i].module_data, + sizeof(struct keyboard_drv_interface) + ); + break; + } } - keylist = NULL; + if (keyboard_info.driver.keycache_init != NULL) + keyboard_info.driver.keycache_init(); +} + +/* keycache_init() : keycache descructor */ +void keycache_quit(void) +{ + if (keyboard_info.driver.keycache_quit != NULL) + keyboard_info.driver.keycache_quit(); } //--- // Public API //--- -/* keycache_update() : Add / update key code node */ -void keycache_update(int row, int column, uint8_t keyframe) +/* keycache_keydown() : check the current key state */ +int keycache_keydown(key_t key) { - struct keycache_s *node; - uint8_t keycode; - - keycode = KEYCODE_GEN(row, column); - - cpu_atomic_start(); - - node = keylist; - while (node != NULL) { - if (node->keycode == keycode) { - node->keyframe = keyframe; - break; - } - node = node->next; - } - - if (node == NULL) { - node = keycache_alloc(keycode, keyframe); - if (node != NULL) { - node->next = keylist; - keylist = node; - } - } - - cpu_atomic_end(); + if (keyboard_info.driver.keycache_keydown != NULL) + return keyboard_info.driver.keycache_keydown(key); + return -1; } -/* keycache_clean() : Remove dirty node */ -void keycache_clean(int keyframe) +/* keycache_event_wait() : wait until the next event or the timeout != 0 */ +void keycache_event_wait(key_event_t *event, volatile int *timeout) { - struct keycache_s **current_node; - - cpu_atomic_start(); - - current_node = &keylist; - while (*current_node != NULL) { - if ((*current_node)->keyframe != keyframe) { - (*current_node)->keycode = KEY_UNUSED; - *current_node = (*current_node)->next; - continue; - } - (*current_node)->repeated = (*current_node)->repeated + 1; - current_node = &(*current_node)->next; - } - - cpu_atomic_end(); + if (keyboard_info.driver.keycache_event_wait != NULL) + keyboard_info.driver.keycache_event_wait(event, timeout); +} + +/* keycache_event_pop() : pop the first key event in the cache */ +void keycache_event_pop(key_event_t * event) +{ + if (keyboard_info.driver.keycache_event_pop != NULL) + keyboard_info.driver.keycache_event_pop(event); +} + +/* keycache_event_push() : push a key event in the cache */ +void keycache_event_push(key_event_t * event) +{ + if (keyboard_info.driver.keycache_event_push != NULL) + keyboard_info.driver.keycache_event_push(event); } diff --git a/src/modules/keyboard/keydown.c b/src/modules/keyboard/keydown.c new file mode 100644 index 0000000..f20c6af --- /dev/null +++ b/src/modules/keyboard/keydown.c @@ -0,0 +1,48 @@ +#include +#include +#include + + +/* keydown(): Current key state */ +int keydown(key_t key) +{ + return keycache_keydown(key); +} + +/* keydown_all(): Check a set of keys for simultaneous input */ +int keydown_all(key_t key1, ...) +{ + int key; + va_list ap; + + va_start(ap, key1); + + key = key1; + do { + if (keycache_keydown(key) == 0) + return 0; + key = va_arg(ap, key_t); + } while (key != KEY_NONE); + + va_end(ap); + return 1; +} + +/* keydown_any(): Check a set of keys for any input */ +int keydown_any(key_t key1, ...) +{ + int key; + va_list ap; + + va_start(ap, key1); + + key = key1; + do { + if (keycache_keydown(key) != 0) + return 1; + key = va_arg(ap, key_t); + } while (key != KEY_NONE); + + va_end(ap); + return 0; +} diff --git a/src/modules/keyboard/keyvent.c b/src/modules/keyboard/keyvent.c new file mode 100644 index 0000000..7ad0445 --- /dev/null +++ b/src/modules/keyboard/keyvent.c @@ -0,0 +1,32 @@ +#include +#include + +/* keyvent_poll(): Poll the next keyboard event */ +key_event_t keyvent_poll(void) +{ + key_event_t e; + + keycache_event_pop(&e); + return e; +} + +/* waitevent(): Wait for the next keyboard event */ +key_event_t keyvent_wait(volatile int *timeout) +{ + key_event_t e; + + keycache_event_wait(&e, timeout); + return e; +} + +/* clearevents(): Clear all events waiting in the queue */ +void keyvent_clear(void) +{ + key_event_t e; + + while (1) { + e = keyvent_poll(); + if (e.type == KEYEV_NONE) + break; + } +} diff --git a/src/modules/keyboard/wait_event.c b/src/modules/keyboard/wait_event.c deleted file mode 100644 index e9c63f0..0000000 --- a/src/modules/keyboard/wait_event.c +++ /dev/null @@ -1,43 +0,0 @@ -#if 0 -#include -#include - -/*keyboard_wait_event() - Wait keys events (press or release) */ -void keyboard_wait_event(keyscan_t *list) -{ - extern volatile uint8_t keylist_isUpdate; - extern struct keycache_s *keylist; - struct keycache_s *keynode; - int i; - - // Wait key list update. - // @note : each tim the user press or relase key(s) - // the hardware driver will set the "keylist_isUpdate" to 1. - // TODO: schedule !! - while (keylist_isUpdate == 0) - { - __asm__ volatile ("sleep"); - } - - // Start atomic operations - atomic_start(); - - // Dump all keys - i = 0; - keynode = keylist; - while (keynode != NULL) - { - list[i].counter = keynode->counter; - list[i].keycode = keynode->keycode; - keynode = keynode->next; - i = i + 1; - } - list[i].keycode = KEY_UNUSED; - - // Indicate that the key buffer has been readed - keylist_isUpdate = 0; - - // Stop atomic operations - atomic_stop(); -} -#endif diff --git a/src/modules/timer/timer.c b/src/modules/timer/timer.c index 9439334..f8641a9 100644 --- a/src/modules/timer/timer.c +++ b/src/modules/timer/timer.c @@ -15,6 +15,14 @@ struct { // user-level timer API //--- +/* timer_reserve(): Reserve and configure a timer */ +tid_t timer_reserve(uint64_t delay_us) +{ + if (timer_info.driver.timer_reserve != NULL) + return (timer_info.driver.timer_reserve(delay_us)); + return (-1); +} + /* timer_configure(): Reserve and configure a timer */ tid_t timer_configure(uint64_t delay_us, timer_call_t callback) {