Interrupt controller module description (WIP), task switch and return to menu.

This commit is contained in:
lephe 2017-07-01 16:07:14 +02:00
parent cd6bd5a1a4
commit 5e66efc560
20 changed files with 297 additions and 130 deletions

3
TODO
View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1 +1 @@
beta-0.9-354 beta-0.9-410