Added a configure script with some options, made Makefile output pretty. Set up an event system (used by keyboard).

This commit is contained in:
lephe 2016-11-05 22:00:23 +01:00
parent 98fdbbc333
commit eedec2b124
27 changed files with 604 additions and 150 deletions

3
.gitignore vendored
View file

@ -15,3 +15,6 @@ LIBC
libc.a libc.a
libgint.a libgint.a
gintdemo.g1a gintdemo.g1a
# Configuration files
gcc.cfg

97
Makefile Normal file → Executable file
View file

@ -13,7 +13,7 @@
# Modules # Modules
modules-gint = core clock keyboard mmu mpu rtc screen timer \ modules-gint = core clock keyboard mmu mpu rtc screen timer \
bopti display gray tales bopti display gray tales events
modules-libc = setjmp string stdio stdlib time modules-libc = setjmp string stdio stdlib time
# Targets # Targets
@ -22,15 +22,15 @@ target-lib = libgint.a
target-std = libc.a target-std = libc.a
# Tools # Tools
cc = sh3eb-elf-gcc cc = sh3eb-elf-gcc
as = sh3eb-elf-as as = sh3eb-elf-as
ar = sh3eb-elf-ar ar = sh3eb-elf-ar
ob = sh3eb-elf-objcopy ob = sh3eb-elf-objcopy
wr = g1a-wrapper wr = g1a-wrapper
# Flags # Flags
cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os \ cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os \
-W -Wall -Wextra -pedantic -W -Wall -Wextra -pedantic @gcc.cfg
# Demo application (could be done better) # Demo application (could be done better)
demo-src = $(notdir $(wildcard demo/*.[cs])) demo-src = $(notdir $(wildcard demo/*.[cs]))
@ -47,7 +47,8 @@ demo-libs = -L. -lgint -lc -lgcc
obj-lib-spec = build/display_font_system.bmp.o obj-lib-spec = build/display_font_system.bmp.o
obj-std-spec = obj-std-spec =
# Configuration files
config = gcc.cfg
#--- #---
# Automatic variables. # Automatic variables.
@ -61,6 +62,10 @@ define n
endef endef
ifeq ("$(wildcard $(config))","")
$(error "Configuration files are missing. Did you ./configure?")
endif
# Module-scope variables. # Module-scope variables.
$(foreach mod, $(modules), $(eval \ $(foreach mod, $(modules), $(eval \
mod-$(mod)-c = $(notdir $(wildcard src/$(mod)/*.c)) $n\ mod-$(mod)-c = $(notdir $(wildcard src/$(mod)/*.c)) $n\
@ -82,21 +87,28 @@ hdr-dep = $(wildcard include/*.h include/internals/*.h)
# Rule templates. # Rule templates.
#--- #---
#ifndef VERBOSE
#$(note "default full log")
#VERBOSE =
#endif
# C source file template: # C source file template:
# $1 module name # $1 module name
# $2 filename # $2 filename
# $3 dependencies # $3 dependencies
define rule-c-source define rule-c-source
build/$1_$2.o: src/$1/$2 $3 build/$1_$2.o: src/$1/$2 $3 $(config)
$(cc) -c $$< -o $$@ $(cflags) -I src/$1 $(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $$<\n')
$(if $(VERBOSE),,@) $(cc) -c $$< -o $$@ $(cflags) -I src/$1
endef endef
# asm source file template: # asm source file template:
# $1 module name # $1 module name
# $2 filename # $2 filename
define rule-asm-source define rule-asm-source
build/$1_$2.o: src/$1/$2 build/$1_$2.o: src/$1/$2 $(config)
$(as) -c $$< -o $$@ $(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m as $$<\n')
$(if $(VERBOSE),,@) $(as) -c $$< -o $$@
endef endef
@ -107,25 +119,36 @@ endef
# Generic rules # Generic rules
all: build $(target-std) $(target-lib) $(target-g1a) all: $(config) build $(target-std) $(target-lib) $(target-g1a)
@echo "[ \033[32;1mOK\033[0m ] All done!" @ printf '\e[32;1mmsg \u00bb\e[0m All done!\n'
build: build:
mkdir -p $@ @ mkdir -p $@
$(target-std): $(obj-std) $(target-std): $(config) $(obj-std)
$(ar) rcs $@ $^ $(if $(VERBOSE),,@ printf '\e[35;1mlib \u00bb\e[0m ar $@\n')
@echo "[ \033[32;1mOK\033[0m ] libc: `stat -c %s $@` bytes" $(if $(VERBOSE),,@) $(ar) rcs $@ $(obj-std)
@ printf '\e[32;1mmsg \u00bb\e[0m Succesfully built libc ('
@ printf $$(stat -c %s $@)
@ printf ' bytes)\n\n'
$(target-lib): $(target-std) $(obj-lib) $(target-lib): $(config) $(target-std) $(obj-lib)
$(ar) rcs $@ $(obj-lib) $(if $(VERBOSE),,@ printf '\e[35;1mlib \u00bb\e[0m ar $@\n')
@echo "[ \033[32;1mOK\033[0m ] libgint: `stat -c %s $@` bytes" $(if $(VERBOSE),,@) $(ar) rcs $@ $(obj-lib)
@ printf '\e[32;1mmsg \u00bb\e[0m Succesfully built libgint ('
@ printf $$(stat -c %s $@)
@ printf ' bytes)\n\n'
$(target-g1a): $(target-std) $(target-lib) $(demo-obj) $(target-g1a): $(config) $(target-std) $(target-lib) $(demo-obj)
$(cc) -o $(demo-elf) $(cflags) -T $(demo-ld) $(demo-obj) $(demo-libs) $(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m ld -o $(demo-elf)\n')
$(ob) -R .comment -R .bss -O binary $(demo-elf) $(demo-bin) $(if $(VERBOSE),,@) $(cc) -o $(demo-elf) $(cflags) -T $(demo-ld) $(demo-obj) $(demo-libs)
$(wr) $(demo-bin) -o $@ -i $(demo-icon) $(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m objcopy -o $(demo-bin)\n')
@echo "[ \033[32;1mOK\033[0m ] demo app: `stat -c %s $@` bytes" $(if $(VERBOSE),,@) $(ob) -R .comment -R .bss -O binary $(demo-elf) $(demo-bin)
$(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m g1a-wrapper -o $@\n')
$(if $(VERBOSE),,@) $(wr) $(demo-bin) -o $@ -i $(demo-icon)
@ printf '\e[32;1mmsg \u00bb\e[0m Succesfully built demo application ('
@ printf $$(stat -c %s $@)
@ printf ' bytes)\n\n'
# Automated rules # Automated rules
@ -139,23 +162,28 @@ $(foreach mod,$(modules), \
# Specific rules # Specific rules
# This one should not be optimized. It makes __attribute__((interrupt_handler)) # This one should not be optimized. It makes __attribute__((interrupt_handler))
# buggy... maybe. Anyway there's a bug in this file. # buggy... maybe. Anyway there's some bug in this file that I can't fix now.
build/core_gint.c.o: src/core/gint.c $(mod-core-dep) build/core_gint.c.o: src/core/gint.c $(mod-core-dep) $(config)
$(cc) -c $< -o $@ $(cflags) -I src/core -O0 $(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $<\n')
$(if $(VERBOSE),,@) $(cc) -c $< -o $@ $(cflags) -I src/core -O0
build/display_font_system.bmp.o: src/display/font_system.bmp build/display_font_system.bmp.o: src/display/font_system.bmp
fxconv $< -o $@ --font -n gint_font_system $(if $(VERBOSE),,@ printf '\e[36;1mres \u00bb\e[0m fxconv $<\n')
$(if $(VERBOSE),,@) fxconv $< -o $@ --font -n gint_font_system
# Demo application # Demo application
build/demo_%.c.o: demo/%.c $(hdr-dep) $(demo-dep) build/demo_%.c.o: demo/%.c $(hdr-dep) $(demo-dep) $(config)
$(cc) -c $< -o $@ $(cflags) $(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $<\n')
$(if $(VERBOSE),,@) $(cc) -c $< -o $@ $(cflags)
build/demo_font_%.bmp.o: demo/resources/font_%.bmp build/demo_font_%.bmp.o: demo/resources/font_%.bmp
fxconv $< -o $@ --font -n $(patsubst demo/resources/%.bmp,res_%,$<) $(if $(VERBOSE),,@ printf '\e[36;1mres \u00bb\e[0m fxconv $<\n')
$(if $(VERBOSE),,@) fxconv $< -o $@ --font -n $(patsubst demo/resources/%.bmp,res_%,$<)
build/demo_%.bmp.o: demo/resources/%.bmp build/demo_%.bmp.o: demo/resources/%.bmp
fxconv $< -o $@ -n $(patsubst demo/resources/%.bmp,res_%,$<) $(if $(VERBOSE),,@ printf '\e[36;1mres \u00bb\e[0m fxconv $<\n')
$(if $(VERBOSE),,@) fxconv $< -o $@ -n $(patsubst demo/resources/%.bmp,res_%,$<)
@ -169,6 +197,7 @@ clean:
mrproper: clean mrproper: clean
@ rm -f $(target-g1a) $(target-lib) $(target-std) @ rm -f $(target-g1a) $(target-lib) $(target-std)
@ rm -rf build @ rm -rf build
@ rm -f $(config)
distclean: mrproper distclean: mrproper

6
TODO
View file

@ -25,3 +25,9 @@ Things to investigate:
- Registers that may need to be saved within setjmp() - Registers that may need to be saved within setjmp()
- Registers that may need to be saved and restored by gint - Registers that may need to be saved and restored by gint
- Possible bug when optimizing __attribute__((interrupt_handler)) - Possible bug when optimizing __attribute__((interrupt_handler))
Configuration:
- ATEXIT_MAX (16)
- RTC_CB_ARRAY_SIZE (5)
- EVENTS_QUEUE_SIZE (64)
- GINT_NO_SYSCALLS (undefined)

78
configure vendored Executable file
View file

@ -0,0 +1,78 @@
#! /bin/bash
declare -A conf
conf[ATEXIT_MAX]=16
conf[RTC_CB_ARRAY_SIZE]=5
conf[EVENTS_QUEUE_SIZE]=64
conf[GINT_NO_SYSCALLS]=
fail=false
output="gcc.cfg"
help()
{
cat << EOF
Configuration script for the gint library.
Options that affect the behavior of the library:
--no-syscalls [default: false]
Never use syscalls. Expect some trouble with the malloc() function...
Do not trigger this option unless you know what you are doing.
Options that customize size limits:
--atexit-max=<integer> [default: 16]
Number of exit handlers that can be registered by atexit().
--rtc-callbacks=<integer> [default: 5]
Number of RTC callbacks that can be registered.
--events-queue-size=<integer> [default: 64]
Number of events simultaneously stored in the event queue.
EOF
exit 0
}
for arg; do case "$arg" in
-h | --help) help;;
--no-syscalls) conf[GINT_NO_SYSCALLS]=true;;
--atexit-max=*)
size=${arg#*=}
if [[ $size == +([0-9]) ]]; then
conf[ATEXIT_MAX]=$size
else echo "error: --atexit-max expects an integer value"
fail=true; fi;;
--rtc-callbacks=*)
size=${arg#*=}
if [[ $size == +([0-9]) ]]; then
conf[RTC_CB_ARRAY_SIZE]=$size
else echo "error: --rtc-callbacks expects an integer value"
fail=true; fi;;
--events-queue-size=*)
size=${arg#*=}
if [[ $size == +([0-9]) ]]; then
conf[EVENTS_QUEUE_SIZE]=$size
else echo "error: --events-queue-size expects an integer value"
fail=true; fi;;
--atexit-max | --rtc-callbacks | --events-queue-size)
echo "error: syntax for $arg is $arg=<integer-value>";;
*)
echo "error: unrecognized argument '$arg'"; fail=true;;
esac; done
output_config()
{
echo "-D ATEXIT_MAX=${conf[ATEXIT_MAX]}"
echo "-D RTC_CB_ARRAY_SIZE=${conf[RTC_CB_ARRAY_SIZE]}"
echo "-D EVENTS_QUEUE_SIZE=${conf[EVENTS_QUEUE_SIZE]}"
if [ "${conf[GINT_NO_SYSCALLS]}" != "" ]; then
echo "-D GINT_NO_SYSCALLS"
fi
}
if $fail; then
echo "Configuration has not been modified."
else
output_config > $output
echo "Configuration details have been output to file $output."
fi

84
include/events.h Normal file
View file

@ -0,0 +1,84 @@
//---
//
// gint core module: events
//
// Finally some user-friendly API.
//
//---
#ifndef _EVENTS_H
#define _EVENTS_H
//---
// Type definitions.
//---
/*
enum EventType
Something user programs will surely use most often.
*/
enum EventType
{
EventType_None = 0,
ET_None = EventType_None,
EventType_User = 1,
ET_User = EventType_User,
EventType_KeyPressed = 2,
ET_KeyPress = EventType_KeyPressed,
EventType_KeyReleased = 3,
ET_KeyRel = EventType_KeyReleased,
};
/*
struct Event
Wake up, something's going on. The union member that holds information
about the event is implicitly defined by the type attribute.
*/
struct Event
{
enum EventType type;
union
{
// For ET_User.
void *data;
// For ET_KeyPress and ET_KeyRel.
int key;
};
};
//---
// Event management.
//---
/*
event_push()
Queues a user-defined event, allowing it to be retrieved by getevent()
or pollevent() later. Most often you will not need to use this, as
system events are automatically queued. Pushing ET_None events is not
allowed.
Returns non-zero on error.
*/
int event_push(struct Event event);
/*
getevent()
Returns the next event. If no one is available, waits for something to
happen. This function uses low-level sleep and should be preferred to
active waiting using loops.
*/
struct Event getevent(void);
/*
pollevent()
Returns the next event. If no one is available, returns an event whose
type is ET_None. This function always returns immediately.
*/
struct Event pollevent(void);
#endif // _EVENTS_H

View file

@ -30,6 +30,18 @@ unsigned int gint_getVBR(void);
*/ */
unsigned int gint_systemVBR(void); unsigned int gint_systemVBR(void);
/*
gint_setDefaultHandler()
In case gint receives an interrupt it doesn't recognize, it can fall
back to a user-provided interrupt handler. Set it to NULL to disable
this feature.
Be aware that the event code passed to the default handler will either
be INTEVT2 (SH7705) or INTEVT (SH7305), but its value for each
interrupt source is completely platform-dependent. Remember to handle
both platforms for increased portability, if possible.
*/
void gint_setDefaultHandler(void (*default_handler)(int event_code));
//--- //---
@ -85,6 +97,12 @@ const char *gint_strerror(int is_tlb);
*/ */
void gint_setVBR(unsigned int new_vbr_address, void (*setup)(void)); void gint_setVBR(unsigned int new_vbr_address, void (*setup)(void));
/*
gint_callDefaultHandler()
Calls the user-provided default interrupt handler.
*/
void gint_callDefaultHandler(int event_code);
/* /*
gint_init() gint_init()
Initializes gint. Loads the interrupt handler into the memory and sets Initializes gint. Loads the interrupt handler into the memory and sets

View file

@ -0,0 +1,19 @@
#ifndef _INTERNALS_EVENTS_H
#define _INTERNALS_EVENTS_H
#include <events.h>
#ifndef EVENTS_QUEUE_SIZE
#define EVENTS_QUEUE_SIZE 64
#endif
/*
This module is just a circular-array queue that pushes and pops events
like any other queue. Trying to add an event when the queue is full
fails, and the operation is ignored.
*/
extern volatile struct Event event_queue[];
extern volatile int queue_start;
extern volatile int queue_size;
#endif // _INTERNALS_EVENT_H

View file

@ -1,5 +1,5 @@
#ifndef _INTERNALS_KEYBOARD_H #ifndef _INTERNALS_KEYBOARD_H
#define _INTERNALS_KEYBOARD_H 1 #define _INTERNALS_KEYBOARD_H
#include <keyboard.h> #include <keyboard.h>

View file

@ -1,10 +1,12 @@
#ifndef _INTERNALS_RTC_H #ifndef _INTERNALS_RTC_H
#define _INTERNALS_RTC_H 1 #define _INTERNALS_RTC_H
#include <rtc.h> #include <rtc.h>
#include <stddef.h> #include <stddef.h>
#ifndef RTC_CB_ARRAY_SIZE
#define RTC_CB_ARRAY_SIZE 5 #define RTC_CB_ARRAY_SIZE 5
#endif
/* /*
struct rtc_cb struct rtc_cb

View file

@ -1,12 +1,3 @@
//---
//
// gint drawing module: tales
//
// Text displaying. Does some good optimization, though requires dynamic
// allocation.
//
//---
#ifndef _INTERNALS_TALES_H #ifndef _INTERNALS_TALES_H
#define _INTERNALS_TALES_H 1 #define _INTERNALS_TALES_H 1

View file

@ -147,13 +147,10 @@ enum GetkeyOpt
{ {
Getkey_NoOption = 0x00, Getkey_NoOption = 0x00,
// Return KEY_NONE when a key is released.
Getkey_ReleaseEvent = 0x01,
// Consider [SHIFT] and [ALPHA] as modifiers instead of returning // Consider [SHIFT] and [ALPHA] as modifiers instead of returning
// KEY_SHIFT and KEY_ALPHA. // KEY_SHIFT and KEY_ALPHA.
Getkey_ShiftModifier = 0x02, Getkey_ShiftModifier = 0x01,
Getkey_AlphaModifier = 0x04, Getkey_AlphaModifier = 0x02,
// Key repetition. Notice that modifiers will never be repeated. // Key repetition. Notice that modifiers will never be repeated.
Getkey_RepeatArrowKeys = 0x10, Getkey_RepeatArrowKeys = 0x10,
@ -219,7 +216,7 @@ int getkey_opt(enum GetkeyOpt options, int max_cycles);
The results are guaranteed to be exact if two keys or less are pressed. The results are guaranteed to be exact if two keys or less are pressed.
With three keys or more, column effects (on SH4) and rectangle effects With three keys or more, column effects (on SH4) and rectangle effects
(on both platforms) mess up the results by making this function think (on both platforms) mess up the results by making this function think
that some keys that are actually unpressed, are pressed. that some keys, which are actually unpressed, are pressed.
This function is designed to make combinations of one or two arrow keys This function is designed to make combinations of one or two arrow keys
with another key as viable as possible. On SH4, this works pretty well with another key as viable as possible. On SH4, this works pretty well
@ -257,7 +254,7 @@ int keyid(int key);
/* /*
keychar() keychar()
Returns the ASCII character associated with a character key ; 0 for Returns the ASCII character associated with a character key; 0 for
other keys. other keys.
*/ */
int keychar(int key); int keychar(int key);

View file

@ -22,7 +22,9 @@
#define EXIT_FAILURE 0 #define EXIT_FAILURE 0
// Number of atexit() registrations guaranteed. // Number of atexit() registrations guaranteed.
#ifndef ATEXIT_MAX
#define ATEXIT_MAX 16 #define ATEXIT_MAX 16
#endif
// Maximum value returned by rand(). // Maximum value returned by rand().
#define RAND_MAX INT_MAX #define RAND_MAX INT_MAX

View file

@ -189,9 +189,9 @@ static void clock_compute_7305(void)
volatile unsigned int *FLLFRQ = (void *)0xa4150050; volatile unsigned int *FLLFRQ = (void *)0xa4150050;
// Surely the documentation of SH7724 does not meet the specification // Surely the documentation of SH7724 does not meet the specification
// if SH7305 for the PLL setting, because the register accepts other // of SH7305 for the PLL setting, because the register accepts other
// values than the ones specified by SH7724. The formula given by // values than the ones specified for SH7724. The relation given by
// Sentaro21 (thanks again!) yields good results though. // Sentaro21 (thanks again!) yields good results.
int pll = (*FRQCRA >> 24) & 0x3f; // Raw setting int pll = (*FRQCRA >> 24) & 0x3f; // Raw setting
pll = pll + 1; // Resulting multiplier pll = pll + 1; // Resulting multiplier
conf.PLL = pll; conf.PLL = pll;

View file

@ -6,9 +6,7 @@
#include <clock.h> #include <clock.h>
#include <internals/mmu.h> #include <internals/mmu.h>
void __Hmem_SetMMU(unsigned int, unsigned int, int); int main(void);
void __GLibAddinAplExecutionCheck(int, int, int);
int main(void);
static void init(void); static void init(void);
static void fini(void); static void fini(void);
@ -54,8 +52,6 @@ int start(void)
// Copying the .data section. // Copying the .data section.
while(data < &edata) *data++ = *src++; while(data < &edata) *data++ = *src++;
__GLibAddinAplExecutionCheck(0, 1, 1);
mmu_pseudoTLBInit(); mmu_pseudoTLBInit();
// Initializing gint. // Initializing gint.

View file

@ -16,6 +16,8 @@ static unsigned int
new_vbr, new_vbr,
sys_vbr; sys_vbr;
static void (*default_handler)(int event_code) = NULL;
//--- //---
@ -64,6 +66,21 @@ inline unsigned int gint_systemVBR(void)
return sys_vbr; return sys_vbr;
} }
/*
gint_setDefaultHandler()
In case gint receives an interrupt it doesn't recognize, it can fall
back to a user-provided interrupt handler. Set it to NULL to disable
this feature.
Be aware that the event code passed to the default handler will either
be INTEVT2 (SH7705) or INTEVT (SH7305), but its value for each
interrupt case is completely platform-dependent. Remember to handle
both platforms for increased portability, if possible.
*/
void gint_setDefaultHandler(void (*new_handler)(int event_code))
{
default_handler = new_handler;
}
/* /*
gint_init() gint_init()
Initializes gint. Loads the interrupt handler into the memory and sets Initializes gint. Loads the interrupt handler into the memory and sets
@ -220,6 +237,21 @@ void gint_int(void)
gint_int_7305(); gint_int_7305();
} }
//---
// Internal API.
//---
/*
gint_callDefaultHandler()
Calls the user-provided default interrupt handler.
*/
void gint_callDefaultHandler(int event_code)
{
if(default_handler) default_handler(event_code);
}
/* /*
gint_reg() gint_reg()
Returns the address of a common register. All common registers exist Returns the address of a common register. All common registers exist

View file

@ -3,35 +3,31 @@
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!
Looks like an important step towards being completely free-standing :)
*/ */
.global ___GLibAddinAplExecutionCheck .global ___malloc
.global _malloc .global ___free
.global _free .global ___realloc
___GLibAddinAplExecutionCheck: ___malloc:
mov.l syscall_table, r2
mov #0x13, r0
jmp @r2
nop
_malloc:
mov.l syscall_table, r2 mov.l syscall_table, r2
mov.l 1f, r0 mov.l 1f, r0
jmp @r2 jmp @r2
nop nop
1: .long 0xacd 1: .long 0xacd
_free: ___free:
mov.l syscall_table, r2 mov.l syscall_table, r2
mov.l 1f, r0 mov.l 1f, r0
jmp @r2 jmp @r2
nop nop
1: .long 0xacc 1: .long 0xacc
_realloc: ___realloc:
mov.l syscall_table, r2 mov.l syscall_table, r2
mov.l 1f, r0 mov.l 1f, r0
jmp @r2 jmp @r2

