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:
Yann MAGNIN 2022-06-24 15:33:36 +02:00
parent c966807cd7
commit 752757e0ef
39 changed files with 1145 additions and 402 deletions

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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__ } \
}

View File

@ -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 */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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>

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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();
}

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -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
);

View File

@ -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
);

View File

@ -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
);

View File

@ -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
);

View File

@ -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
);
}
}

View File

@ -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,

View File

@ -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
);

View File

@ -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,

View File

@ -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);
}
//---

View File

@ -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,

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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)
{