VxKernel 0.6.0-18 : Add Vhex indirect call + prepare DMA driver
@add <> vhex/defs/call | add common `vhex_call_t` which allow indirect call invocation | add default helper macros to generate internal struct | add default helper macros to involve manually the vhex call <> vhex/dma | add DMA user-level API | add DMA user-level types | add DNA driver-level interface <> vhex/driver/mpu/sh/sh7305 | [dma] add hardware definition | [dma] prepare DMA driver definition (WIP) | [dma] add DMA driver declaration (WIP) | [dma] prepare DMA primitives (WIP) <> src/dma | wrap the DMA driver | expose the DMA user-level API | expose the DMA module @update <> board/fxcg50/fxcg50.ld | expose the two VRAM for the future frame render which use the triple buffering. For now, this method add ~347ko in the generated ELF, but it's a temporary. <> driver/mpu/sh/sh7305 | [intc] rename some kernel-level function | [intc] use the new vhex call mechanism instead of timer-specific indirect call | [intc] update the generic interrupt handler installation | [intc] isolate the generic interrupt handler | [rtc] use the new vhex call mechanism instead of rtc-specific indirect call | [keysc] use the new vhex call mechanism @fix <> src | [keyboard] fix key_t type definition | [keyboard] fix the driver priority | [timer] fix the driver priority
This commit is contained in:
parent
e8e63016d5
commit
7e01fb8444
|
@ -111,6 +111,21 @@ SECTIONS
|
|||
|
||||
/* dynamic BSS information (move me ?) */
|
||||
*(.dynbss)
|
||||
|
||||
/* Video RAM symbols
|
||||
|
||||
The Video RAM contains a full pixel sized frame for the
|
||||
screen. Its size is 396x224 and each pixel depth is 16bits,
|
||||
so (3996 * 224) * 2 = 177408
|
||||
|
||||
Thus, we use a double buffering methods to speed-up the
|
||||
render, this is why we define two VRAM */
|
||||
|
||||
_vhex_vram0 = ALIGN(32);
|
||||
. = _vhex_vram0 + 177408;
|
||||
_vhex_vram1 = ALIGN(32);
|
||||
. = _vhex_vram1 + 177408;
|
||||
|
||||
} > userram
|
||||
|
||||
/* Vhex VBR management geometry
|
||||
|
|
|
@ -7,7 +7,6 @@ void hypervisor_init(void)
|
|||
hyp_world_t vhex = hypervisor_world_new("vhex");
|
||||
|
||||
hypervisor_world_switch(casio, vhex);
|
||||
|
||||
}
|
||||
|
||||
/* hypervisor_quit() : quit the hypervisor module */
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
#ifndef __VHEX_DEFS_CALL__
|
||||
# define __VHEX_DEFS_CALL__
|
||||
|
||||
#include <vhex/defs/types.h>
|
||||
|
||||
/* vhex_call_arg_t: All types of arguments allowed in an indirect call
|
||||
|
||||
Because a function call cannot be easily pieced together, there are
|
||||
restrictions on what arguments can be passed. The following union lists all
|
||||
of the available types. Other types can be used if casted, mainly pointers;
|
||||
see the description of VHEX_CALL() for details. */
|
||||
typedef union {
|
||||
/* 32-bit integers */
|
||||
int i;
|
||||
unsigned int u;
|
||||
int32_t i32;
|
||||
uint32_t u32;
|
||||
/* 32-bit floating-point */
|
||||
float f;
|
||||
|
||||
/* Pointers to most common types, in all possible const/volatile
|
||||
qualifications */
|
||||
#define POINTER(type, name) \
|
||||
type *name; \
|
||||
type const *name ## _c; \
|
||||
type volatile *name ## _v; \
|
||||
type volatile const *name ## _cv;
|
||||
|
||||
POINTER(void, pv)
|
||||
POINTER(char, pc)
|
||||
POINTER(unsigned char, puc)
|
||||
POINTER(short, ps)
|
||||
POINTER(unsigned short, pus)
|
||||
POINTER(int, pi)
|
||||
POINTER(unsigned int, pui)
|
||||
POINTER(int8_t, pi8)
|
||||
POINTER(uint8_t, pu8)
|
||||
POINTER(int16_t, pi16)
|
||||
POINTER(uint16_t, pu16)
|
||||
POINTER(int32_t, pi32)
|
||||
POINTER(uint32_t, pu32)
|
||||
POINTER(int64_t, pi64)
|
||||
POINTER(uint64_t, pu64)
|
||||
POINTER(long long int, pll)
|
||||
POINTER(unsigned long long int, pull)
|
||||
POINTER(float, pf)
|
||||
POINTER(double, pd)
|
||||
|
||||
#undef POINTER
|
||||
} vhex_call_arg_t;
|
||||
|
||||
/* vhex_call_t: Indirect call with up to 4 register arguments */
|
||||
struct vhex_call {
|
||||
void *function;
|
||||
vhex_call_arg_t args[4];
|
||||
};
|
||||
typedef struct vhex_call vhex_call_t;
|
||||
|
||||
/* VHEX_CALL(): Build an callback from function and arguments */
|
||||
#define VHEX_CALL(fct, ...) \
|
||||
(vhex_call_t){ \
|
||||
.function = (void*)fct, \
|
||||
.args = { __VA_OPT__(VHEX_CALL_ARGS1(__VA_ARGS__)) } \
|
||||
}
|
||||
#define VHEX_CALL_ARGS1(a1, ...) \
|
||||
(vhex_call_arg_t)(a1), __VA_OPT__(VHEX_CALL_ARGS2(__VA_ARGS__))
|
||||
#define VHEX_CALL_ARGS2(a2, ...) \
|
||||
(vhex_call_arg_t)(a2), __VA_OPT__(VHEX_CALL_ARGS3(__VA_ARGS__))
|
||||
#define VHEX_CALL_ARGS3(a3, ...) \
|
||||
(vhex_call_arg_t)(a3), __VA_OPT__(VHEX_CALL_ARGS4(__VA_ARGS__))
|
||||
#define VHEX_CALL_ARGS4(a4, ...) \
|
||||
({ \
|
||||
__VA_OPT__( \
|
||||
_Static_assert( \
|
||||
0, \ \
|
||||
"VHEX_CALL: too many arguments (maximum 4)" \
|
||||
); \
|
||||
) \
|
||||
(vhex_call_arg_t)(a4); \
|
||||
})
|
||||
|
||||
/* VHEX_CALL_NULL: Empty function call */
|
||||
#define VHEX_CALL_NULL ((vhex_call_t){ .function = NULL, .args = {} })
|
||||
|
||||
/* vhex_call(): Perform an indirect call */
|
||||
static VINLINE int vhex_call(vhex_call_t callback)
|
||||
{
|
||||
return ((int(*)(int r4, int r5, int r6, int r7))callback.function)(
|
||||
callback.args[0].i,
|
||||
callback.args[1].i,
|
||||
callback.args[2].i,
|
||||
callback.args[3].i
|
||||
);
|
||||
}
|
||||
|
||||
#endif /* __VHEX_DEFS_CALL__ */
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef __VHEX_DMA__
|
||||
# define __VHEX_DMA__
|
||||
|
||||
#include <vhex/dma/types.h>
|
||||
|
||||
/* dma_memcpy() : memcpy-like using the DMA
|
||||
|
||||
As set in the short function description, we use the DMA transfert to perform
|
||||
the copy which allow us to do other things in parallele.
|
||||
|
||||
This function act like memcpy except that it will not return the destination
|
||||
address but the dma ID that should be used to wait the end of the transfert
|
||||
afterwards. */
|
||||
extern dma_id_t dma_memcpy(void * restrict dst, void * restrict src, size_t sz);
|
||||
|
||||
/* dma_memset() : memset using the DMA */
|
||||
extern dma_id_t dma_memset(void *dst, int c, size_t sz);
|
||||
|
||||
/* dma_wait() : wait dma transfert end (dma_memset or dma_memcpy) */
|
||||
extern int dma_wait(dma_id_t id);
|
||||
|
||||
#endif /* __VHEX_DMA__ */
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef __VHEX_DMA_INTERFACE__
|
||||
# define __VHEX_DMA_INTERFACE__
|
||||
|
||||
#include <vhex/dma/types.h>
|
||||
|
||||
struct dma_drv_interface
|
||||
{
|
||||
dma_id_t (*dma_memcpy)(void * restrict, void * restrict, size_t);
|
||||
dma_id_t (*dma_memset)(void * restrict, int, size_t);
|
||||
int (*dma_wait)(dma_id_t);
|
||||
};
|
||||
|
||||
#endif /* __VHEX_DMA_INTERFACE__ */
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef __VHEX_DMA_TYPES__
|
||||
# define __VHEX_DMA_TYPES__
|
||||
|
||||
#include <vhex/defs/types.h>
|
||||
|
||||
typedef uint32_t dma_id_t;
|
||||
|
||||
#endif /* __VHEX_DMA_TYPES__ */
|
|
@ -0,0 +1,100 @@
|
|||
#ifndef __VHEX_DRIVER_MPU_SH_SH7305_DMA__
|
||||
# define __VHEX_DRIVER_MPU_SH_SH7305_DMA__
|
||||
|
||||
#include <vhex/defs/attributes.h>
|
||||
#include <vhex/defs/types.h>
|
||||
|
||||
//---
|
||||
// SH7305 Direct Memory Access Controller. Refer to:
|
||||
// "Renesas SH7724 User's Manual: Hardware"
|
||||
// Section 16: "Direct Memory Access Controller (DMAC)"
|
||||
//
|
||||
// However, there is some (minor) differencies with the DMA controller of
|
||||
// the SH7305. Mainly, only the first channel have special features that
|
||||
// other don't.
|
||||
//---
|
||||
|
||||
/* sh7305_dma_channel_t - One of the main 6 channels of the DMA
|
||||
|
||||
Note that the many settings are only available on channels 0 to 3 (denoted
|
||||
by [0..3]) or on channels 0 (denoted by [0]).
|
||||
The documentation is apparently wrong about the placement is TS[3:2], the
|
||||
neighboring read-only bit must be swapped before TS[3:2]. */
|
||||
struct __sh7305_dma_channel
|
||||
{
|
||||
uint32_t SAR;
|
||||
uint32_t DAR;
|
||||
|
||||
/* Mind that the 8 upper bits should always be written as 0 */
|
||||
uint32_t TCR;
|
||||
|
||||
lword_union(CHCR,
|
||||
uint32_t :1;
|
||||
uint32_t LCKN :1; /* Bus Right Release Enable */
|
||||
uint32_t :2;
|
||||
|
||||
uint32_t RPT :3; /* Repeat setting [0..3] */
|
||||
uint32_t DA :1; /* DREQ Asynchronous [0] */
|
||||
|
||||
uint32_t DO :1; /* DMA Overrun [0] */
|
||||
uint32_t :1;
|
||||
uint32_t TS3 :1; /* Transfer Size (bit3) */
|
||||
uint32_t TS2 :1; /* Transfer Size (bit2) */
|
||||
|
||||
uint32_t HE :1; /* Half-End flag [0..3] */
|
||||
uint32_t HIE :1; /* Half-end Interrupt Enable [0..3] */
|
||||
uint32_t AM :1; /* Acknowledge mode [0] */
|
||||
uint32_t AL :1; /* Acknowledge level [0] */
|
||||
|
||||
uint32_t DM :2; /* Destination address Mode */
|
||||
uint32_t SM :2; /* Source address Mode */
|
||||
|
||||
uint32_t RS :4; /* Resource Select */
|
||||
|
||||
uint32_t DL :1; /* DREQ Level [0] */
|
||||
uint32_t DS :1; /* DREQ Source select[0] */
|
||||
uint32_t TB :1; /* Transfer Bus Mode */
|
||||
uint32_t TS1 :1; /* Transfer Size (bit1) */
|
||||
|
||||
uint32_t TS0 :1; /* Transfer Size (bit0) */
|
||||
uint32_t IE :1; /* Interrupt Enable */
|
||||
uint32_t TE :1; /* Transfer End flag */
|
||||
uint32_t DE :1; /* DMA Enable */
|
||||
);
|
||||
|
||||
} VPACKED(4);
|
||||
|
||||
/* sh7305_dma_t - DMA Controller */
|
||||
struct __sh7305_dma
|
||||
{
|
||||
struct __sh7305_dma_channel DMA0;
|
||||
struct __sh7305_dma_channel DMA1;
|
||||
struct __sh7305_dma_channel DMA2;
|
||||
struct __sh7305_dma_channel DMA3;
|
||||
|
||||
word_union(DMAOR,
|
||||
uint16_t CMS :4; /* Cycle steal Mode Select */
|
||||
|
||||
uint16_t :2;
|
||||
uint16_t PR :2; /* PRiority mode */
|
||||
|
||||
uint16_t :4;
|
||||
|
||||
uint16_t :1;
|
||||
uint16_t AE :1; /* Address Error flag */
|
||||
uint16_t NMIF :1; /* NMI Flag */
|
||||
uint16_t DME :1; /* DMA Master Enable */
|
||||
);
|
||||
pad(14);
|
||||
|
||||
struct __sh7305_dma_channel DMA4;
|
||||
struct __sh7305_dma_channel DMA5;
|
||||
|
||||
} VPACKED(4);
|
||||
|
||||
#define SH7305_DMA (*((volatile struct __sh7305_dma *)0xfe008020))
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* __VHEX_DRIVER_MPU_SH_SH7305_DMA__ */
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <vhex/defs/attributes.h>
|
||||
#include <vhex/defs/types.h>
|
||||
#include <vhex/defs/call.h>
|
||||
|
||||
/* sh7305_intc_ipc - Interrupt Priority Controller
|
||||
Some of the fields have been left unnamed because they correspond to SH7724
|
||||
|
@ -460,12 +461,12 @@ enum {
|
|||
//---
|
||||
|
||||
/* sh7305_intc_install_inth() : install interrupt gate */
|
||||
extern void *sh7305_intc_install_inth(int blockid, void *gate, size_t size);
|
||||
extern void *sh7305_intc_install_inth_gate(int blockid, void *gate, size_t size);
|
||||
|
||||
/* sh7305_intc_priority() : set the interrupt name priority */
|
||||
extern int sh7305_intc_priority(int intname, int level);
|
||||
|
||||
/* sh7305_intc_generic_handler() : install generic interrupt handler */
|
||||
extern void *sh7305_intc_generic_handler(int event_code, void *user_inth);
|
||||
extern void *sh7305_intc_install_inth_generic(int event_code, vhex_call_t cb);
|
||||
|
||||
#endif /* __VHEX_ARCH_SH7305_INTC__ */
|
||||
|
|
|
@ -77,7 +77,7 @@ struct __sh7305_keysc_s
|
|||
// Internal API
|
||||
//---
|
||||
|
||||
#include <vhex/keyboard.h>
|
||||
#include <vhex/keyboard/types.h>
|
||||
|
||||
/* sh7305_keycache_init() : initialise the keycache information */
|
||||
extern void sh7305_keycache_init(void);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <vhex/defs/attributes.h>
|
||||
#include <vhex/defs/types.h>
|
||||
#include <vhex/defs/call.h>
|
||||
|
||||
//---
|
||||
// Hybrid SH7705-SH7305 Real-Time Clock. Refer to:
|
||||
|
@ -98,19 +99,6 @@ enum
|
|||
RTC_NONE = 0,
|
||||
};
|
||||
|
||||
/* rtc_call: Indirect call with up to 4 register arguments */
|
||||
struct rtc_call {
|
||||
void *function;
|
||||
uint32_t args[4];
|
||||
};
|
||||
|
||||
/* RTC_CALL(): Build an callback from function and arguments */
|
||||
#define RTC_CALL(fct, ...) \
|
||||
(struct rtc_call){ \
|
||||
.function = (void*)fct, \
|
||||
.args = { __VA_ARGS__ } \
|
||||
}
|
||||
|
||||
/* rtc_periodic_enable(): Enable the periodic interrupt
|
||||
|
||||
This function sets up the periodic interrupt to invoke the provided callback
|
||||
|
@ -124,7 +112,7 @@ struct rtc_call {
|
|||
@frequency Periodic interrupt frequency
|
||||
@callback Function to call back at the specified frequency
|
||||
Returns true on success, false if the interrupt is already in use. */
|
||||
extern bool sh7305_rtc_periodic_enable(int frequency, struct rtc_call callback);
|
||||
extern bool sh7305_rtc_periodic_enable(int frequency, vhex_call_t callback);
|
||||
|
||||
/* rtc_periodic_disable(): Stop the periodic interrupt
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <vhex/defs/attributes.h>
|
||||
#include <vhex/defs/types.h>
|
||||
#include <vhex/defs/call.h>
|
||||
|
||||
/* Clock input
|
||||
|
||||
|
@ -92,7 +93,7 @@ typedef volatile etmu_t sh7305_etmu_t[6];
|
|||
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);
|
||||
extern tid_t sh7305_tmu_configure(uint64_t delay, vhex_call_t callback);
|
||||
|
||||
/* sh7305_tmu_start() - start a configured timer */
|
||||
extern int sh7305_tmu_start(tid_t id);
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
#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
|
||||
/* Define all keycode */
|
||||
enum
|
||||
{
|
||||
KEY_F1 = 0x41,
|
||||
KEY_F2 = 0x42,
|
||||
|
@ -70,6 +68,6 @@ typedef enum key_e
|
|||
|
||||
KEY_UNUSED = 0xff,
|
||||
KEY_NONE = 0xfe,
|
||||
} key_t;
|
||||
};
|
||||
|
||||
#endif /* __VHEX_KEYBOARD_KEYCODE__ */
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
# define __VHEX_KEYBOARD_KEYDOWN__
|
||||
|
||||
#include <vhex/keyboard/types.h>
|
||||
#include <vhex/keyboard/keycode.h>
|
||||
|
||||
//---
|
||||
// Key state functions
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
#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
|
||||
|
@ -56,5 +54,7 @@ enum
|
|||
KEYEV_REP_NEXT = 2,
|
||||
};
|
||||
|
||||
/* keyboard key */
|
||||
typedef int key_t;
|
||||
|
||||
#endif /* __VHEX_KEYBOARD_TYPES__ */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __VHEX_TIMER__
|
||||
#define __VHEX_TIMER__
|
||||
|
||||
#include <vhex/timer/call.h>
|
||||
#include <vhex/defs/call.h>
|
||||
#include <vhex/timer/types.h>
|
||||
|
||||
/* TIMER_DELAY_MS() : convert ms into us */
|
||||
|
@ -25,7 +25,7 @@ enum {
|
|||
the supplied callback function at the end of this delay. The callback
|
||||
function can then decide whether to leave the timer running (and be called
|
||||
again after the same delay) or stop the timer. */
|
||||
extern tid_t timer_configure(uint64_t delay_us, timer_call_t callback);
|
||||
extern tid_t timer_configure(uint64_t delay_us, vhex_call_t callback);
|
||||
|
||||
/* timer_reserve() : reserve a timer
|
||||
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef __VHEX_TIMER_CALL__
|
||||
# define __VHEX_TIMER_CALL__
|
||||
|
||||
#include <vhex/defs/types.h>
|
||||
|
||||
/* timer_call_t: Indirect call with up to 4 register arguments */
|
||||
struct timer_call {
|
||||
void *function;
|
||||
uint32_t args[4];
|
||||
};
|
||||
typedef struct timer_call timer_call_t;
|
||||
|
||||
/* TIMER_CALL(): Build an callback from function and arguments */
|
||||
#define TIMER_CALL(fct, ...) \
|
||||
(timer_call_t){ \
|
||||
.function = (void*)fct, \
|
||||
.args = { __VA_ARGS__ } \
|
||||
}
|
||||
|
||||
#endif /* __VHEX_TIMER_CALL__ */
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __VHEX_TIMER_INTERFACE__
|
||||
# define __VHEX_TIMER_INTERFACE__
|
||||
|
||||
#include <vhex/timer/call.h>
|
||||
#include <vhex/defs/call.h>
|
||||
#include <vhex/timer/types.h>
|
||||
#include <vhex/timer/fps.h>
|
||||
|
||||
|
@ -10,7 +10,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);
|
||||
tid_t (*timer_configure)(uint64_t delay_us, vhex_call_t callback);
|
||||
int (*timer_start)(tid_t timer);
|
||||
int (*timer_pause)(tid_t timer);
|
||||
int (*timer_stop)(tid_t timer);
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#include <vhex/dma/interface.h>
|
||||
#include <vhex/dma.h>
|
||||
#include <vhex/module.h>
|
||||
#include <vhex/driver.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* internal timer information */
|
||||
struct {
|
||||
struct dma_drv_interface driver;
|
||||
} dma_info;
|
||||
|
||||
/* __dma_init() : initialize the DMA module */
|
||||
static void __dma_init(void)
|
||||
{
|
||||
memset(&dma_info, 0x00, sizeof(dma_info));
|
||||
|
||||
struct vhex_driver *driver = vhex_driver_table();
|
||||
for (int i = 0; i < vhex_driver_count(); ++i) {
|
||||
if (driver[i].flags.DMA) {
|
||||
memcpy(
|
||||
&rtc_info.driver,
|
||||
driver[i].module_data,
|
||||
sizeof(struct dma_drv_interface)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* __dma_quit() : uninitialize the DMA module */
|
||||
static void __dma_quit(void)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
/* declare the timer module */
|
||||
|
||||
struct vhex_module mod_rtc = {
|
||||
.name = "DMA",
|
||||
.init = &__dma_init,
|
||||
.quit = &__dma_quit,
|
||||
};
|
||||
VHEX_DECLARE_MODULE(04, mod_dma);
|
|
@ -0,0 +1,15 @@
|
|||
#include <vhex/dma/interface.h>
|
||||
#include <vhex/dma.h>
|
||||
|
||||
/* internal driver information */
|
||||
extern struct {
|
||||
struct dma_drv_interface driver;
|
||||
} dma_info;
|
||||
|
||||
/* dma_memcpy() : memcpy using DMA */
|
||||
dma_id_t dma_memcpy(void * restrict dst, void * restrict src, size_t sz)
|
||||
{
|
||||
if (dma_info.driver.dma_memcpy != NULL)
|
||||
return dma_info.driver.dma_memcpy(dst, src, sz);
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#include <vhex/dma/interface.h>
|
||||
#include <vhex/dma.h>
|
||||
|
||||
/* internal driver information */
|
||||
extern struct {
|
||||
struct dma_drv_interface driver;
|
||||
} dma_info;
|
||||
|
||||
/* dma_memcpy() : memcpy using DMA */
|
||||
dma_id_t dma_memset(void * restrict dst, int c, size_t sz)
|
||||
{
|
||||
if (dma_info.driver.dma_memset != NULL)
|
||||
return dma_info.driver.dma_memset(dst, c, sz);
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#include <vhex/dma/interface.h>
|
||||
#include <vhex/dma.h>
|
||||
|
||||
/* internal driver information */
|
||||
extern struct {
|
||||
struct dma_drv_interface driver;
|
||||
} dma_info;
|
||||
|
||||
/* dma_memcpy() : memcpy using DMA */
|
||||
int dma_wait(dma_id_t id)
|
||||
{
|
||||
if (dma_info.driver.dma_wait != NULL)
|
||||
return dma_info.driver.dma_wait(id);
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
#include <vhex/driver/mpu/sh/sh7305/dma.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/intc.h>
|
||||
//#include <vhex/driver/mpu/sh/sh7305/power.h>
|
||||
#include <vhex/driver.h>
|
||||
#include <vhex/defs/call.h>
|
||||
|
||||
#define DMA SH7305_DMA
|
||||
//#define POWER SH7305_POWER
|
||||
|
||||
typedef volatile struct __sh7305_dma_channel channel_t;
|
||||
|
||||
//---
|
||||
// Driver public API
|
||||
//---
|
||||
|
||||
static channel_t *sh7305_dma_channel(int channel)
|
||||
{
|
||||
if (channel < 0 || channel >= 6)
|
||||
return NULL;
|
||||
return (channel_t *[6]){
|
||||
&DMA.DMA0, &DMA.DMA1, &DMA.DMA2,
|
||||
&DMA.DMA3, &DMA.DMA4, &DMA.DMA5,
|
||||
}[channel];
|
||||
}
|
||||
|
||||
static void sh7305_dma_spinwait(channel_t *ch)
|
||||
{
|
||||
(void)ch;
|
||||
}
|
||||
|
||||
//---
|
||||
// Kernel-level API
|
||||
//---
|
||||
|
||||
/* Interrupt handler for all finished DMA transfers */
|
||||
static void sh7305_dma_interrupt_transfer_ended(channel_t *ch)
|
||||
{
|
||||
(void)ch;
|
||||
}
|
||||
|
||||
//---
|
||||
// Declare driver
|
||||
//---
|
||||
|
||||
//FIXME: avoid manualy sync DMAOR with header o(x_x)o
|
||||
struct dma_ctx {
|
||||
channel_t ch[6];
|
||||
word_union(DMAOR,
|
||||
uint16_t CMS :4; /* Cycle steal Mode Select */
|
||||
|
||||
uint16_t :2;
|
||||
uint16_t PR :2; /* PRiority mode */
|
||||
|
||||
uint16_t :4;
|
||||
|
||||
uint16_t :1;
|
||||
uint16_t AE :1; /* Address Error flag */
|
||||
uint16_t NMIF :1; /* NMI Flag */
|
||||
uint16_t DME :1; /* DMA Master Enable */
|
||||
);
|
||||
};
|
||||
|
||||
/* __dma_configure() : configure the DMA */
|
||||
static void __dma_configure(struct dma_ctx *s)
|
||||
{
|
||||
extern void sh7305_dma_inth_te(void);
|
||||
extern void sh7305_dma_inth_ae(void);
|
||||
|
||||
int codes[] = { 0x800, 0x820, 0x840, 0x860, 0xb80, 0xba0 };
|
||||
|
||||
for(int i = 0; i < 6; i++)
|
||||
{
|
||||
sh7305_intc_install_inth_generic(
|
||||
codes[i],
|
||||
VHEX_CALL(
|
||||
sh7305_dma_interrupt_transfer_ended,
|
||||
(void*)sh7305_dma_channel(i)
|
||||
)
|
||||
);
|
||||
|
||||
s->ch[i].SAR = 0x00000000;
|
||||
s->ch[i].DAR = 0x00000000;
|
||||
s->ch[i].TCR = 0x00000000;
|
||||
|
||||
s->ch[i].CHCR.DE = 0;
|
||||
}
|
||||
|
||||
/* Configure the DMA operations
|
||||
<> select normal cycle steal mode
|
||||
<> select "normal" priority (CH0->CH1->CH2->...)
|
||||
<> clear address error flags
|
||||
<> clear NMIF flags
|
||||
<> enable the master switch */
|
||||
s->DMAOR.CMS = 0b0000;
|
||||
s->DMAOR.PR = 0b00;
|
||||
s->DMAOR.AE = 0;
|
||||
s->DMAOR.NMIF = 0;
|
||||
s->DMAOR.DME = 1;
|
||||
|
||||
/* Install Address Error interrupt gate */
|
||||
sh7305_intc_install_inth_gate(0xbc0, sh7305_dma_inth_ae, 32);
|
||||
|
||||
/* Set interrupt priority to 3, except for the channels that are
|
||||
used by the USB driver (channel 0) */
|
||||
sh7305_intc_priority(INTC_DMA_DEI0, 9);
|
||||
sh7305_intc_priority(INTC_DMA_DEI1, 3);
|
||||
sh7305_intc_priority(INTC_DMA_DEI2, 3);
|
||||
sh7305_intc_priority(INTC_DMA_DEI3, 3);
|
||||
sh7305_intc_priority(INTC_DMA_DEI4, 3);
|
||||
sh7305_intc_priority(INTC_DMA_DEI5, 3);
|
||||
sh7305_intc_priority(INTC_DMA_DADERR, 3);
|
||||
}
|
||||
|
||||
/* __rtc_hsave() : save hardware information */
|
||||
static void __dma_hsave(struct dma_ctx *s)
|
||||
{
|
||||
for(int i = 0; i < 6; i++) {
|
||||
channel_t *ch = sh7305_dma_channel(i);
|
||||
sh7305_dma_spinwait(ch);
|
||||
ch->SAR = s->ch[i].SAR;
|
||||
ch->DAR = s->ch[i].DAR;
|
||||
ch->TCR = s->ch[i].TCR;
|
||||
ch->CHCR.lword = s->ch[i].CHCR.lword;
|
||||
}
|
||||
|
||||
DMA.DMAOR.word = s->DMAOR.word;
|
||||
}
|
||||
|
||||
/* __dma_hrestore() : restore hardware information */
|
||||
static void __dma_hrestore(struct dma_ctx *s)
|
||||
{
|
||||
DMA.DMAOR.DME = 0;
|
||||
|
||||
for(int i = 0; i < 6; i++)
|
||||
{
|
||||
channel_t *ch = sh7305_dma_channel(i);
|
||||
ch->SAR = s->ch[i].SAR;
|
||||
ch->DAR = s->ch[i].DAR;
|
||||
ch->TCR = s->ch[i].TCR;
|
||||
ch->CHCR.lword = s->ch[i].CHCR.lword;
|
||||
}
|
||||
|
||||
DMA.DMAOR.word = s->DMAOR.word;
|
||||
}
|
||||
|
||||
#if 0
|
||||
struct vhex_driver drv_rtc = {
|
||||
.name = "DMA",
|
||||
.hsave = (void*)&__dma_hsave,
|
||||
.hrestore = (void*)&__dma_hrestore,
|
||||
.configure = (void*)&__dma_configure,
|
||||
.state_size = sizeof(struct dma_ctx),
|
||||
.flags = {
|
||||
.DMA = 1,
|
||||
.SHARED = 0,
|
||||
.UNUSED = 0,
|
||||
},
|
||||
};
|
||||
VHEX_DECLARE_DRIVER(05, drv_dma);
|
||||
#endif
|
|
@ -0,0 +1,9 @@
|
|||
#include <vhex/dma.h>
|
||||
|
||||
/* dma_memcpy() : memcpy using DMA */
|
||||
dma_id_t sh7305_dma_memcpy(void * restrict dst, void * restrict src, size_t sz)
|
||||
{
|
||||
(void)dst;
|
||||
(void)src;
|
||||
(void)sz;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include <vhex/dma.h>
|
||||
|
||||
/* dma_memset() : memset using the DMA */
|
||||
dma_id_t sh7305_dma_memset(void *dst, int c, size_t sz)
|
||||
{
|
||||
(void)dst;
|
||||
(void)c;
|
||||
(void)sz;
|
||||
}
|
|
@ -109,7 +109,7 @@ int sh7305_intc_priority(int intname, int level)
|
|||
}
|
||||
|
||||
/* sh7305_intc_install_inth() : install interrupt gate */
|
||||
void *sh7305_intc_install_inth(int event_code, void *gate, size_t size)
|
||||
void *sh7305_intc_install_inth_gate(int event_code, void *gate, size_t size)
|
||||
{
|
||||
extern uintptr_t vhex_vbr;
|
||||
|
||||
|
@ -121,18 +121,21 @@ void *sh7305_intc_install_inth(int event_code, void *gate, size_t size)
|
|||
}
|
||||
|
||||
/* sh7305_intc_generic_handler() : install generic interrupt handler */
|
||||
void *sh7305_intc_generic_handler(int event_code, void *user_inth)
|
||||
void *sh7305_intc_install_inth_generic(int event_code, vhex_call_t callback)
|
||||
{
|
||||
extern void vhex_sh7305_intc_generic_handler(void);
|
||||
extern void sh7305_intc_inth_generic_gate(void);
|
||||
extern void sh7305_inth_callback(void);
|
||||
|
||||
void *h = sh7305_intc_install_inth(
|
||||
uint8_t *h = sh7305_intc_install_inth_gate(
|
||||
event_code,
|
||||
sh7305_intc_generic_handler,
|
||||
sh7305_intc_inth_generic_gate,
|
||||
32
|
||||
);
|
||||
if(!h) return false;
|
||||
if(h == NULL)
|
||||
return false;
|
||||
|
||||
*(void **)(h + 28) = user_inth;
|
||||
memcpy(&h[8], &callback, 20);
|
||||
memcpy(&h[28], &sh7305_inth_callback, 4);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
|
|
@ -65,22 +65,3 @@ _vhex_inth_sh7305:
|
|||
1: .long 0xff000028
|
||||
.first_entry:
|
||||
|
||||
|
||||
/* _vhex_sh7305_intc_generic_handler: Standard interrupt handler
|
||||
|
||||
This is a generic interrupt handler that calls back into a C function,
|
||||
useful for complex handling or simple drivers that benefit more from
|
||||
simplicity than razor-sharp performance. */
|
||||
|
||||
.section .vhex.blocks, "ax"
|
||||
.align 4
|
||||
|
||||
.global _vhex_sh7305_intc_generic_handler /* 32 bytes */
|
||||
|
||||
_vhex_sh7305_intc_generic_handler:
|
||||
mov.l 1f, r1
|
||||
jmp @r1
|
||||
mov r0, r4
|
||||
|
||||
.zero 22 /* Indirect call to be made */
|
||||
1: .long 0 /* Address of the runtime */
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* _sh7305_intc_generic_handler_fate: Standard interrupt handler
|
||||
|
||||
This is a generic interrupt handler that calls back into a C function,
|
||||
useful for complex handling or simple drivers that benefit more from
|
||||
simplicity than razor-sharp performance. */
|
||||
|
||||
.section .vhex.blocks, "ax"
|
||||
.align 4
|
||||
|
||||
.global _sh7305_intc_inth_generic_gate /* 32 bytes */
|
||||
|
||||
_sh7305_intc_inth_generic_gate:
|
||||
mova 1f, r0
|
||||
mov.l 2f, r1
|
||||
jmp @r1
|
||||
mov r0, r4
|
||||
|
||||
1: .zero 20 /* Indirect call to be made (set at runtine) */
|
||||
2: .long 0 /* _sh7305_vhex_inth_callback (set at runtime) */
|
|
@ -48,9 +48,9 @@ void sh7305_keycache_init(void)
|
|||
|
||||
keyinfo.timer.id = sh7305_tmu_configure(
|
||||
7215,
|
||||
TIMER_CALL(
|
||||
VHEX_CALL(
|
||||
&__sh7305_keycache_keyframe,
|
||||
(uintptr_t)&keyinfo.timer.counter
|
||||
&keyinfo.timer.counter
|
||||
)
|
||||
);
|
||||
sh7305_tmu_start(keyinfo.timer.id);
|
||||
|
|
|
@ -83,7 +83,7 @@ static void __keysc_configure(struct keysc_ctx *ctx)
|
|||
|
||||
/* intall the KEYSC interupt handler */
|
||||
extern void sh7305_keysc_inth(void);
|
||||
sh7305_intc_install_inth(0xbe0, &sh7305_keysc_inth, 64);
|
||||
sh7305_intc_install_inth_gate(0xbe0, &sh7305_keysc_inth, 64);
|
||||
}
|
||||
|
||||
/* __keysc_hsave() : save hardware information */
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <vhex/driver/mpu/sh/sh7305/rtc.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/intc.h>
|
||||
#include <vhex/rtc/interface.h>
|
||||
#include <vhex/defs/call.h>
|
||||
#include <vhex/driver.h>
|
||||
|
||||
#include <string.h>
|
||||
|
@ -9,24 +10,12 @@
|
|||
// RTC periodic interrupt
|
||||
//---
|
||||
|
||||
static struct rtc_call rtc_call;
|
||||
static vhex_call_t rtc_call;
|
||||
|
||||
/* rtc_periodic interrupt() : internal interrupt handler */
|
||||
static void sh7305_rtc_periodic_inth(void)
|
||||
{
|
||||
int (*routine)(
|
||||
uintptr_t,
|
||||
uintptr_t,
|
||||
uintptr_t,
|
||||
uintptr_t
|
||||
) = rtc_call.function;
|
||||
|
||||
int rc = routine(
|
||||
rtc_call.args[0],
|
||||
rtc_call.args[1],
|
||||
rtc_call.args[2],
|
||||
rtc_call.args[3]
|
||||
);
|
||||
int rc = vhex_call(rtc_call);
|
||||
|
||||
/* Clear the interrupt flag */
|
||||
do SH7305_RTC.RCR2.PEF = 0;
|
||||
|
@ -37,7 +26,7 @@ static void sh7305_rtc_periodic_inth(void)
|
|||
}
|
||||
|
||||
/* rtc_periodic_enable(): Enable the periodic interrupt */
|
||||
bool sh7305_rtc_periodic_enable(int frequency, struct rtc_call callback)
|
||||
bool sh7305_rtc_periodic_enable(int frequency, vhex_call_t callback)
|
||||
{
|
||||
/* Refuse to override an existing interrupt */
|
||||
if(SH7305_RTC.RCR2.PES != RTC_NONE) return false;
|
||||
|
@ -49,7 +38,7 @@ bool sh7305_rtc_periodic_enable(int frequency, struct rtc_call callback)
|
|||
|
||||
/* Temporarily disable the interrupt and set up the callback */
|
||||
SH7305_RTC.RCR2.PES = RTC_NONE;
|
||||
memcpy(&rtc_call, &callback, sizeof(struct rtc_call));
|
||||
memcpy(&rtc_call, &callback, sizeof(vhex_call_t));
|
||||
|
||||
/* Clear the interrupt flag */
|
||||
do SH7305_RTC.RCR2.PEF = 0;
|
||||
|
@ -99,7 +88,10 @@ static void __rtc_configure(struct rtc_ctx *state)
|
|||
sh7305_intc_priority(INTC_RTC_PRI, 1);
|
||||
|
||||
/* intall the RTC interupt handler */
|
||||
sh7305_intc_generic_handler(0xaa0, &sh7305_rtc_periodic_inth);
|
||||
sh7305_intc_install_inth_generic(
|
||||
0xaa0,
|
||||
VHEX_CALL(&sh7305_rtc_periodic_inth)
|
||||
);
|
||||
}
|
||||
|
||||
/* __rtc_hsave() : save hardware information */
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <string.h>
|
||||
|
||||
/* Callbacks for all timers */
|
||||
timer_call_t sh7305_tmu_callbacks[9];
|
||||
vhex_call_t sh7305_tmu_callbacks[9];
|
||||
|
||||
/* Arrays of standard and extra timers */
|
||||
tmu_t *TMU = SH7305_TMU.TMU;
|
||||
|
@ -84,7 +84,7 @@ static tid_t reserve(tid_t id, uint32_t delay, int clock)
|
|||
}
|
||||
|
||||
/* conf(): Configure a fixed timer */
|
||||
static tid_t conf(tid_t id, timer_call_t call)
|
||||
static tid_t conf(tid_t id, vhex_call_t call)
|
||||
{
|
||||
if(id < 3) {
|
||||
/* Refuse to setup timers that are already in use */
|
||||
|
@ -200,14 +200,14 @@ tid_t sh7305_tmu_reserve(uint64_t delay)
|
|||
}
|
||||
|
||||
/* sh7305_tmu_configure() : configure timer */
|
||||
tid_t sh7305_tmu_configure(uint64_t delay, timer_call_t call)
|
||||
tid_t sh7305_tmu_configure(uint64_t delay, vhex_call_t call)
|
||||
{
|
||||
tid_t timer = sh7305_tmu_reserve(delay);
|
||||
if (timer < 0)
|
||||
return -1;
|
||||
|
||||
if(call.function == NULL)
|
||||
call = TIMER_CALL(&stop_callback);
|
||||
call = VHEX_CALL(&stop_callback);
|
||||
|
||||
return conf(timer, call);
|
||||
}
|
||||
|
@ -498,7 +498,7 @@ static void __tmu_configure(struct tmu_ctx *s)
|
|||
|
||||
/* install the TMUs interupt handler */
|
||||
extern uint32_t sh7305_inth_tmu;
|
||||
sh7305_intc_install_inth(0x400, &sh7305_inth_tmu, 96);
|
||||
sh7305_intc_install_inth_gate(0x400, &sh7305_inth_tmu, 96);
|
||||
|
||||
/* install all ETMUx interrupt handler
|
||||
|
||||
|
@ -517,7 +517,7 @@ static void __tmu_configure(struct tmu_ctx *s)
|
|||
void *h;
|
||||
|
||||
uint16_t etmu_evt[6] = { 0x9e0, 0xc20, 0xc40, 0x900, 0xd00, 0xfa0 };
|
||||
h4 = sh7305_intc_install_inth(etmu_evt[4], &sh7305_inth_etmu4, 96);
|
||||
h4 = sh7305_intc_install_inth_gate(etmu_evt[4], &sh7305_inth_etmu4, 96);
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
/* skip the core ETMUx core handler */
|
||||
|
@ -525,7 +525,11 @@ static void __tmu_configure(struct tmu_ctx *s)
|
|||
continue;
|
||||
|
||||
/* install the default interrupt handler */
|
||||
h = sh7305_intc_install_inth(etmu_evt[i], &sh7305_inth_etmux, 32);
|
||||
h = sh7305_intc_install_inth_gate(
|
||||
etmu_evt[i],
|
||||
&sh7305_inth_etmux,
|
||||
32
|
||||
);
|
||||
|
||||
/* Timer ID, used for sh7305_tmu_stop() after the callback */
|
||||
*(uint16_t *)(h + 16) = i + 3;
|
||||
|
|
|
@ -7,7 +7,11 @@
|
|||
// R61524 driver API
|
||||
//---
|
||||
|
||||
uint32_t vhex_vram[396*(224/2)];
|
||||
/* defined by the linker script */
|
||||
extern uint32_t vhex_vram0;
|
||||
extern uint32_t vhex_vram1;
|
||||
|
||||
static uint32_t *vhex_vram = &vhex_vram0;
|
||||
|
||||
/* r61524_frame_start() - prepar the screen and reset surfaces */
|
||||
VALIGNED(4) int r61524_frame_start(dsurface_t *surface)
|
||||
|
@ -33,15 +37,15 @@ VALIGNED(4) int r61524_frame_start(dsurface_t *surface)
|
|||
|
||||
/* initialize surface information */
|
||||
// surface->vram = (void*)0xe5017000;
|
||||
// surface->width = 396;
|
||||
// surface->height = 10;
|
||||
surface->vram = (void*)vhex_vram;
|
||||
surface->width = 396;
|
||||
surface->height = 224;
|
||||
// surface->height = 10;
|
||||
surface->x1 = 0;
|
||||
surface->y1 = 0;
|
||||
surface->x2 = 395;
|
||||
surface->y2 = 223;
|
||||
// surface->y2 = 9;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,4 +23,4 @@ struct vhex_module mod_keyboard = {
|
|||
.init = &__keyboard_init,
|
||||
.quit = &__keyboard_quit,
|
||||
};
|
||||
VHEX_DECLARE_MODULE(04, mod_keyboard);
|
||||
VHEX_DECLARE_MODULE(05, mod_keyboard);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <vhex/keyboard.h>
|
||||
#include <vhex/keyboard/interface.h>
|
||||
#include <vhex/keyboard/keycode.h>
|
||||
#include <vhex/driver/cpu.h>
|
||||
#include <vhex/timer.h>
|
||||
#include <vhex/driver.h>
|
||||
|
|
|
@ -23,7 +23,7 @@ tid_t timer_reserve(uint64_t delay_us)
|
|||
}
|
||||
|
||||
/* timer_configure(): Reserve and configure a timer */
|
||||
tid_t timer_configure(uint64_t delay_us, timer_call_t callback)
|
||||
tid_t timer_configure(uint64_t delay_us, vhex_call_t callback)
|
||||
{
|
||||
if (timer_info.driver.timer_configure != NULL)
|
||||
return (timer_info.driver.timer_configure(delay_us, callback));
|
||||
|
@ -118,4 +118,4 @@ struct vhex_module mod_timer = {
|
|||
.init = &__timer_init,
|
||||
.quit = &__timer_quit,
|
||||
};
|
||||
VHEX_DECLARE_MODULE(02, mod_timer);
|
||||
VHEX_DECLARE_MODULE(04, mod_timer);
|
||||
|
|
Loading…
Reference in New Issue