38
src/events/event_get.c Normal file
View file

@ -0,0 +1,38 @@
#include <internals/events.h>
#include <events.h>
#include <clock.h>
/*
pollevent()
Returns the next event. If no one is available, returns an event whose
type is ET_None. This function always returns immediately.
*/
struct Event pollevent(void)
{
struct Event event = {
.type = ET_None
};
if(queue_size <= 0) return event;
event = event_queue[queue_start];
queue_size--;
if(queue_start == EVENTS_QUEUE_SIZE - 1) queue_start = 0;
else queue_start++;
return event;
}
/*
getevent()
Returns the next event. If no one is available, waits for something to
happen. This function uses low-level sleep and should be preferred to
active waiting using loops.
*/
struct Event getevent(void)
{
struct Event event;
while((event = pollevent()).type == ET_None) sleep();
return event;
}

26
src/events/event_push.c Normal file
View file

@ -0,0 +1,26 @@
#include <internals/events.h>
#include <events.h>
volatile struct Event event_queue[EVENTS_QUEUE_SIZE];
volatile int queue_start = 0;
volatile int queue_size = 0;
/*
event_push()
Queues a user-defined event, allowing it to be retrieved by getevent()
or pollevent() later. Pushing ET_None events is not allowed.
Returns non-zero on error.
*/
int event_push(struct Event event)
{
if(queue_size >= EVENTS_QUEUE_SIZE) return 1;
if(event.type == ET_None) return 2;
int index = queue_start + queue_size;
if(index >= EVENTS_QUEUE_SIZE) index -= EVENTS_QUEUE_SIZE;
event_queue[index] = event;
queue_size++;
return 0;
}

