VxKernel 0.6.0-13 : Add keyboard API + update timer API
@add <> include/vhex/driver/mpu/sh/sh7305/keysc | add internal driver primitives <> include/vhex/driver/mpu/sh/sh7305/tmu | add internal driver primitives <> include/vhex/keyboard | add getkey* (high-level) API | add key event API | add key status API | add keycode information | add keyboard driver interface @update <> include/vhex/driver | add KEYBOARD driver flags <> include/vhex/keyboard | isolate each part of the keyboard module | link the keycache part with the driver-provided keycache information <> src/drivers/mpu/sh/sh7305/keysc | use the new keycache API (high-level interrupt handler) | update keycache API | link the new API in the driver device <> src/drivers/mpu/sh/sh7305/tmu | add timer reservation (WIP) | use a "reservation" cache to known which timer is free instead of hardware | rename internal functions <> src/module/display | Now, by default, DSTACK_CALL() create a pointer on a dstack_call_t | use dsubimage dstack primitive in dimage() @fix <> board/fxcg50/fxcg50.ld | remove the IL-memory and allow only the X-memory area. This because the bootloader uses the IL-memory for DMA transfer and other "low-level" routine used by Gint. Moreover, I originally try to move each "display-driver" in this place, but after some profiling and tests, the dclear()/dupdate() combo went from 9155us up to 33250us (for many reason). So, I keep this area free, but I moved-back from RAM display routines. <> board/fxcg50/initialize | remove "section" copy. This role has been delegated to the bootload (vxBoot) because, in the final ELF file generated by GCC, many relocalization information for the IL/X memory has been set and the bootloader cannot performs general relocalization. So, all "special section/memory" displacement has been moved in the bootloader and we don't have to worrying about the section copy. <> src/drivers/mpu/sh/sh7305/tmu | fix delay calculation in timer reload primitive | disable interruption for profiling timer <> src/module/dislay/ | fix shader index used during the dstack_render() | fix many errors in dimage() shadow render (WIP)
This commit is contained in:
parent
c966807cd7
commit
752757e0ef
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -10,15 +10,10 @@
|
|||
#include <stdlib.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
|
||||
|
||||
/* 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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ } \
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -73,4 +73,31 @@ struct __sh7305_keysc_s
|
|||
|
||||
#define SH7305_KEYSC (*(volatile struct __sh7305_keysc_s *)0xa44b0000)
|
||||
|
||||
//---
|
||||
// Internal API
|
||||
//---
|
||||
|
||||
#include <vhex/keyboard.h>
|
||||
|
||||
/* 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__ */
|
||||
|
|
|
@ -80,6 +80,65 @@ typedef volatile etmu_t sh7305_etmu_t[6];
|
|||
#define SH7305_ETMU (*(sh7305_etmu_t *)0xa44d0030)
|
||||
|
||||
|
||||
//---
|
||||
// internal API
|
||||
//---
|
||||
|
||||
#include <vhex/timer.h>
|
||||
|
||||
/* 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__ */
|
||||
|
|
|
@ -1,98 +1,5 @@
|
|||
#ifndef __KERNEL_DEVICES_KEYBOARD_H__
|
||||
# define __KERNEL_DEVICES_KEYBOARD_H__
|
||||
|
||||
#include <vhex/defs/types.h>
|
||||
|
||||
|
||||
|
||||
/* 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 <vhex/keyboard/keycode.h>
|
||||
#include <vhex/keyboard/keydown.h>
|
||||
#include <vhex/keyboard/keyvent.h>
|
||||
#include <vhex/keyboard/getkey.h>
|
||||
#include <vhex/keyboard/time.h>
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
#ifndef __VHEX_KEYBOARD_GETKEY__
|
||||
# define __VHEX_KEYBOARD_GETKEY__
|
||||
|
||||
#include <vhex/keyboard/types.h>
|
||||
|
||||
//---
|
||||
// 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__ */
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef __VHEX_KEYBOARD_INTERFACE__
|
||||
# define __VHEX_KEYBOARD_INTERFACE__
|
||||
|
||||
#include <vhex/keyboard/types.h>
|
||||
|
||||
/* 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__ */
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef __VHEX_KEYBOARD_KEYCACHE__
|
||||
# define __VHEX_KEYBOARD_KEYCACHE__
|
||||
|
||||
#include <vhex/keyboard/types.h>
|
||||
|
||||
/* 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__ */
|
|
@ -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__ */
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef __VHEX_KEYBOARD_KEYDOWN__
|
||||
# define __VHEX_KEYBOARD_KEYDOWN__
|
||||
|
||||
#include <vhex/keyboard/types.h>
|
||||
|
||||
//---
|
||||
// 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__ */
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef __VHEX_KEYBOARD_KEYVENT__
|
||||
# define __VHEX_KEYBOARD_KEYVENT__
|
||||
|
||||
#include <vhex/keyboard/types.h>
|
||||
|
||||
//---
|
||||
// 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__ */
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef __VHEX_KEYBOARD_TIME__
|
||||
# define __VHEX_KEYBOARD_TIME__
|
||||
|
||||
#include <vhex/keyboard/types.h>
|
||||
|
||||
//---
|
||||
// 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__ */
|
|
@ -0,0 +1,60 @@
|
|||
#ifndef __VHEX_KEYBOARD_TYPES__
|
||||
# define __VHEX_KEYBOARD_TYPES__
|
||||
|
||||
#include <vhex/defs/types.h>
|
||||
#include <vhex/defs/attributes.h>
|
||||
|
||||
#include <vhex/keyboard/keycode.h>
|
||||
|
||||
/* 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__ */
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -2,16 +2,15 @@
|
|||
#include <vhex/driver/mpu/sh/sh7305/keysc.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/intc.h>
|
||||
|
||||
/* 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;
|
||||
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
#include <vhex/driver/mpu/sh/sh7305/keysc.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/tmu.h>
|
||||
#include <vhex/keyboard.h>
|
||||
#include <vhex/timer.h>
|
||||
#include <vhex/driver/cpu.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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();
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#include <vhex/driver/mpu/sh/sh7305/keysc.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/intc.h>
|
||||
#include <vhex/keyboard/interface.h>
|
||||
#include <vhex/driver.h>
|
||||
|
||||
/* 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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 <vhex/display.h>
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
//---
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
#if 0
|
||||
//FIXME : driver-specific
|
||||
//FIXME : redirect custom mode for getkey_opt
|
||||
#include <vhex/keyboard.h>
|
||||
#include <vhex/keyboard/keycache.h>
|
||||
|
||||
/* 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
|
|
@ -1,104 +1,80 @@
|
|||
#include <vhex/keyboard.h>
|
||||
#include <vhex/keyboard/interface.h>
|
||||
#include <vhex/driver/cpu.h>
|
||||
#include <vhex/timer.h>
|
||||
#include <vhex/driver.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
#include <vhex/keyboard.h>
|
||||
#include <vhex/keyboard/keycache.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
/* 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;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#include <vhex/keyboard/keyvent.h>
|
||||
#include <vhex/keyboard/keycache.h>
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
#if 0
|
||||
#include <kernel/drivers/keyboard.h>
|
||||
#include <kernel/util/atomic.h>
|
||||
|
||||
/*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
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue