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:
|
||||
- bopti: Test partial transparency
|
||||
* core: Allow return to menu
|
||||
- demo: Try 284x124 at (-60, -28) (all disadvantages)
|
||||
- project: Check size of *all* library structures
|
||||
- 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
|
||||
|
||||
Things to do later:
|
||||
|
|
|
@ -277,6 +277,9 @@ void tlb_debug(void)
|
|||
}
|
||||
*/
|
||||
|
||||
#include <modules/rtc.h>
|
||||
#include <modules/interrupts.h>
|
||||
|
||||
/*
|
||||
main_menu()
|
||||
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[] = {
|
||||
"Keyboard and events",
|
||||
"Keyboard & events",
|
||||
"Gray engine",
|
||||
"Image rendering",
|
||||
"Text rendering",
|
||||
|
@ -353,9 +356,10 @@ void main_menu(int *category, int *app)
|
|||
{
|
||||
case 0:
|
||||
print(1, 1, "gint %s", gint_version);
|
||||
print(2, 4, "handler size: %5d", gint_size);
|
||||
print(2, 5, "mpu type: %7s", mpu);
|
||||
print(2, 6, "romdata: %08x", &romdata);
|
||||
print(2, 3, "MPU type %7s", mpu);
|
||||
print(2, 4, "Add-in size %3dk",
|
||||
((uint32_t)&romdata - 0x00300000) >> 10);
|
||||
print(2, 5, "gint size %5do", gint_size);
|
||||
|
||||
list = NULL;
|
||||
break;
|
||||
|
@ -408,9 +412,6 @@ void main_menu(int *category, int *app)
|
|||
|
||||
switch(getkey())
|
||||
{
|
||||
// case KEY_7:
|
||||
// crt0_system_menu();
|
||||
// break;
|
||||
case KEY_F1:
|
||||
if(!tab) break;
|
||||
tab = 0;
|
||||
|
@ -434,6 +435,9 @@ void main_menu(int *category, int *app)
|
|||
index = 0;
|
||||
scroll = 0;
|
||||
break;
|
||||
case KEY_F5:
|
||||
gint_switch();
|
||||
break;
|
||||
case KEY_F6:;
|
||||
void screen(void);
|
||||
screen();
|
||||
|
@ -480,11 +484,11 @@ void main_menu(int *category, int *app)
|
|||
if(app) *app = index + 1;
|
||||
return;
|
||||
|
||||
case KEY_MENU:
|
||||
/* case KEY_MENU:
|
||||
if(category) *category = 0;
|
||||
if(app) *app = 0;
|
||||
return;
|
||||
|
||||
*/
|
||||
default:
|
||||
leave = 0;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
output. Note how symbols romdata, bbss, ebss, bdata and edata are used
|
||||
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
|
||||
virtualized ram.
|
||||
*/
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
#include <stdlib.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 x, y;
|
||||
|
||||
|
@ -29,6 +30,7 @@ static void draw_keyboard(volatile uint8_t *state)
|
|||
// Drawing a filled shape when the key is pressed.
|
||||
if(state[i] & (0x80 >> j))
|
||||
{
|
||||
pressed_keys++;
|
||||
for(k = -2; k <= 2; k++) for(l = -2; l <= 2; l++)
|
||||
if(abs(k) + abs(l) <= 2)
|
||||
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.
|
||||
dline(5, 28, 32, 28, color_black);
|
||||
|
||||
return pressed_keys;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
event_type_t type;
|
||||
uint32_t key;
|
||||
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) \
|
||||
((x).type == (y).type && (x).key == (y).key.code)
|
||||
// Only reset the number of pressed keys in the history when the actual
|
||||
// number of pressed keys reaches 0.
|
||||
|
||||
// Determining where the history ends.
|
||||
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))
|
||||
if(event.type == event_key_release)
|
||||
{
|
||||
history[length - 1].repeats++;
|
||||
pressed_keys--;
|
||||
if(!pressed_keys) h->pressed = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Making up some space if required.
|
||||
if(length == size)
|
||||
// Now we're sure a key was pressed or repeated. Check if it's in the
|
||||
// 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];
|
||||
length = size - 1;
|
||||
if(h->data[i].key == event.key.code)
|
||||
{
|
||||
h->data[i].repeats++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Adding a new entry to the history.
|
||||
history[length].type = event.type;
|
||||
history[length].key = event.key.code;
|
||||
history[length].repeats = 1;
|
||||
// If there are already h->size keys pressed, do not add more.
|
||||
if(event.type == event_key_press) h->pressed++;
|
||||
if(h->pressed > h->size) return;
|
||||
|
||||
#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[] = {
|
||||
"F1", "F2", "F3", "F4", "F5", "F6",
|
||||
|
@ -102,17 +118,21 @@ static void draw_events(enhanced_event_t *history, int size)
|
|||
"1", "2", "3", "+", "-", 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],
|
||||
key_names[key_id(history[i].key)]);
|
||||
if(history[i].repeats > 1)
|
||||
print(19, 3 + i, "%d", history[i].repeats);
|
||||
if(!h->data[i].key) continue;
|
||||
print(8, y, "%s", key_names[key_id(h->data[i].key)]);
|
||||
if(h->data[i].repeats > 1)
|
||||
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)
|
||||
{
|
||||
enhanced_event_t history[5];
|
||||
int history_size = 5;
|
||||
history_key_t history_data[5] = { 0 };
|
||||
history_t history = {
|
||||
.data = history_data,
|
||||
.size = 5,
|
||||
.pressed = 0,
|
||||
};
|
||||
event_t event;
|
||||
|
||||
for(int i = 0; i < history_size; i++) history[i].type = event_none;
|
||||
|
||||
while(1)
|
||||
{
|
||||
dclear();
|
||||
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();
|
||||
|
||||
event = waitevent();
|
||||
if(event.type == event_key_release) releases++;
|
||||
if(event.type == event_key_press && event.key.code == KEY_EXIT)
|
||||
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);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Other functions
|
||||
//---
|
||||
|
||||
/*
|
||||
gint_switch()
|
||||
Temporarily returns to the system's main menu.
|
||||
*/
|
||||
void gint_switch(void);
|
||||
|
||||
#endif // _GINT_H
|
||||
|
|
|
@ -51,6 +51,14 @@ uint32_t *gray_lightVRAM(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()
|
||||
Returns the gray engine delays. Pointers are not set if NULL.
|
||||
|
|
|
@ -162,6 +162,10 @@ typedef enum
|
|||
// compatible models.
|
||||
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
|
||||
// repeat events (use keyboard_setRepeatRate() for this) but filters
|
||||
// them. Please note that modifiers will never be repeated, even when
|
||||
|
|
|
@ -590,7 +590,7 @@ typedef struct
|
|||
uint8_t IMR12;
|
||||
char gap2[15];
|
||||
|
||||
} __attribute__((packed)) mod_intc_masks_7305_t;
|
||||
} __attribute__((packed, aligned(4))) mod_intc_masks_7305_t;
|
||||
|
||||
/*
|
||||
mod_intc_userimask_7305_t
|
||||
|
@ -605,7 +605,7 @@ typedef struct
|
|||
void set_user_imask(int new_level)
|
||||
{
|
||||
mod_intc_userimask_7305_t mask = *(INTC._7305.USERIMASK);
|
||||
mask._a5 = 0xa5;
|
||||
mask._0xa5 = 0xa5;
|
||||
mask.UIMASK = new_level & 0x0f;
|
||||
*(INTC._7305.USERIMASK) = mask;
|
||||
}
|
||||
|
@ -613,7 +613,7 @@ typedef struct
|
|||
typedef struct
|
||||
{
|
||||
lword_union(,
|
||||
uint _a5 :8; /* Always set to 0xa5 before writing */
|
||||
uint _0xa5 :8; /* Always set to 0xa5 before writing */
|
||||
uint :16;
|
||||
uint UIMASK :4; /* User Interrupt Mask Level */
|
||||
uint :4;
|
||||
|
@ -628,7 +628,7 @@ typedef struct
|
|||
*/
|
||||
typedef struct
|
||||
{
|
||||
byte_union(,
|
||||
word_union(,
|
||||
uint const NMIL :1; /* NMI Interupt Level */
|
||||
uint :14;
|
||||
uint NMIFL :1; /* NMI Interrupt Request Flag */
|
||||
|
@ -682,4 +682,7 @@ typedef union
|
|||
|
||||
} __attribute__((packed)) mod_intc_t;
|
||||
|
||||
// Here's what you'll need to use.
|
||||
extern mod_intc_t INTC;
|
||||
|
||||
#endif // _MODULE_INTERRUPTS
|
||||
|
|
|
@ -39,7 +39,7 @@ typedef unsigned uint;
|
|||
uint16_t word; \
|
||||
struct { fields } \
|
||||
__attribute__((packed)); \
|
||||
} __attribute__((packed)) name
|
||||
} __attribute__((packed, aligned(2))) name
|
||||
|
||||
/*
|
||||
lword_union()
|
||||
|
@ -52,6 +52,6 @@ typedef unsigned uint;
|
|||
uint32_t lword; \
|
||||
struct { fields } \
|
||||
__attribute__((packed)); \
|
||||
} __attribute__((packed)) name
|
||||
} __attribute__((packed, aligned(4))) name
|
||||
|
||||
#endif // _MODULES_MACROS_H
|
||||
|
|
|
@ -140,8 +140,6 @@ __attribute__((section(".pretext.entry"))) int start(void)
|
|||
dg->stage = stage_running;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Saving the execution state there.
|
||||
int x = setjmp(env);
|
||||
// If the program has just started, executing main(). Otherwise, the
|
||||
|
@ -253,13 +251,3 @@ int atexit(void (*function)(void))
|
|||
atexit_handlers[atexit_index++] = function;
|
||||
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()
|
||||
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.
|
||||
*/
|
||||
void gint_uninstall(gint_interrupt_type_t type)
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include <gint.h>
|
||||
#include <timer.h>
|
||||
#include <rtc.h>
|
||||
#include <7705.h>
|
||||
|
||||
/*
|
||||
gint_reg()
|
||||
|
@ -34,15 +33,18 @@ volatile void *gint_reg_7705(gint_register_t reg)
|
|||
|
||||
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.
|
||||
e->IPR[0] = INTC.IPRA.WORD;
|
||||
e->IPR[1] = INTC.IPRB.WORD;
|
||||
e->IPR[2] = INTX.IPRC.WORD;
|
||||
e->IPR[3] = INTX.IPRD.WORD;
|
||||
e->IPR[4] = INTX.IPRE.WORD;
|
||||
e->IPR[5] = INTX.IPRF.WORD;
|
||||
e->IPR[6] = INTX.IPRG.WORD;
|
||||
e->IPR[7] = INTX.IPRH.WORD;
|
||||
e->IPR[0] = ipc->IPRA->word;
|
||||
e->IPR[1] = ipc->IPRB->word;
|
||||
e->IPR[2] = ipc->IPRC->word;
|
||||
e->IPR[3] = ipc->IPRD->word;
|
||||
e->IPR[4] = ipc->IPRE->word;
|
||||
e->IPR[5] = ipc->IPRF->word;
|
||||
e->IPR[6] = ipc->IPRG->word;
|
||||
e->IPR[7] = ipc->IPRH->word;
|
||||
|
||||
// Saving RTC registers.
|
||||
e->RCR1 = RTC.RCR1->byte;
|
||||
|
@ -54,35 +56,39 @@ void gint_save_7705(environment_7705_t *e)
|
|||
e->TMU2 = *(TMU.timers[2]);
|
||||
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->PADR = PA.DR.BYTE;
|
||||
e->PBCR = PFC.PBCR.WORD;
|
||||
e->PBDR = PB.DR.BYTE;
|
||||
e->PMCR = PFC.PMCR.WORD;
|
||||
e->PMDR = PM.DR.BYTE;
|
||||
*/
|
||||
}
|
||||
|
||||
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
|
||||
// the handler doesn't handle, which would cause the user program to
|
||||
// freeze.
|
||||
INTC.IPRA.WORD = 0x0000;
|
||||
INTC.IPRB.WORD = 0x0000;
|
||||
INTX.IPRC.WORD = 0x0000;
|
||||
INTX.IPRD.WORD = 0x0000;
|
||||
INTX.IPRE.WORD = 0x0000;
|
||||
INTX.IPRF.WORD = 0x0000;
|
||||
INTX.IPRG.WORD = 0x0000;
|
||||
INTX.IPRH.WORD = 0x0000;
|
||||
ipc->IPRA->word = 0x0000;
|
||||
ipc->IPRB->word = 0x0000;
|
||||
ipc->IPRC->word = 0x0000;
|
||||
ipc->IPRD->word = 0x0000;
|
||||
ipc->IPRE->word = 0x0000;
|
||||
ipc->IPRF->word = 0x0000;
|
||||
ipc->IPRG->word = 0x0000;
|
||||
ipc->IPRH->word = 0x0000;
|
||||
|
||||
// Allowing RTC and timer (which handles keyboard and a whole bunch of
|
||||
// other things).
|
||||
INTC.IPRA.BIT._RTC = 10;
|
||||
INTC.IPRA.BIT._TMU0 = 12;
|
||||
INTC.IPRA.BIT._TMU1 = 12;
|
||||
INTC.IPRA.BIT._TMU2 = 12;
|
||||
ipc->IPRA->RTC = 10;
|
||||
ipc->IPRA->TMU0 = 12;
|
||||
ipc->IPRA->TMU1 = 12;
|
||||
ipc->IPRA->TMU2 = 12;
|
||||
|
||||
// Don't enable RTC periodic signals by default.
|
||||
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)
|
||||
{
|
||||
mod_intc_7705_t *intc = &INTC._7705;
|
||||
mod_intc_ipc_7705_t *ipc = &intc->iprs;
|
||||
|
||||
// Restoring the saved states.
|
||||
INTC.IPRA.WORD = e->IPR[0];
|
||||
INTC.IPRB.WORD = e->IPR[1];
|
||||
INTX.IPRC.WORD = e->IPR[2];
|
||||
INTX.IPRD.WORD = e->IPR[3];
|
||||
INTX.IPRE.WORD = e->IPR[4];
|
||||
INTX.IPRF.WORD = e->IPR[5];
|
||||
INTX.IPRG.WORD = e->IPR[6];
|
||||
INTX.IPRH.WORD = e->IPR[7];
|
||||
ipc->IPRA->word = e->IPR[0];
|
||||
ipc->IPRB->word = e->IPR[1];
|
||||
ipc->IPRC->word = e->IPR[2];
|
||||
ipc->IPRD->word = e->IPR[3];
|
||||
ipc->IPRE->word = e->IPR[4];
|
||||
ipc->IPRF->word = e->IPR[5];
|
||||
ipc->IPRG->word = e->IPR[6];
|
||||
ipc->IPRH->word = e->IPR[7];
|
||||
|
||||
// Restoring RTC registers.
|
||||
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.TSTR->byte = e->TSTR;
|
||||
|
||||
// Restoring keyboard-related I/O port registers.
|
||||
/* // Restoring keyboard-related I/O port registers.
|
||||
PFC.PACR.WORD = e->PACR;
|
||||
PA.DR.BYTE = e->PADR;
|
||||
PFC.PBCR.WORD = e->PBCR;
|
||||
PB.DR.BYTE = e->PBDR;
|
||||
PFC.PMCR.WORD = e->PMCR;
|
||||
PM.DR.BYTE = e->PMDR;
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -79,3 +79,46 @@ void gint_quit(void)
|
|||
// Restoring the system's VBR.
|
||||
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
|
||||
better".
|
||||
We have finally gotten rid of every obscure system-related syscalls!
|
||||
Looks like an important step towards being completely free-standing :)
|
||||
*/
|
||||
|
||||
.global ___malloc
|
||||
|
@ -45,6 +44,18 @@ ___system_menu:
|
|||
sts.l pr, @-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. */
|
||||
|
||||
mov r15, r4
|
||||
|
@ -60,14 +71,14 @@ ___system_menu:
|
|||
mov r15, r4 /* column pointer */
|
||||
add #-4, r15
|
||||
mov r15, r5 /* row pointer */
|
||||
mov #-5, r15
|
||||
mov r15, r1
|
||||
add #-4, r15
|
||||
mov r15, r1 /* keycode pointer */
|
||||
|
||||
mov #2, r6 /* type of waiting */
|
||||
mov #0, r7 /* timeout period */
|
||||
mov.l r1, @-r15 /* keycode pointer */
|
||||
mov #0, r2
|
||||
mov.l r2, @-r15 /* allow return to menu */
|
||||
mov.l r1, @-r15
|
||||
mov #0, r2 /* allow return to menu */
|
||||
mov.l r2, @-r15
|
||||
|
||||
mov.l syscall_table, r1
|
||||
mov.l .syscall_getkeywait, r0
|
||||
|
@ -88,8 +99,14 @@ ___system_menu:
|
|||
.long 0x0247
|
||||
.syscall_putcode:
|
||||
.long 0x024f
|
||||
.syscall_vram:
|
||||
.long 0x0135
|
||||
.matrix_menu:
|
||||
.word 0x0308
|
||||
.vram_size:
|
||||
.word 1024
|
||||
.memcpy:
|
||||
.long _memcpy
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -69,3 +69,5 @@ _inline int tolower(int c) {
|
|||
_inline int toupper(int c) {
|
||||
return c & ~(islower(c) << 1);
|
||||
}
|
||||
|
||||
#undef _inline
|
||||
|
|
|
@ -140,6 +140,17 @@ uint32_t *gray_darkVRAM(void)
|
|||
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()
|
||||
Returns the gray engine delays. Pointers are not set if NULL.
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <keyboard.h>
|
||||
#include <events.h>
|
||||
#include <screen.h>
|
||||
#include <gint.h>
|
||||
|
||||
/*
|
||||
getkey()
|
||||
|
@ -15,6 +16,7 @@ int getkey(void)
|
|||
getkey_shift_modifier |
|
||||
getkey_alpha_modifier |
|
||||
getkey_manage_backlight |
|
||||
getkey_task_switch |
|
||||
getkey_repeat_arrow_keys,
|
||||
|
||||
0
|
||||
|
@ -62,6 +64,11 @@ int getkey_opt(getkey_option_t options, int delay_ms)
|
|||
modifier &= ~MOD_SHIFT;
|
||||
continue;
|
||||
}
|
||||
if((options & getkey_task_switch) && key == KEY_MENU
|
||||
&& !modifier)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(options & getkey_shift_modifier && key == KEY_SHIFT)
|
||||
{
|
||||
modifier ^= MOD_SHIFT;
|
||||
|
@ -98,6 +105,13 @@ int getkey_opt(getkey_option_t options, int delay_ms)
|
|||
break;
|
||||
|
||||
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;
|
||||
last_key = KEY_NONE;
|
||||
last_repeats = 0;
|
||||
|
|
|
@ -82,42 +82,66 @@ static inline void push_release(int keycode)
|
|||
*/
|
||||
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)
|
||||
: keyboard_updateState_7305(state);
|
||||
|
||||
// This procedure really needs to be speed-optimized... and it's hard
|
||||
// because of this bit manipulation. This condition handles AC/ON.
|
||||
if(keyboard_state[0] ^ state[0])
|
||||
{
|
||||
uint8_t pressed = ~keyboard_state[0] & state[0];
|
||||
uint8_t released = keyboard_state[0] & ~state[0];
|
||||
// Event types associated with each old/new state pair (see later).
|
||||
uint8_t events[4] = {
|
||||
event_none,
|
||||
event_key_release,
|
||||
event_key_press,
|
||||
event_key_repeat,
|
||||
};
|
||||
|
||||
if(pressed & 1) push_press(KEY_AC_ON);
|
||||
if(released & 1) push_release(KEY_AC_ON);
|
||||
// AC/ON has not a matrix code that corresponds to its location in the
|
||||
// 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];
|
||||
|
||||
for(int row = 1; row <= 9; row++)
|
||||
{
|
||||
uint8_t pressed = ~keyboard_state[row] & state[row];
|
||||
uint8_t repeated = keyboard_state[row] & state[row];
|
||||
uint8_t released = keyboard_state[row] & ~state[row];
|
||||
// Shifting the new state will allow us to make up a 2-bit
|
||||
// value for each key more easily, improving efficiency.
|
||||
uint16_t old = keyboard_state[row];
|
||||
uint16_t new = state[row] << 1;
|
||||
|
||||
if(!new && !old) continue;
|
||||
keyboard_state[row] = state[row];
|
||||
|
||||
// Make this a bit faster.
|
||||
if(!(pressed | repeated | released)) continue;
|
||||
|
||||
for(int column = 0; column < 8; column++)
|
||||
for(uint8_t code = row; code < (row | 0x80); code += 0x10)
|
||||
{
|
||||
if(pressed & 1) push_press ((column << 4) | row);
|
||||
if(repeated & 1) push_repeat ((column << 4) | row);
|
||||
if(released & 1) push_release((column << 4) | row);
|
||||
int kind = (new & 2) | (old & 1);
|
||||
old >>= 1;
|
||||
new >>= 1;
|
||||
|
||||
pressed >>= 1;
|
||||
repeated >>= 1;
|
||||
released >>= 1;
|
||||
if(!kind) continue;
|
||||
|
||||
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
|
||||
-2 Invalid parameter
|
||||
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)
|
||||
{
|
||||
|
|
2
version
2
version
|
@ -1 +1 @@
|
|||
beta-0.9-354
|
||||
beta-0.9-410
|
||||
|
|
Loading…
Reference in a new issue