View file

@ -1,5 +1,6 @@
#include <internals/keyboard.h> #include <internals/keyboard.h>
#include <keyboard.h> #include <keyboard.h>
#include <events.h>
/* /*
getkey() getkey()
@ -18,96 +19,113 @@ int getkey(void)
); );
} }
/* /*
getkey_opt() getkey_opt()
Enhances getkey() with most general functionalities. Enhances getkey() with more general functionalities.
If max_cycles is non-zero and positive, getkey_opt() will return If max_cycles is non-zero and positive, getkey_opt() will return
KEY_NOEVENT if no event occurs during max_cycle analysis. KEY_NOEVENT if no event occurs during max_cycle analysis.
*/ */
int getkey_opt(enum GetkeyOpt options, int max_cycles) void getkey_opt_wait(int *cycles)
{ {
int key; while(!interrupt_flag) sleep();
enum KeyType type; interrupt_flag = 0;
int modifier = 0, last_modifier = KEY_NONE;
int r;
if(!max_cycles) max_cycles = -1; if(*cycles > 0) (*cycles)--;
}
int getkey_opt(enum GetkeyOpt options, int cycles)
{
struct Event event;
int modifier = 0;
static int event_ref = 0;
while(max_cycles != 0) if(cycles <= 0) cycles = -1;
while(cycles != 0)
{ {
while(!interrupt_flag) sleep(); event = pollevent();
interrupt_flag = 0; switch(event.type)
if(max_cycles > 0) max_cycles--;
// Getting key and adding modifiers.
key = getPressedKey(keyboard_state);
// Handling "no_key" event;
if(key == KEY_NONE)
{ {
// Condition for returning. case ET_None:
r = (last_key != KEY_NONE && if(last_key == KEY_NONE)
options & Getkey_ReleaseEvent); {
getkey_opt_wait(&cycles);
continue;
}
last_key = KEY_NONE; // Handling repetitions.
last_modifier = KEY_NONE; enum KeyType type = keytype(last_key);
last_repeats = 0; if(!(options & (type << 4))) break;
last_events = 0;
if(r) return KEY_NONE; if(event_ref <= 0)
} {
getkey_opt_wait(&cycles);
event_ref++;
continue;
}
// Handling "new key" events. last_events++;
else if(key != last_key) event_ref--;
{
if(last_events >= (last_repeats ? repeat_next :
repeat_first))
{
last_repeats++;
last_events = 0;
return last_key;
}
break;
case ET_KeyPress:
;
int key = event.key;
if(options & Getkey_ShiftModifier && key == KEY_SHIFT) if(options & Getkey_ShiftModifier && key == KEY_SHIFT)
{ {
if(last_modifier != KEY_SHIFT) modifier ^= MOD_SHIFT;
modifier ^= MOD_SHIFT;
last_modifier = KEY_SHIFT;
continue; continue;
} }
if(options & Getkey_AlphaModifier && key == KEY_ALPHA) if(options & Getkey_AlphaModifier && key == KEY_ALPHA)
{ {
if(last_modifier != KEY_ALPHA) modifier ^= MOD_ALPHA;
modifier ^= MOD_ALPHA;
last_modifier = KEY_ALPHA;
continue; continue;
} }
last_key = key; last_key = key;
last_repeats = 0; last_repeats = 0;
last_events = 0; last_events = 0;
event_ref = 0;
return key | modifier; return key | modifier;
case ET_KeyRel:
if(event.key != last_key) break;
last_key = KEY_NONE;
last_repeats = 0;
last_events = 0;
event_ref = 0;
break;
default:
break;
} }
}
last_key = KEY_NONE;
last_repeats = 0;
last_events = 0;
event_ref = 0;
return KEY_NONE;
}
/*
int getkey_opt(enum GetkeyOpt options, int max_cycles)
{
while(max_cycles != 0)
{
// Handling "new key" events.
// Handling key repetitions. // Handling key repetitions.
else
{
type = keytype(key);
// Checking whether this key type is repeated.
if(options & (type << 4))
{
last_events++;
r = last_repeats ? repeat_next : repeat_first;
if(last_events >= r)
{
last_repeats++;
last_events = 0;
return key;
}
}
}
} }
// When no key was pressed during the given delay... // When no key was pressed during the given delay...
return KEY_NOEVENT; return KEY_NOEVENT;
} }
*/

View file

@ -1,9 +1,9 @@
#include <internals/keyboard.h>
#include <keyboard.h> #include <keyboard.h>
#include <timer.h> #include <timer.h>
#include <mpu.h> #include <mpu.h>
#include <clock.h> #include <clock.h>
#include <events.h>
#include <internals/keyboard.h>
//--- //---
// Keyboard variables. // Keyboard variables.
@ -26,6 +26,24 @@ unsigned cb_id;
// Interrupt management. // Interrupt management.
//--- //---
static void push_press(int keycode)
{
struct Event event = {
.type = ET_KeyPress,
.key = keycode,
};
event_push(event);
}
static void push_release(int keycode)
{
struct Event event = {
.type = ET_KeyRel,
.key = keycode,
};
event_push(event);
}
/* /*
keyboard_interrupt() keyboard_interrupt()
Callback for keyboard update. Allows keyboard analysis functions to Callback for keyboard update. Allows keyboard analysis functions to
@ -33,10 +51,42 @@ unsigned cb_id;
*/ */
void keyboard_interrupt(void) void keyboard_interrupt(void)
{ {
if(isSH3()) unsigned char state[10] = { 0 };
keyboard_updateState_7705(keyboard_state);
else isSH3() ? keyboard_updateState_7705(state)
keyboard_updateState_7305(keyboard_state); : keyboard_updateState_7305(state)
;
// Try to minimize number of operations in common cases... this handles
// AC/ON.
if(keyboard_state[0] ^ state[0])
{
unsigned char pressed = ~keyboard_state[0] & state[0];
unsigned char released = keyboard_state[0] & ~state[0];
if(pressed & 1) push_press(KEY_AC_ON);
if(released & 1) push_release(KEY_AC_ON);
}
keyboard_state[0] = state[0];
for(int row = 1; row <= 9; row++)
{
unsigned char pressed = ~keyboard_state[row] & state[row];
unsigned char released = keyboard_state[row] & ~state[row];
keyboard_state[row] = state[row];
// Fasten this a bit.
if(!pressed && !released) continue;
for(int column = 0; column < 8; column++)
{
if(pressed & 1) push_press ((column << 4) | row);
if(released & 1) push_release((column << 4) | row);
pressed >>= 1;
released >>= 1;
}
}
interrupt_flag = 1; interrupt_flag = 1;
} }

View file

@ -138,12 +138,5 @@ static int krow(int row)
*/ */
void keyboard_updateState_7305(volatile unsigned char *keyboard_state) void keyboard_updateState_7305(volatile unsigned char *keyboard_state)
{ {
int i; for(int i = 0; i < 10; i++) keyboard_state[i] = krow(i);
keyboard_state[8] = krow(8);
for(i = 0; i < 10; i++)
{
if(i != 7 && i != 8) keyboard_state[i] = krow(i);
}
keyboard_state[7] = krow(7);
} }

View file

@ -131,7 +131,5 @@ static int krow(int row)
*/ */
void keyboard_updateState_7705(volatile unsigned char *keyboard_state) void keyboard_updateState_7705(volatile unsigned char *keyboard_state)
{ {
int i; for(int i = 0; i < 10; i++) keyboard_state[i] = krow(i);
for(i = 0; i < 10; i++) keyboard_state[i] = krow(i);
} }

View file

@ -55,6 +55,9 @@ void gint_int_7305(void)
case IC_TMU0_TUNI2: case IC_TMU0_TUNI2:
timer_interrupt(TIMER_TMU2); timer_interrupt(TIMER_TMU2);
break; break;
default:
gint_callDefaultHandler(code);
} }
} }

