mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-29 13:03:36 +01:00
Interrupt controller module description (WIP), task switch and return to menu.
This commit is contained in:
parent
cd6bd5a1a4
commit
5e66efc560
20 changed files with 297 additions and 130 deletions
3
TODO
3
TODO
|
@ -6,11 +6,10 @@ Bugs to fix:
|
||||||
|
|
||||||
Things to do before 1.0:
|
Things to do before 1.0:
|
||||||
- bopti: Test partial transparency
|
- bopti: Test partial transparency
|
||||||
* core: Allow return to menu
|
|
||||||
- demo: Try 284x124 at (-60, -28) (all disadvantages)
|
- demo: Try 284x124 at (-60, -28) (all disadvantages)
|
||||||
- project: Check size of *all* library structures
|
- project: Check size of *all* library structures
|
||||||
- project: Clean headers that have some internal definitions
|
- project: Clean headers that have some internal definitions
|
||||||
- project: Unify this hellish mess of register access!
|
- project: Get rid of 7705.h (keyboard) and 7305.h (keyboard, gint)
|
||||||
- time: Compute CLOCKS_PER_SEC
|
- time: Compute CLOCKS_PER_SEC
|
||||||
|
|
||||||
Things to do later:
|
Things to do later:
|
||||||
|
|
|
@ -277,6 +277,9 @@ void tlb_debug(void)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <modules/rtc.h>
|
||||||
|
#include <modules/interrupts.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
main_menu()
|
main_menu()
|
||||||
Displays the main menu and returns user's choice: 0 for [EXIT],
|
Displays the main menu and returns user's choice: 0 for [EXIT],
|
||||||
|
@ -301,7 +304,7 @@ void main_menu(int *category, int *app)
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *list_tests[] = {
|
const char *list_tests[] = {
|
||||||
"Keyboard and events",
|
"Keyboard & events",
|
||||||
"Gray engine",
|
"Gray engine",
|
||||||
"Image rendering",
|
"Image rendering",
|
||||||
"Text rendering",
|
"Text rendering",
|
||||||
|
@ -353,9 +356,10 @@ void main_menu(int *category, int *app)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
print(1, 1, "gint %s", gint_version);
|
print(1, 1, "gint %s", gint_version);
|
||||||
print(2, 4, "handler size: %5d", gint_size);
|
print(2, 3, "MPU type %7s", mpu);
|
||||||
print(2, 5, "mpu type: %7s", mpu);
|
print(2, 4, "Add-in size %3dk",
|
||||||
print(2, 6, "romdata: %08x", &romdata);
|
((uint32_t)&romdata - 0x00300000) >> 10);
|
||||||
|
print(2, 5, "gint size %5do", gint_size);
|
||||||
|
|
||||||
list = NULL;
|
list = NULL;
|
||||||
break;
|
break;
|
||||||
|
@ -408,9 +412,6 @@ void main_menu(int *category, int *app)
|
||||||
|
|
||||||
switch(getkey())
|
switch(getkey())
|
||||||
{
|
{
|
||||||
// case KEY_7:
|
|
||||||
// crt0_system_menu();
|
|
||||||
// break;
|
|
||||||
case KEY_F1:
|
case KEY_F1:
|
||||||
if(!tab) break;
|
if(!tab) break;
|
||||||
tab = 0;
|
tab = 0;
|
||||||
|
@ -434,6 +435,9 @@ void main_menu(int *category, int *app)
|
||||||
index = 0;
|
index = 0;
|
||||||
scroll = 0;
|
scroll = 0;
|
||||||
break;
|
break;
|
||||||
|
case KEY_F5:
|
||||||
|
gint_switch();
|
||||||
|
break;
|
||||||
case KEY_F6:;
|
case KEY_F6:;
|
||||||
void screen(void);
|
void screen(void);
|
||||||
screen();
|
screen();
|
||||||
|
@ -480,11 +484,11 @@ void main_menu(int *category, int *app)
|
||||||
if(app) *app = index + 1;
|
if(app) *app = index + 1;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case KEY_MENU:
|
/* case KEY_MENU:
|
||||||
if(category) *category = 0;
|
if(category) *category = 0;
|
||||||
if(app) *app = 0;
|
if(app) *app = 0;
|
||||||
return;
|
return;
|
||||||
|
*/
|
||||||
default:
|
default:
|
||||||
leave = 0;
|
leave = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
output. Note how symbols romdata, bbss, ebss, bdata and edata are used
|
output. Note how symbols romdata, bbss, ebss, bdata and edata are used
|
||||||
in the initialization routine (crt0.c) to initialize the application.
|
in the initialization routine (crt0.c) to initialize the application.
|
||||||
|
|
||||||
Two ram areas are specified. The "real ram" is accessed direcly while
|
Two ram areas are specified. The "real ram" is accessed directly while
|
||||||
the other area is virtualized. It is not possible to execute code in
|
the other area is virtualized. It is not possible to execute code in
|
||||||
virtualized ram.
|
virtualized ram.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <events.h>
|
#include <events.h>
|
||||||
|
|
||||||
static void draw_keyboard(volatile uint8_t *state)
|
static int draw_keyboard(volatile uint8_t *state)
|
||||||
{
|
{
|
||||||
|
int pressed_keys = 0;
|
||||||
int i, j, k, l;
|
int i, j, k, l;
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ static void draw_keyboard(volatile uint8_t *state)
|
||||||
// Drawing a filled shape when the key is pressed.
|
// Drawing a filled shape when the key is pressed.
|
||||||
if(state[i] & (0x80 >> j))
|
if(state[i] & (0x80 >> j))
|
||||||
{
|
{
|
||||||
|
pressed_keys++;
|
||||||
for(k = -2; k <= 2; k++) for(l = -2; l <= 2; l++)
|
for(k = -2; k <= 2; k++) for(l = -2; l <= 2; l++)
|
||||||
if(abs(k) + abs(l) <= 2)
|
if(abs(k) + abs(l) <= 2)
|
||||||
dpixel(x + k, y + l, color_black);
|
dpixel(x + k, y + l, color_black);
|
||||||
|
@ -49,47 +51,61 @@ static void draw_keyboard(volatile uint8_t *state)
|
||||||
|
|
||||||
// An horizontal line to separate parts of the keyboard.
|
// An horizontal line to separate parts of the keyboard.
|
||||||
dline(5, 28, 32, 28, color_black);
|
dline(5, 28, 32, 28, color_black);
|
||||||
|
|
||||||
|
return pressed_keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
event_type_t type;
|
|
||||||
uint32_t key;
|
uint32_t key;
|
||||||
int repeats;
|
int repeats;
|
||||||
|
} history_key_t;
|
||||||
|
|
||||||
} enhanced_event_t;
|
typedef struct {
|
||||||
|
history_key_t *data;
|
||||||
|
int size;
|
||||||
|
int pressed;
|
||||||
|
} history_t;
|
||||||
|
|
||||||
static void push_history(enhanced_event_t *history, int size, event_t event)
|
static int pressed_keys = -1;
|
||||||
|
static int releases = 0;
|
||||||
|
|
||||||
|
static void history_push(history_t *h, event_t event)
|
||||||
{
|
{
|
||||||
#define event_eq(x, y) \
|
// Only reset the number of pressed keys in the history when the actual
|
||||||
((x).type == (y).type && (x).key == (y).key.code)
|
// number of pressed keys reaches 0.
|
||||||
|
|
||||||
// Determining where the history ends.
|
if(event.type == event_key_release)
|
||||||
int length = 0;
|
|
||||||
while(length < size && history[length].type != event_none) length++;
|
|
||||||
|
|
||||||
// Checking if the previous event is being repeated.
|
|
||||||
if(length > 0 && event_eq(history[length - 1], event))
|
|
||||||
{
|
{
|
||||||
history[length - 1].repeats++;
|
pressed_keys--;
|
||||||
|
if(!pressed_keys) h->pressed = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Making up some space if required.
|
// Now we're sure a key was pressed or repeated. Check if it's in the
|
||||||
if(length == size)
|
// last pressed elements of the history array, if so, update it.
|
||||||
|
// Otherwise make space for a new entry and add it.
|
||||||
|
|
||||||
|
if(event.type == event_key_press) pressed_keys++;
|
||||||
|
|
||||||
|
for(int i = h->size - h->pressed; i < h->size; i++)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < size - 1; i++) history[i] = history[i + 1];
|
if(h->data[i].key == event.key.code)
|
||||||
length = size - 1;
|
{
|
||||||
|
h->data[i].repeats++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adding a new entry to the history.
|
// If there are already h->size keys pressed, do not add more.
|
||||||
history[length].type = event.type;
|
if(event.type == event_key_press) h->pressed++;
|
||||||
history[length].key = event.key.code;
|
if(h->pressed > h->size) return;
|
||||||
history[length].repeats = 1;
|
|
||||||
|
|
||||||
#undef event_eq
|
for(int i = 0; i < h->size - 1; i++) h->data[i] = h->data[i + 1];
|
||||||
|
h->data[h->size - 1].key = event.key.code;
|
||||||
|
h->data[h->size - 1].repeats = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_events(enhanced_event_t *history, int size)
|
static void draw_events(history_t *h)
|
||||||
{
|
{
|
||||||
const char *key_names[] = {
|
const char *key_names[] = {
|
||||||
"F1", "F2", "F3", "F4", "F5", "F6",
|
"F1", "F2", "F3", "F4", "F5", "F6",
|
||||||
|
@ -102,17 +118,21 @@ static void draw_events(enhanced_event_t *history, int size)
|
||||||
"1", "2", "3", "+", "-", NULL,
|
"1", "2", "3", "+", "-", NULL,
|
||||||
"0", ".", "\x08", "(-)", "EXE", NULL
|
"0", ".", "\x08", "(-)", "EXE", NULL
|
||||||
};
|
};
|
||||||
const char *event_names[] = {
|
|
||||||
"None ", "User ", "Press", "Rept.", "Rel. ", "Timer"
|
|
||||||
};
|
|
||||||
|
|
||||||
for(int i = 0; i < size && history[i].type != event_none; i++)
|
int y = 3;
|
||||||
|
|
||||||
|
print(8, 2, "%d %d %d", pressed_keys, h->pressed, releases);
|
||||||
|
|
||||||
|
for(int i = 0; i < h->size; i++)
|
||||||
{
|
{
|
||||||
print(8, 3 + i, "%s %s", event_names[history[i].type],
|
if(!h->data[i].key) continue;
|
||||||
key_names[key_id(history[i].key)]);
|
print(8, y, "%s", key_names[key_id(h->data[i].key)]);
|
||||||
if(history[i].repeats > 1)
|
if(h->data[i].repeats > 1)
|
||||||
print(19, 3 + i, "%d", history[i].repeats);
|
print(18, y, "%d", h->data[i].repeats);
|
||||||
|
y++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(h->pressed > h->size) print(8, 8, "(more)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -121,23 +141,31 @@ static void draw_events(enhanced_event_t *history, int size)
|
||||||
*/
|
*/
|
||||||
void test_keyboard_events(void)
|
void test_keyboard_events(void)
|
||||||
{
|
{
|
||||||
enhanced_event_t history[5];
|
history_key_t history_data[5] = { 0 };
|
||||||
int history_size = 5;
|
history_t history = {
|
||||||
|
.data = history_data,
|
||||||
|
.size = 5,
|
||||||
|
.pressed = 0,
|
||||||
|
};
|
||||||
event_t event;
|
event_t event;
|
||||||
|
|
||||||
for(int i = 0; i < history_size; i++) history[i].type = event_none;
|
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
dclear();
|
dclear();
|
||||||
locate(1, 1, "Keyboard and events");
|
locate(1, 1, "Keyboard and events");
|
||||||
draw_keyboard(keyboard_stateBuffer());
|
|
||||||
draw_events(history, history_size);
|
// There may be more than zero keys pressed when this test
|
||||||
|
// starts. We need to detect this count automatically.
|
||||||
|
int x = draw_keyboard(keyboard_stateBuffer());
|
||||||
|
if(pressed_keys < 0) pressed_keys = x;
|
||||||
|
|
||||||
|
draw_events(&history);
|
||||||
dupdate();
|
dupdate();
|
||||||
|
|
||||||
event = waitevent();
|
event = waitevent();
|
||||||
|
if(event.type == event_key_release) releases++;
|
||||||
if(event.type == event_key_press && event.key.code == KEY_EXIT)
|
if(event.type == event_key_press && event.key.code == KEY_EXIT)
|
||||||
break;
|
break;
|
||||||
push_history(history, history_size, event);
|
history_push(&history, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -236,4 +236,16 @@ typedef enum
|
||||||
*/
|
*/
|
||||||
volatile void *gint_reg(gint_register_t reg);
|
volatile void *gint_reg(gint_register_t reg);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Other functions
|
||||||
|
//---
|
||||||
|
|
||||||
|
/*
|
||||||
|
gint_switch()
|
||||||
|
Temporarily returns to the system's main menu.
|
||||||
|
*/
|
||||||
|
void gint_switch(void);
|
||||||
|
|
||||||
#endif // _GINT_H
|
#endif // _GINT_H
|
||||||
|
|
|
@ -51,6 +51,14 @@ uint32_t *gray_lightVRAM(void);
|
||||||
*/
|
*/
|
||||||
uint32_t *gray_darkVRAM(void);
|
uint32_t *gray_darkVRAM(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
gray_currentVRAM()
|
||||||
|
Returns the currently displayed video ram (if the engine runs). Used
|
||||||
|
internally, but has no interest for the user. You don't want to draw to
|
||||||
|
this vram.
|
||||||
|
*/
|
||||||
|
uint32_t *gray_currentVRAM(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gray_getDelays()
|
gray_getDelays()
|
||||||
Returns the gray engine delays. Pointers are not set if NULL.
|
Returns the gray engine delays. Pointers are not set if NULL.
|
||||||
|
|
|
@ -162,6 +162,10 @@ typedef enum
|
||||||
// compatible models.
|
// compatible models.
|
||||||
getkey_manage_backlight = 0x04,
|
getkey_manage_backlight = 0x04,
|
||||||
|
|
||||||
|
// Allow returning to menu using the [MENU] key. (This operation is not
|
||||||
|
// absolutely safe.)
|
||||||
|
getkey_task_switch = 0x08,
|
||||||
|
|
||||||
// Allow key repetition. This option does not control the generation of
|
// Allow key repetition. This option does not control the generation of
|
||||||
// repeat events (use keyboard_setRepeatRate() for this) but filters
|
// repeat events (use keyboard_setRepeatRate() for this) but filters
|
||||||
// them. Please note that modifiers will never be repeated, even when
|
// them. Please note that modifiers will never be repeated, even when
|
||||||
|
|
|
@ -590,7 +590,7 @@ typedef struct
|
||||||
uint8_t IMR12;
|
uint8_t IMR12;
|
||||||
char gap2[15];
|
char gap2[15];
|
||||||
|
|
||||||
} __attribute__((packed)) mod_intc_masks_7305_t;
|
} __attribute__((packed, aligned(4))) mod_intc_masks_7305_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
mod_intc_userimask_7305_t
|
mod_intc_userimask_7305_t
|
||||||
|
@ -605,7 +605,7 @@ typedef struct
|
||||||
void set_user_imask(int new_level)
|
void set_user_imask(int new_level)
|
||||||
{
|
{
|
||||||
mod_intc_userimask_7305_t mask = *(INTC._7305.USERIMASK);
|
mod_intc_userimask_7305_t mask = *(INTC._7305.USERIMASK);
|
||||||
mask._a5 = 0xa5;
|
mask._0xa5 = 0xa5;
|
||||||
mask.UIMASK = new_level & 0x0f;
|
mask.UIMASK = new_level & 0x0f;
|
||||||
*(INTC._7305.USERIMASK) = mask;
|
*(INTC._7305.USERIMASK) = mask;
|
||||||
}
|
}
|
||||||
|
@ -613,7 +613,7 @@ typedef struct
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
lword_union(,
|
lword_union(,
|
||||||
uint _a5 :8; /* Always set to 0xa5 before writing */
|
uint _0xa5 :8; /* Always set to 0xa5 before writing */
|
||||||
uint :16;
|
uint :16;
|
||||||
uint UIMASK :4; /* User Interrupt Mask Level */
|
uint UIMASK :4; /* User Interrupt Mask Level */
|
||||||
uint :4;
|
uint :4;
|
||||||
|
@ -628,7 +628,7 @@ typedef struct
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
byte_union(,
|
word_union(,
|
||||||
uint const NMIL :1; /* NMI Interupt Level */
|
uint const NMIL :1; /* NMI Interupt Level */
|
||||||
uint :14;
|
uint :14;
|
||||||
uint NMIFL :1; /* NMI Interrupt Request Flag */
|
uint NMIFL :1; /* NMI Interrupt Request Flag */
|
||||||
|
@ -682,4 +682,7 @@ typedef union
|
||||||
|
|
||||||
} __attribute__((packed)) mod_intc_t;
|
} __attribute__((packed)) mod_intc_t;
|
||||||
|
|
||||||
|
// Here's what you'll need to use.
|
||||||
|
extern mod_intc_t INTC;
|
||||||
|
|
||||||
#endif // _MODULE_INTERRUPTS
|
#endif // _MODULE_INTERRUPTS
|
||||||
|
|
|
@ -39,7 +39,7 @@ typedef unsigned uint;
|
||||||
uint16_t word; \
|
uint16_t word; \
|
||||||
struct { fields } \
|
struct { fields } \
|
||||||
__attribute__((packed)); \
|
__attribute__((packed)); \
|
||||||
} __attribute__((packed)) name
|
} __attribute__((packed, aligned(2))) name
|
||||||
|
|
||||||
/*
|
/*
|
||||||
lword_union()
|
lword_union()
|
||||||
|
@ -52,6 +52,6 @@ typedef unsigned uint;
|
||||||
uint32_t lword; \
|
uint32_t lword; \
|
||||||
struct { fields } \
|
struct { fields } \
|
||||||
__attribute__((packed)); \
|
__attribute__((packed)); \
|
||||||
} __attribute__((packed)) name
|
} __attribute__((packed, aligned(4))) name
|
||||||
|
|
||||||
#endif // _MODULES_MACROS_H
|
#endif // _MODULES_MACROS_H
|
||||||
|
|
|
@ -140,8 +140,6 @@ __attribute__((section(".pretext.entry"))) int start(void)
|
||||||
dg->stage = stage_running;
|
dg->stage = stage_running;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Saving the execution state there.
|
// Saving the execution state there.
|
||||||
int x = setjmp(env);
|
int x = setjmp(env);
|
||||||
// If the program has just started, executing main(). Otherwise, the
|
// If the program has just started, executing main(). Otherwise, the
|
||||||
|
@ -253,13 +251,3 @@ int atexit(void (*function)(void))
|
||||||
atexit_handlers[atexit_index++] = function;
|
atexit_handlers[atexit_index++] = function;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void crt0_system_menu(void)
|
|
||||||
{
|
|
||||||
fini();
|
|
||||||
gint_quit();
|
|
||||||
__system_menu();
|
|
||||||
mmu_pseudoTLBInit();
|
|
||||||
gint_init();
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
|
@ -153,7 +153,7 @@ void gint_install(gint_interrupt_type_t type, void *function)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gint_uninstall()
|
gint_uninstall()
|
||||||
Uninstalls the exception or interrupt handler that was used for the
|
Un-installs the exception or interrupt handler that was used for the
|
||||||
given interrupt, falling back to gint's default handler.
|
given interrupt, falling back to gint's default handler.
|
||||||
*/
|
*/
|
||||||
void gint_uninstall(gint_interrupt_type_t type)
|
void gint_uninstall(gint_interrupt_type_t type)
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include <gint.h>
|
#include <gint.h>
|
||||||
#include <timer.h>
|
#include <timer.h>
|
||||||
#include <rtc.h>
|
#include <rtc.h>
|
||||||
#include <7705.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gint_reg()
|
gint_reg()
|
||||||
|
@ -34,15 +33,18 @@ volatile void *gint_reg_7705(gint_register_t reg)
|
||||||
|
|
||||||
void gint_save_7705(environment_7705_t *e)
|
void gint_save_7705(environment_7705_t *e)
|
||||||
{
|
{
|
||||||
|
mod_intc_7705_t *intc = &INTC._7705;
|
||||||
|
mod_intc_ipc_7705_t *ipc = &intc->iprs;
|
||||||
|
|
||||||
// Saving the interrupt masks from registers IPRA to IPRH.
|
// Saving the interrupt masks from registers IPRA to IPRH.
|
||||||
e->IPR[0] = INTC.IPRA.WORD;
|
e->IPR[0] = ipc->IPRA->word;
|
||||||
e->IPR[1] = INTC.IPRB.WORD;
|
e->IPR[1] = ipc->IPRB->word;
|
||||||
e->IPR[2] = INTX.IPRC.WORD;
|
e->IPR[2] = ipc->IPRC->word;
|
||||||
e->IPR[3] = INTX.IPRD.WORD;
|
e->IPR[3] = ipc->IPRD->word;
|
||||||
e->IPR[4] = INTX.IPRE.WORD;
|
e->IPR[4] = ipc->IPRE->word;
|
||||||
e->IPR[5] = INTX.IPRF.WORD;
|
e->IPR[5] = ipc->IPRF->word;
|
||||||
e->IPR[6] = INTX.IPRG.WORD;
|
e->IPR[6] = ipc->IPRG->word;
|
||||||
e->IPR[7] = INTX.IPRH.WORD;
|
e->IPR[7] = ipc->IPRH->word;
|
||||||
|
|
||||||
// Saving RTC registers.
|
// Saving RTC registers.
|
||||||
e->RCR1 = RTC.RCR1->byte;
|
e->RCR1 = RTC.RCR1->byte;
|
||||||
|
@ -54,35 +56,39 @@ void gint_save_7705(environment_7705_t *e)
|
||||||
e->TMU2 = *(TMU.timers[2]);
|
e->TMU2 = *(TMU.timers[2]);
|
||||||
e->TSTR = TMU.TSTR->byte;
|
e->TSTR = TMU.TSTR->byte;
|
||||||
|
|
||||||
// Saving port data used to access the keyboard.
|
/* // Saving port data used to access the keyboard.
|
||||||
e->PACR = PFC.PACR.WORD;
|
e->PACR = PFC.PACR.WORD;
|
||||||
e->PADR = PA.DR.BYTE;
|
e->PADR = PA.DR.BYTE;
|
||||||
e->PBCR = PFC.PBCR.WORD;
|
e->PBCR = PFC.PBCR.WORD;
|
||||||
e->PBDR = PB.DR.BYTE;
|
e->PBDR = PB.DR.BYTE;
|
||||||
e->PMCR = PFC.PMCR.WORD;
|
e->PMCR = PFC.PMCR.WORD;
|
||||||
e->PMDR = PM.DR.BYTE;
|
e->PMDR = PM.DR.BYTE;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void gint_lock_and_setup_7705(void)
|
void gint_lock_and_setup_7705(void)
|
||||||
{
|
{
|
||||||
|
mod_intc_7705_t *intc = &INTC._7705;
|
||||||
|
mod_intc_ipc_7705_t *ipc = &intc->iprs;
|
||||||
|
|
||||||
// Disabling everything by default to avoid receiving an interrupt that
|
// Disabling everything by default to avoid receiving an interrupt that
|
||||||
// the handler doesn't handle, which would cause the user program to
|
// the handler doesn't handle, which would cause the user program to
|
||||||
// freeze.
|
// freeze.
|
||||||
INTC.IPRA.WORD = 0x0000;
|
ipc->IPRA->word = 0x0000;
|
||||||
INTC.IPRB.WORD = 0x0000;
|
ipc->IPRB->word = 0x0000;
|
||||||
INTX.IPRC.WORD = 0x0000;
|
ipc->IPRC->word = 0x0000;
|
||||||
INTX.IPRD.WORD = 0x0000;
|
ipc->IPRD->word = 0x0000;
|
||||||
INTX.IPRE.WORD = 0x0000;
|
ipc->IPRE->word = 0x0000;
|
||||||
INTX.IPRF.WORD = 0x0000;
|
ipc->IPRF->word = 0x0000;
|
||||||
INTX.IPRG.WORD = 0x0000;
|
ipc->IPRG->word = 0x0000;
|
||||||
INTX.IPRH.WORD = 0x0000;
|
ipc->IPRH->word = 0x0000;
|
||||||
|
|
||||||
// Allowing RTC and timer (which handles keyboard and a whole bunch of
|
// Allowing RTC and timer (which handles keyboard and a whole bunch of
|
||||||
// other things).
|
// other things).
|
||||||
INTC.IPRA.BIT._RTC = 10;
|
ipc->IPRA->RTC = 10;
|
||||||
INTC.IPRA.BIT._TMU0 = 12;
|
ipc->IPRA->TMU0 = 12;
|
||||||
INTC.IPRA.BIT._TMU1 = 12;
|
ipc->IPRA->TMU1 = 12;
|
||||||
INTC.IPRA.BIT._TMU2 = 12;
|
ipc->IPRA->TMU2 = 12;
|
||||||
|
|
||||||
// Don't enable RTC periodic signals by default.
|
// Don't enable RTC periodic signals by default.
|
||||||
RTC.RCR2->byte = 0x09;
|
RTC.RCR2->byte = 0x09;
|
||||||
|
@ -90,15 +96,18 @@ void gint_lock_and_setup_7705(void)
|
||||||
|
|
||||||
void gint_restore_and_unlock_7705(environment_7705_t *e)
|
void gint_restore_and_unlock_7705(environment_7705_t *e)
|
||||||
{
|
{
|
||||||
|
mod_intc_7705_t *intc = &INTC._7705;
|
||||||
|
mod_intc_ipc_7705_t *ipc = &intc->iprs;
|
||||||
|
|
||||||
// Restoring the saved states.
|
// Restoring the saved states.
|
||||||
INTC.IPRA.WORD = e->IPR[0];
|
ipc->IPRA->word = e->IPR[0];
|
||||||
INTC.IPRB.WORD = e->IPR[1];
|
ipc->IPRB->word = e->IPR[1];
|
||||||
INTX.IPRC.WORD = e->IPR[2];
|
ipc->IPRC->word = e->IPR[2];
|
||||||
INTX.IPRD.WORD = e->IPR[3];
|
ipc->IPRD->word = e->IPR[3];
|
||||||
INTX.IPRE.WORD = e->IPR[4];
|
ipc->IPRE->word = e->IPR[4];
|
||||||
INTX.IPRF.WORD = e->IPR[5];
|
ipc->IPRF->word = e->IPR[5];
|
||||||
INTX.IPRG.WORD = e->IPR[6];
|
ipc->IPRG->word = e->IPR[6];
|
||||||
INTX.IPRH.WORD = e->IPR[7];
|
ipc->IPRH->word = e->IPR[7];
|
||||||
|
|
||||||
// Restoring RTC registers.
|
// Restoring RTC registers.
|
||||||
RTC.RCR1->byte = e->RCR1;
|
RTC.RCR1->byte = e->RCR1;
|
||||||
|
@ -110,11 +119,12 @@ void gint_restore_and_unlock_7705(environment_7705_t *e)
|
||||||
*(TMU.timers[2]) = e->TMU2;
|
*(TMU.timers[2]) = e->TMU2;
|
||||||
TMU.TSTR->byte = e->TSTR;
|
TMU.TSTR->byte = e->TSTR;
|
||||||
|
|
||||||
// Restoring keyboard-related I/O port registers.
|
/* // Restoring keyboard-related I/O port registers.
|
||||||
PFC.PACR.WORD = e->PACR;
|
PFC.PACR.WORD = e->PACR;
|
||||||
PA.DR.BYTE = e->PADR;
|
PA.DR.BYTE = e->PADR;
|
||||||
PFC.PBCR.WORD = e->PBCR;
|
PFC.PBCR.WORD = e->PBCR;
|
||||||
PB.DR.BYTE = e->PBDR;
|
PB.DR.BYTE = e->PBDR;
|
||||||
PFC.PMCR.WORD = e->PMCR;
|
PFC.PMCR.WORD = e->PMCR;
|
||||||
PM.DR.BYTE = e->PMDR;
|
PM.DR.BYTE = e->PMDR;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,3 +79,46 @@ void gint_quit(void)
|
||||||
// Restoring the system's VBR.
|
// Restoring the system's VBR.
|
||||||
gint_setvbr(gint.system_vbr, stop);
|
gint_setvbr(gint.system_vbr, stop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// System-switch technique
|
||||||
|
//---
|
||||||
|
|
||||||
|
#include <display.h>
|
||||||
|
#include <gray.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
gint_switch()
|
||||||
|
Temporarily returns to the system's main menu.
|
||||||
|
*/
|
||||||
|
static environment_t switch_env;
|
||||||
|
static void switch_(void)
|
||||||
|
{
|
||||||
|
isSH3() ? gint_restore_and_unlock_7705(&switch_env.env_7705)
|
||||||
|
: gint_restore_and_unlock_7305(&switch_env.env_7305);
|
||||||
|
}
|
||||||
|
void gint_switch(void)
|
||||||
|
{
|
||||||
|
// Save the current environment in a special buffer, so that we can
|
||||||
|
// restore it if we ever come back to gint.
|
||||||
|
isSH3() ? gint_save_7705(&switch_env.env_7705)
|
||||||
|
: gint_save_7305(&switch_env.env_7305);
|
||||||
|
// Give the control back to the system.
|
||||||
|
gint_setvbr(gint.system_vbr, stop);
|
||||||
|
|
||||||
|
// When returning to the add-in from the menu, the system displays the
|
||||||
|
// add-in's video ram again, but it's often blank. We thus need to copy
|
||||||
|
// the contents of the gint video ram to the system's.
|
||||||
|
void *vram = gray_runs()
|
||||||
|
? gray_currentVRAM()
|
||||||
|
: display_getCurrentVRAM();
|
||||||
|
|
||||||
|
// Use system calls to put KEY_MENU in the key buffer and invoke
|
||||||
|
// GetKeyWait(), triggering the main menu.
|
||||||
|
__system_menu(vram);
|
||||||
|
|
||||||
|
// If the user came back, restore the gint working environment.
|
||||||
|
gint_setvbr(gint.gint_vbr, switch_);
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
All the system calls used by the library. Somehow "the less, the
|
All the system calls used by the library. Somehow "the less, the
|
||||||
better".
|
better".
|
||||||
We have finally gotten rid of every obscure system-related syscalls!
|
We have finally gotten rid of every obscure system-related syscalls!
|
||||||
Looks like an important step towards being completely free-standing :)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.global ___malloc
|
.global ___malloc
|
||||||
|
@ -45,6 +44,18 @@ ___system_menu:
|
||||||
sts.l pr, @-r15
|
sts.l pr, @-r15
|
||||||
add #-4, r15
|
add #-4, r15
|
||||||
|
|
||||||
|
/* Copying gint's VRAM into the system's. */
|
||||||
|
mov.l syscall_table, r1
|
||||||
|
mov.l .syscall_vram, r0
|
||||||
|
jsr @r1
|
||||||
|
mov.l r4, @r15 /* gint video ram */
|
||||||
|
mov r0, r4
|
||||||
|
mov.l @r15, r5
|
||||||
|
mov.w .vram_size, r6
|
||||||
|
mov.l .memcpy, r1
|
||||||
|
jsr @r1
|
||||||
|
nop
|
||||||
|
|
||||||
/* Putting the matrix code in the key buffer. */
|
/* Putting the matrix code in the key buffer. */
|
||||||
|
|
||||||
mov r15, r4
|
mov r15, r4
|
||||||
|
@ -60,14 +71,14 @@ ___system_menu:
|
||||||
mov r15, r4 /* column pointer */
|
mov r15, r4 /* column pointer */
|
||||||
add #-4, r15
|
add #-4, r15
|
||||||
mov r15, r5 /* row pointer */
|
mov r15, r5 /* row pointer */
|
||||||
mov #-5, r15
|
add #-4, r15
|
||||||
mov r15, r1
|
mov r15, r1 /* keycode pointer */
|
||||||
|
|
||||||
mov #2, r6 /* type of waiting */
|
mov #2, r6 /* type of waiting */
|
||||||
mov #0, r7 /* timeout period */
|
mov #0, r7 /* timeout period */
|
||||||
mov.l r1, @-r15 /* keycode pointer */
|
mov.l r1, @-r15
|
||||||
mov #0, r2
|
mov #0, r2 /* allow return to menu */
|
||||||
mov.l r2, @-r15 /* allow return to menu */
|
mov.l r2, @-r15
|
||||||
|
|
||||||
mov.l syscall_table, r1
|
mov.l syscall_table, r1
|
||||||
mov.l .syscall_getkeywait, r0
|
mov.l .syscall_getkeywait, r0
|
||||||
|
@ -88,8 +99,14 @@ ___system_menu:
|
||||||
.long 0x0247
|
.long 0x0247
|
||||||
.syscall_putcode:
|
.syscall_putcode:
|
||||||
.long 0x024f
|
.long 0x024f
|
||||||
|
.syscall_vram:
|
||||||
|
.long 0x0135
|
||||||
.matrix_menu:
|
.matrix_menu:
|
||||||
.word 0x0308
|
.word 0x0308
|
||||||
|
.vram_size:
|
||||||
|
.word 1024
|
||||||
|
.memcpy:
|
||||||
|
.long _memcpy
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -69,3 +69,5 @@ _inline int tolower(int c) {
|
||||||
_inline int toupper(int c) {
|
_inline int toupper(int c) {
|
||||||
return c & ~(islower(c) << 1);
|
return c & ~(islower(c) << 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef _inline
|
||||||
|
|
|
@ -140,6 +140,17 @@ uint32_t *gray_darkVRAM(void)
|
||||||
return vrams[(~current & 2) | 1];
|
return vrams[(~current & 2) | 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
gray_currentVRAM()
|
||||||
|
Returns the currently displayed video ram (if the engine runs). Used
|
||||||
|
internally, but has no interest for the user. You don't want to draw to
|
||||||
|
this vram.
|
||||||
|
*/
|
||||||
|
uint32_t *gray_currentVRAM(void)
|
||||||
|
{
|
||||||
|
return vrams[current ^ 1];
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gray_getDelays()
|
gray_getDelays()
|
||||||
Returns the gray engine delays. Pointers are not set if NULL.
|
Returns the gray engine delays. Pointers are not set if NULL.
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <keyboard.h>
|
#include <keyboard.h>
|
||||||
#include <events.h>
|
#include <events.h>
|
||||||
#include <screen.h>
|
#include <screen.h>
|
||||||
|
#include <gint.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
getkey()
|
getkey()
|
||||||
|
@ -15,6 +16,7 @@ int getkey(void)
|
||||||
getkey_shift_modifier |
|
getkey_shift_modifier |
|
||||||
getkey_alpha_modifier |
|
getkey_alpha_modifier |
|
||||||
getkey_manage_backlight |
|
getkey_manage_backlight |
|
||||||
|
getkey_task_switch |
|
||||||
getkey_repeat_arrow_keys,
|
getkey_repeat_arrow_keys,
|
||||||
|
|
||||||
0
|
0
|
||||||
|
@ -62,6 +64,11 @@ int getkey_opt(getkey_option_t options, int delay_ms)
|
||||||
modifier &= ~MOD_SHIFT;
|
modifier &= ~MOD_SHIFT;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if((options & getkey_task_switch) && key == KEY_MENU
|
||||||
|
&& !modifier)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if(options & getkey_shift_modifier && key == KEY_SHIFT)
|
if(options & getkey_shift_modifier && key == KEY_SHIFT)
|
||||||
{
|
{
|
||||||
modifier ^= MOD_SHIFT;
|
modifier ^= MOD_SHIFT;
|
||||||
|
@ -98,6 +105,13 @@ int getkey_opt(getkey_option_t options, int delay_ms)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case event_key_release:
|
case event_key_release:
|
||||||
|
if((options & getkey_task_switch) && event.key.code == KEY_MENU
|
||||||
|
&& !modifier)
|
||||||
|
{
|
||||||
|
gint_switch();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if((int)event.key.code != last_key) break;
|
if((int)event.key.code != last_key) break;
|
||||||
last_key = KEY_NONE;
|
last_key = KEY_NONE;
|
||||||
last_repeats = 0;
|
last_repeats = 0;
|
||||||
|
|
|
@ -82,42 +82,66 @@ static inline void push_release(int keycode)
|
||||||
*/
|
*/
|
||||||
void keyboard_interrupt(void)
|
void keyboard_interrupt(void)
|
||||||
{
|
{
|
||||||
uint8_t state[10] = { 0 };
|
// This procedure is critical for speed. If there's anything that could
|
||||||
|
// be optimized, please tell me.
|
||||||
|
|
||||||
|
// New keyboard state.
|
||||||
|
uint8_t state[10] = { 0 };
|
||||||
isSH3() ? keyboard_updateState_7705(state)
|
isSH3() ? keyboard_updateState_7705(state)
|
||||||
: keyboard_updateState_7305(state);
|
: keyboard_updateState_7305(state);
|
||||||
|
|
||||||
// This procedure really needs to be speed-optimized... and it's hard
|
// Event types associated with each old/new state pair (see later).
|
||||||
// because of this bit manipulation. This condition handles AC/ON.
|
uint8_t events[4] = {
|
||||||
if(keyboard_state[0] ^ state[0])
|
event_none,
|
||||||
{
|
event_key_release,
|
||||||
uint8_t pressed = ~keyboard_state[0] & state[0];
|
event_key_press,
|
||||||
uint8_t released = keyboard_state[0] & ~state[0];
|
event_key_repeat,
|
||||||
|
};
|
||||||
|
|
||||||
if(pressed & 1) push_press(KEY_AC_ON);
|
// AC/ON has not a matrix code that corresponds to its location in the
|
||||||
if(released & 1) push_release(KEY_AC_ON);
|
// buffer, so we need to check it independently.
|
||||||
|
if(keyboard_state[0] | state[0])
|
||||||
|
{
|
||||||
|
int kind = (state[0] << 1) | keyboard_state[0];
|
||||||
|
|
||||||
|
if(kind)
|
||||||
|
{
|
||||||
|
event_t event = {
|
||||||
|
.type = events[kind],
|
||||||
|
.key.code = KEY_AC_ON,
|
||||||
|
.key.id = key_id(KEY_AC_ON),
|
||||||
|
.key.character = key_char(KEY_AC_ON)
|
||||||
|
};
|
||||||
|
event_push(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
keyboard_state[0] = state[0];
|
keyboard_state[0] = state[0];
|
||||||
|
|
||||||
for(int row = 1; row <= 9; row++)
|
for(int row = 1; row <= 9; row++)
|
||||||
{
|
{
|
||||||
uint8_t pressed = ~keyboard_state[row] & state[row];
|
// Shifting the new state will allow us to make up a 2-bit
|
||||||
uint8_t repeated = keyboard_state[row] & state[row];
|
// value for each key more easily, improving efficiency.
|
||||||
uint8_t released = keyboard_state[row] & ~state[row];
|
uint16_t old = keyboard_state[row];
|
||||||
|
uint16_t new = state[row] << 1;
|
||||||
|
|
||||||
|
if(!new && !old) continue;
|
||||||
keyboard_state[row] = state[row];
|
keyboard_state[row] = state[row];
|
||||||
|
|
||||||
// Make this a bit faster.
|
for(uint8_t code = row; code < (row | 0x80); code += 0x10)
|
||||||
if(!(pressed | repeated | released)) continue;
|
|
||||||
|
|
||||||
for(int column = 0; column < 8; column++)
|
|
||||||
{
|
{
|
||||||
if(pressed & 1) push_press ((column << 4) | row);
|
int kind = (new & 2) | (old & 1);
|
||||||
if(repeated & 1) push_repeat ((column << 4) | row);
|
old >>= 1;
|
||||||
if(released & 1) push_release((column << 4) | row);
|
new >>= 1;
|
||||||
|
|
||||||
pressed >>= 1;
|
if(!kind) continue;
|
||||||
repeated >>= 1;
|
|
||||||
released >>= 1;
|
event_t event = {
|
||||||
|
.type = events[kind],
|
||||||
|
.key.code = code,
|
||||||
|
.key.id = key_id(code),
|
||||||
|
.key.character = key_char(code)
|
||||||
|
};
|
||||||
|
event_push(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ static void rtc_cb_update(void)
|
||||||
-1 Array is full
|
-1 Array is full
|
||||||
-2 Invalid parameter
|
-2 Invalid parameter
|
||||||
The number of repeats may be set to 0, in which case the callback is
|
The number of repeats may be set to 0, in which case the callback is
|
||||||
called indefinitely unless the user calls rtc_cb_end().
|
called indefinitely until the user calls rtc_cb_end().
|
||||||
*/
|
*/
|
||||||
int rtc_cb_add(rtc_frequency_t freq, void (*function)(void), int repeats)
|
int rtc_cb_add(rtc_frequency_t freq, void (*function)(void), int repeats)
|
||||||
{
|
{
|
||||||
|
|
2
version
2
version
|
@ -1 +1 @@
|
||||||
beta-0.9-354
|
beta-0.9-410
|
||||||
|
|
Loading…
Reference in a new issue