View file

@ -55,6 +55,9 @@ void gint_int_7705(void)
case IC_TMU2_TUNI2: case IC_TMU2_TUNI2:
timer_interrupt(TIMER_TMU2); timer_interrupt(TIMER_TMU2);
break; break;
default:
gint_callDefaultHandler(code);
} }
} }

20
src/stdlib/free.c Normal file
View file

@ -0,0 +1,20 @@
#include <stdlib.h>
#pragma GCC diagnostic ignored "-Wunused-parameter"
#ifndef GINT_NO_SYSCALLS
void __free(void *ptr);
#endif
/*
free()
Frees a memory block allocated by malloc(), calloc() or realloc().
*/
void free(void *ptr)
{
#ifndef GINT_NO_SYSCALLS
__free(ptr);
#endif
}
#pragma GCC diagnostic pop

27
src/stdlib/malloc.c Normal file
View file

@ -0,0 +1,27 @@
#include <stdlib.h>
/*
malloc()
Allocates 'size' bytes and returns a pointer to a free memory area.
Returns NULL on error.
*/
#ifndef GINT_NO_SYSCALLS
void *__malloc(size_t size);
void *malloc(size_t size)
{
return __malloc(size);
}
#else
#pragma GCC diagnostic ignored "-Wunused-parameter"
void *malloc(size_t size)
{
return NULL;
}
#pragma GCC diagnostic pop
#endif

25
src/stdlib/realloc.c Normal file
View file

@ -0,0 +1,25 @@
#include <stdlib.h>
/*
realloc()
Reallocates a memory block and moves its data.
*/
#ifndef GINT_NO_SYSCALLS
void *__realloc(void *ptr, size_t size);
void *realloc(void *ptr, size_t size)
{
return __realloc(ptr, size);
}
#else
#pragma GCC diagnostic ignored "-Wunused-parameter"
void *realloc(void *ptr, size_t size)
{
return NULL;
}
#pragma GCC diagnostic pop
#endif